MobilApp/lib/widgets/map/imported_layer_overlay.dart

201 lines
7.3 KiB
Dart
Raw Permalink Normal View History

// Térkép overlay és panel widget az importált rétegekhez.
// Az ImportedLayer már kész flutter_map objektumokat tartalmaz —
// itt csak megjelenítjük őket.
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
import 'package:terepi_seged/enums/layer_import_source_type.dart';
import '../../models/imported_layer.dart';
import '../../services/layer_import_service.dart';
// ════════════════════════════════════════════════════════════════════
// Térkép réteg — a flutter_map layers listájába kerül
// ════════════════════════════════════════════════════════════════════
class ImportedLayerOverlay extends StatelessWidget {
const ImportedLayerOverlay({super.key});
@override
Widget build(BuildContext context) {
if (!Get.isRegistered<LayerImportService>()) {
return const SizedBox.shrink();
}
return Obx(() {
final visible = LayerImportService.to.visibleLayers;
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();
return Stack(children: [
if (polygons.isNotEmpty) PolygonLayer(polygons: polygons),
if (polylines.isNotEmpty) PolylineLayer(polylines: polylines),
if (markers.isNotEmpty) MarkerLayer(markers: markers),
]);
});
}
}
// ════════════════════════════════════════════════════════════════════
// Réteg panel — import gomb + betöltött rétegek listája
// ════════════════════════════════════════════════════════════════════
class ImportLayerPanel extends StatelessWidget {
/// Ha meg van adva, a rétegre zoom gomb ezt hívja
final void Function(LatLngBounds bounds)? onFitBounds;
const ImportLayerPanel({super.key, this.onFitBounds});
@override
Widget build(BuildContext context) {
final svc = LayerImportService.to;
return Obx(() => Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Import gomb
_ImportButton(svc: svc),
// Réteg lista
if (svc.layers.isNotEmpty) ...[
const SizedBox(height: 12),
const Divider(height: 1),
const SizedBox(height: 8),
...svc.layers.map((layer) => _LayerTile(
layer: layer,
onToggle: () => svc.toggleLayer(layer.id),
onRemove: () => svc.removeLayer(layer.id),
onZoomTo: onFitBounds != null
? () {
final b = layer.bounds;
if (b != null) onFitBounds!(b);
}
: null,
)),
],
],
));
}
}
// ─── Import gomb ─────────────────────────────────────────────────────────────
class _ImportButton extends StatelessWidget {
final LayerImportService svc;
const _ImportButton({required this.svc});
@override
Widget build(BuildContext context) {
return Obx(() => svc.isLoading.value
? const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(mainAxisSize: MainAxisSize.min, children: [
SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2)),
SizedBox(width: 8),
Text('Betöltés...', style: TextStyle(fontSize: 13)),
]),
)
: OutlinedButton.icon(
onPressed: () => svc.importFile(),
icon: const Icon(Icons.file_open_outlined, size: 18),
label: const Text('GeoJSON / KML / KMZ'),
));
}
}
// ─── Egy réteg sor ───────────────────────────────────────────────────────────
class _LayerTile extends StatelessWidget {
final ImportedLayer layer;
final VoidCallback onToggle;
final VoidCallback onRemove;
final VoidCallback? onZoomTo;
const _LayerTile({
required this.layer,
required this.onToggle,
required this.onRemove,
this.onZoomTo,
});
@override
Widget build(BuildContext context) {
final icon = switch (layer.sourceType) {
LayerImportSourceType.geoJson => Icons.data_object,
LayerImportSourceType.kml => Icons.map_outlined,
LayerImportSourceType.kmz => Icons.folder_zip_outlined,
};
return Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Row(children: [
// Láthatóság
Transform.scale(
scale: 0.85,
child: Switch.adaptive(
value: layer.isVisible,
onChanged: (_) => onToggle(),
),
),
// Ikon
Icon(icon, size: 15, color: Colors.grey.shade500),
const SizedBox(width: 6),
// Név + statisztika
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(layer.name,
style: const TextStyle(
fontSize: 13, fontWeight: FontWeight.w500),
overflow: TextOverflow.ellipsis),
Text(_stats(),
style: TextStyle(fontSize: 10, color: Colors.grey.shade500)),
],
),
),
// Zoom gomb
if (onZoomTo != null)
IconButton(
icon: const Icon(Icons.fit_screen, size: 16),
onPressed: onZoomTo,
tooltip: 'Ráközelítés',
padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: 28, minHeight: 28),
color: Colors.grey.shade500,
),
// Törlés
IconButton(
icon: const Icon(Icons.close, size: 16),
onPressed: onRemove,
tooltip: 'Eltávolítás',
padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: 28, minHeight: 28),
color: Colors.grey.shade400,
),
]),
);
}
String _stats() {
final parts = <String>[];
if (layer.markers.isNotEmpty) parts.add('${layer.markers.length} pont');
if (layer.polylines.isNotEmpty)
parts.add('${layer.polylines.length} vonal');
if (layer.polygons.isNotEmpty)
parts.add('${layer.polygons.length} terület');
return parts.isEmpty ? 'Üres réteg' : parts.join(' · ');
}
}