Importált rétegek stílusának szerkesztése

This commit is contained in:
2026-07-04 23:36:01 +02:00
parent 077b40967c
commit 2cf83149f0
12 changed files with 341 additions and 64 deletions
+33 -30
View File
@@ -117,39 +117,42 @@ class _GeometryLayerTile extends StatelessWidget {
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 0),
leading: Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: (visible ? color : Colors.grey).withOpacity(0.12),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: (visible ? color : Colors.grey).withOpacity(0.3),
return Material(
color: Colors.transparent,
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 0),
leading: Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: (visible ? color : Colors.grey).withOpacity(0.12),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: (visible ? color : Colors.grey).withOpacity(0.3),
),
),
child: Icon(icon, size: 18, color: visible ? color : Colors.grey),
),
child: Icon(icon, size: 18, color: visible ? color : Colors.grey),
title: Text(label,
style: TextStyle(
fontWeight: FontWeight.w500,
color: visible ? null : cs.onSurfaceVariant,
)),
subtitle: count > 0
? Text('$count objektum', style: const TextStyle(fontSize: 11))
: Text('Nincs rögzített geometria',
style: TextStyle(fontSize: 11, color: cs.onSurfaceVariant)),
trailing: Switch(
value: visible,
onChanged: (_) => onToggle(),
activeColor: color,
trackColor: WidgetStateProperty.resolveWith((states) =>
states.contains(WidgetState.selected)
? color.withOpacity(0.3)
: null),
),
onTap: onToggle,
),
title: Text(label,
style: TextStyle(
fontWeight: FontWeight.w500,
color: visible ? null : cs.onSurfaceVariant,
)),
subtitle: count > 0
? Text('$count objektum', style: const TextStyle(fontSize: 11))
: Text('Nincs rögzített geometria',
style: TextStyle(fontSize: 11, color: cs.onSurfaceVariant)),
trailing: Switch(
value: visible,
onChanged: (_) => onToggle(),
activeColor: color,
trackColor: WidgetStateProperty.resolveWith((states) =>
states.contains(WidgetState.selected)
? color.withOpacity(0.3)
: null),
),
onTap: onToggle,
);
}
}
+66 -4
View File
@@ -10,6 +10,8 @@ import 'package:terepi_seged/enums/layer_import_source_type.dart';
import '../../models/imported_layer.dart';
import '../../services/layer_import_service.dart';
import '../map_edit_tools/imported_layer_style_sheet.dart';
import '../map_edit_tools/style_editable.dart';
// ════════════════════════════════════════════════════════════════════
// Térkép réteg — a flutter_map layers listájába kerül
@@ -26,13 +28,39 @@ class ImportedLayerOverlay extends StatelessWidget {
return Obx(() {
final visible = LayerImportService.to.visibleLayers;
final styles = LayerImportService.to.layerStyles;
if (visible.isEmpty) return const SizedBox.shrink();
// Az összes látható réteg objektumait összegyűjtjük
final polylines = visible.expand((l) => l.polylines).toList();
final polygons = visible.expand((l) => l.polygons).toList();
final markers = visible.expand((l) => l.markers).toList();
final polylines = <Polyline>[];
final polygons = <Polygon>[];
final markers = <Marker>[];
for (final layer in visible) {
final style = styles[layer.id]; // ← override ha van
if (style != null) {
// Stílussal felülírva
polylines.addAll(layer.polylines.map((p) => Polyline(
points: p.points,
color: style.color.withOpacity(0.85),
strokeWidth: style.strokeWidth,
)));
polygons.addAll(layer.polygons.map((p) => Polygon(
points: p.points,
holePointsList: p.holePointsList,
color: style.color.withOpacity(style.opacity),
borderColor: style.color,
borderStrokeWidth: style.strokeWidth,
label: p.label,
)));
markers.addAll(layer.markers); // marker szín nem változik egyszerűen
} else {
// Eredeti stílus
polylines.addAll(layer.polylines);
polygons.addAll(layer.polygons);
markers.addAll(layer.markers);
}
}
return Stack(children: [
if (polygons.isNotEmpty) PolygonLayer(polygons: polygons),
if (polylines.isNotEmpty) PolylineLayer(polylines: polylines),
@@ -175,6 +203,10 @@ class _LayerTile extends StatelessWidget {
constraints: const BoxConstraints(minWidth: 28, minHeight: 28),
color: Colors.grey.shade500,
),
IconButton(
icon: const Icon(Icons.palette_outlined, size: 16),
onPressed: () => _openStyleSheet(context, layer),
tooltip: 'Stílus szerkesztése'),
// Törlés
IconButton(
icon: const Icon(Icons.close, size: 16),
@@ -188,6 +220,36 @@ class _LayerTile extends StatelessWidget {
);
}
void _openStyleSheet(BuildContext context, ImportedLayer layer) {
final svc = LayerImportService.to;
final current = svc.getLayerStyle(layer.id);
final session = LayerStyleSession(
color: current?.color ?? const Color(0xFF1565C0),
opacity: current?.opacity ?? 0.35,
strokeWidth: current?.strokeWidth ?? 2.5,
);
Get.bottomSheet(
ImportedLayerStyleSheet(
layerName: layer.name,
session: session,
onSave: () => svc.setLayerStyle(
layer.id,
ImportedLayerStyle(
color: session.activeEditColor.value,
opacity: session.activeEditOpacity.value,
strokeWidth: session.activeEditStrokeWidth.value,
)),
onReset: () {
svc.layerStyles.remove(layer.id);
svc.layers.refresh();
},
),
isScrollControlled: true,
backgroundColor: Colors.transparent,
);
}
String _stats() {
final parts = <String>[];
if (layer.markers.isNotEmpty) parts.add('${layer.markers.length} pont');
+2 -1
View File
@@ -1,9 +1,10 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/core/style_editable.dart';
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
class ColorRow extends StatelessWidget {
final MapSurveyController ctrl;
final StyleEditable ctrl;
final double circleSize;
static const _palette = [
@@ -0,0 +1,81 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/widgets/map_edit_tools/style_editable.dart';
import 'color_row.dart';
import 'opacity_slider.dart';
import 'stroke_slider.dart';
class ImportedLayerStyleSheet extends StatelessWidget {
final String layerName;
final LayerStyleSession session; // ← a közös interfész implementációja
final VoidCallback onSave;
final VoidCallback onReset;
const ImportedLayerStyleSheet({
required this.layerName,
required this.session,
required this.onSave,
required this.onReset,
});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.fromLTRB(
20, 16, 20, MediaQuery.of(context).padding.bottom + 16),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Handle
Center(
child: Container(
width: 40,
height: 4,
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(2)),
)),
Text(layerName,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
overflow: TextOverflow.ellipsis),
const SizedBox(height: 20),
// ── Meglévő widgetek — ismerős felület ──────────────────
ColorRow(ctrl: session), // ← ugyanaz mint a geometriáknál
const SizedBox(height: 18),
OpacitySlider(ctrl: session),
const SizedBox(height: 10),
StrokeSlider(ctrl: session),
const SizedBox(height: 24),
// Gombok
Row(children: [
OutlinedButton(
onPressed: () {
onReset();
Get.back();
},
child: const Text('Visszaállítás'),
),
const Spacer(),
FilledButton(
onPressed: () {
onSave();
Get.back();
},
child: const Text('Alkalmaz'),
),
]),
],
),
);
}
}
@@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/core/style_editable.dart';
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
import 'labeled_slider.dart';
class OpacitySlider extends StatelessWidget {
final MapSurveyController ctrl;
final StyleEditable ctrl;
const OpacitySlider({required this.ctrl});
@override
@@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/core/style_editable.dart';
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
import 'labeled_slider.dart';
class StrokeSlider extends StatelessWidget {
final MapSurveyController ctrl;
final StyleEditable ctrl;
const StrokeSlider({required this.ctrl});
@override
@@ -0,0 +1,23 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:terepi_seged/core/style_editable.dart';
class LayerStyleSession implements StyleEditable {
@override
Rx<Color> activeEditColor = Color(0xFF1565C0).obs;
@override
RxDouble activeEditOpacity = 0.35.obs;
@override
RxDouble activeEditStrokeWidth = 2.5.obs;
LayerStyleSession(
{required Color color,
required double opacity,
required double strokeWidth}) {
activeEditColor.value = color;
activeEditOpacity.value = opacity;
activeEditStrokeWidth.value = strokeWidth;
}
}