Kml, kmz és geojson import és térképi megjelnítésük.
This commit is contained in:
@@ -87,7 +87,35 @@ class AppDrawer extends StatelessWidget {
|
||||
);
|
||||
}),
|
||||
|
||||
const Divider(height: 24),
|
||||
//const Divider(height: 24),
|
||||
const Divider(height: 12),
|
||||
|
||||
// ----------- További funkciók
|
||||
const _SectionLabel('Funkciók'),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.message_outlined),
|
||||
title: const Text('Üzenetek'),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
// Get.to(() => const NtripSettingsView());
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.phone_outlined),
|
||||
title: const Text('Kapcsolatok'),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
// Get.to(() => const NtripSettingsView());
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.data_exploration_outlined),
|
||||
title: const Text('Mérés'),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
// Get.to(() => const NtripSettingsView());
|
||||
},
|
||||
),
|
||||
|
||||
// ── 3. Beállítások ─────────────────────────────────
|
||||
const _SectionLabel('Beállítások'),
|
||||
|
||||
@@ -156,7 +156,11 @@ class ShellMapAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
PopupMenuButton(
|
||||
tooltip: 'További funkciók',
|
||||
icon: const Icon(Icons.more_vert),
|
||||
onSelected: null,
|
||||
onSelected: (value) {
|
||||
if (value == 1) {
|
||||
controller.openLayerPanel();
|
||||
}
|
||||
},
|
||||
itemBuilder: (context) => const [
|
||||
PopupMenuItem(
|
||||
value: 1,
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
// 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(' · ');
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,12 @@ class MapModeMenuAnchor extends StatelessWidget {
|
||||
fontSize: 18, fontWeight: FontWeight.w600)),
|
||||
const Icon(Icons.arrow_drop_down, size: 22),
|
||||
]),
|
||||
Text(p == null ? 'Projekt' : p.name,
|
||||
Text(
|
||||
p == null
|
||||
? 'Projekt'
|
||||
: (p.name.length > 18
|
||||
? '${p.name.substring(0, 18)}...'
|
||||
: p.name),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontStyle: FontStyle.italic,
|
||||
|
||||
Reference in New Issue
Block a user