From 7f514da38f602a3852445d1df03dca58aa805fa2 Mon Sep 17 00:00:00 2001 From: "torok.istvan" Date: Thu, 30 Jul 2026 18:37:53 +0200 Subject: [PATCH] =?UTF-8?q?Geopackage=20export:=20geometri=C3=A1k=20export?= =?UTF-8?q?=C3=A1l=C3=A1sa=20d=C3=A1tum=20szerinti=20sz=C5=B1r=C3=A9ssel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/geopackage_exporter.dart | 58 ++++++++++++++----- .../controllers/map_survey_controller.dart | 56 ++++++++++++++++++ 2 files changed, 98 insertions(+), 16 deletions(-) diff --git a/lib/core/geopackage_exporter.dart b/lib/core/geopackage_exporter.dart index 8172d20..39ed35d 100644 --- a/lib/core/geopackage_exporter.dart +++ b/lib/core/geopackage_exporter.dart @@ -29,7 +29,7 @@ import '../enums/note_type.dart'; class GeoPackageExporter { // ── Publikus belépési pont ──────────────────────────────────────── - Future exportProject() async { + Future exportProject({DateTime? since}) async { final project = ProjectService.to.activeProject.value; final projectId = ProjectService.to.activeProjectId; final name = project?.name ?? 'projekt'; @@ -42,11 +42,11 @@ class GeoPackageExporter { try { // 1. GeoPackage létrehozása final gpkgPath = p.join(workDir.path, '$name.gpkg'); - await _buildGpkg(gpkgPath, projectId); + await _buildGpkg(gpkgPath, projectId, since); // 2. Médiafájlok összegyűjtése final mediaDir = Directory(p.join(workDir.path, 'media')); - await _collectMedia(projectId, mediaDir); + await _collectMedia(projectId, mediaDir, since); // 3. ZIP csomagolás final zipPath = p.join(tmpDir.path, '${name}_$ts.zip'); @@ -65,13 +65,13 @@ class GeoPackageExporter { // ── GeoPackage (.gpkg) létrehozása ─────────────────────────────── - Future _buildGpkg(String path, int? projectId) async { + Future _buildGpkg(String path, int? projectId, DateTime? since) async { final db = await openDatabase(path); try { await _initGpkg(db); - await _exportNoteItems(db, projectId); - await _exportMeasuredPoints(db, projectId); - await _exportTracks(db, projectId); + await _exportNoteItems(db, projectId, since); + await _exportMeasuredPoints(db, projectId, since); + await _exportTracks(db, projectId, since); } finally { await db.close(); } @@ -187,11 +187,17 @@ class GeoPackageExporter { // ── NoteItem exportok ───────────────────────────────────────────── - Future _exportNoteItems(Database db, int? projectId) async { + Future _exportNoteItems( + Database db, int? projectId, DateTime? since) async { final items = await AppDatabase.instance.listNoteItems(projectId); - final points = items.where((i) => i.type == NoteType.point).toList(); - final lines = items.where((i) => i.type == NoteType.line).toList(); - final polygons = items.where((i) => i.type == NoteType.polygon).toList(); + + final filtered = since != null + ? items.where((i) => i.createdAt.isAfter(since)).toList() + : items; + + final points = filtered.where((i) => i.type == NoteType.point).toList(); + final lines = filtered.where((i) => i.type == NoteType.line).toList(); + final polygons = filtered.where((i) => i.type == NoteType.polygon).toList(); if (points.isNotEmpty) await _exportPoints(db, points); if (lines.isNotEmpty) await _exportLines(db, lines); @@ -310,12 +316,19 @@ class GeoPackageExporter { // ── Bemért pontok exportja ──────────────────────────────────────── - Future _exportMeasuredPoints(Database db, int? projectId) async { + Future _exportMeasuredPoints( + Database db, int? projectId, DateTime? since) async { final points = projectId != null ? await AppDatabase.instance.listMeasuredPoints(projectId) : []; if (points.isEmpty) return; + final filtered = since != null + ? points.where((p) => p.timestamp.isAfter(since)).toList() + : points; + + if (filtered.isEmpty) return; + await db.execute(''' CREATE TABLE measured_points ( id INTEGER PRIMARY KEY, @@ -353,13 +366,20 @@ class GeoPackageExporter { // ── Track exportja ──────────────────────────────────────────────── - Future _exportTracks(Database db, int? projectId) async { + Future _exportTracks( + Database db, int? projectId, DateTime? since) async { final tracks = await AppDatabase.instance.listTracks(); - final filtered = projectId != null + var filtered = projectId != null ? tracks.where((t) => t.projectId == projectId).toList() : tracks; if (filtered.isEmpty) return; + if (since != null) { + filtered = filtered.where((t) => t.startTime.isAfter(since)).toList(); + } + + if (filtered.isEmpty) return; + await db.execute(''' CREATE TABLE tracks ( id INTEGER PRIMARY KEY, @@ -395,7 +415,8 @@ class GeoPackageExporter { // ── Médiafájlok másolása ────────────────────────────────────────── - Future _collectMedia(int? projectId, Directory mediaDir) async { + Future _collectMedia( + int? projectId, Directory mediaDir, DateTime? since) async { if (projectId == null) return; final photos = Directory(p.join(mediaDir.path, 'photos')); @@ -404,7 +425,12 @@ class GeoPackageExporter { await audios.create(recursive: true); final items = await AppDatabase.instance.listNoteItems(projectId); - for (final item in items) { + + final filtered = since != null + ? items.where((i) => i.createdAt.isAfter(since)).toList() + : items; + + for (final item in filtered) { // Fotók final photoList = await AppDatabase.instance.listNotePhotos(item.id!); for (final photo in photoList) { diff --git a/lib/pages/map_survey/presentations/controllers/map_survey_controller.dart b/lib/pages/map_survey/presentations/controllers/map_survey_controller.dart index ac18a30..909b4e4 100644 --- a/lib/pages/map_survey/presentations/controllers/map_survey_controller.dart +++ b/lib/pages/map_survey/presentations/controllers/map_survey_controller.dart @@ -1895,6 +1895,9 @@ class MapSurveyController extends GetxController implements StyleEditable { showGeometryLabels.value = !showGeometryLabels.value; Future exportProject() async { + final since = await _showExportDateDialog(); + if (since == false) return; // felhasználó megszakította + Get.dialog( Center( child: Material( @@ -1932,6 +1935,59 @@ class MapSurveyController extends GetxController implements StyleEditable { } } + /// Visszaad: DateTime (szűrt export), null (teljes export), false (mégse) + Future _showExportDateDialog() async { + return Get.dialog(AlertDialog( + title: const Text('Export tartalma'), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + leading: const Icon(Icons.all_inclusive), + title: const Text('Teljes projekt'), + onTap: () => Get.back(result: null), + ), + ListTile( + leading: const Icon(Icons.today), + title: const Text('Mai nap'), + onTap: () => Get.back( + result: DateTime(DateTime.now().year, DateTime.now().month, + DateTime.now().day)), + ), + ListTile( + leading: const Icon(Icons.today), + title: const Text('Tegnapi nap'), + onTap: () => Get.back( + result: DateTime(DateTime.now().year, DateTime.now().month, + DateTime.now().day) + .subtract(const Duration(days: 1))), + ), + ListTile( + leading: const Icon(Icons.date_range), + title: const Text('Dátum kiválasztása...'), + onTap: () async { + Get.back(); + final picked = await showDatePicker( + context: Get.context!, + initialDate: DateTime.now().subtract(const Duration(days: 7)), + firstDate: DateTime(2024), + lastDate: DateTime.now(), + ); + if (picked != null) Get.back(result: picked); + }, + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Get.back(result: false), + child: const Text('Mégse'), + ), + ], + )); + } + void _subscribeToTeamPosition() { _teamChannel = Supabase.instance.client .channel('public:terepi_seged_device_positions')