Geopackage export: geometriák exportálása dátum szerinti szűréssel
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 7s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 7s
This commit is contained in:
@@ -29,7 +29,7 @@ import '../enums/note_type.dart';
|
|||||||
class GeoPackageExporter {
|
class GeoPackageExporter {
|
||||||
// ── Publikus belépési pont ────────────────────────────────────────
|
// ── Publikus belépési pont ────────────────────────────────────────
|
||||||
|
|
||||||
Future<void> exportProject() async {
|
Future<void> exportProject({DateTime? since}) async {
|
||||||
final project = ProjectService.to.activeProject.value;
|
final project = ProjectService.to.activeProject.value;
|
||||||
final projectId = ProjectService.to.activeProjectId;
|
final projectId = ProjectService.to.activeProjectId;
|
||||||
final name = project?.name ?? 'projekt';
|
final name = project?.name ?? 'projekt';
|
||||||
@@ -42,11 +42,11 @@ class GeoPackageExporter {
|
|||||||
try {
|
try {
|
||||||
// 1. GeoPackage létrehozása
|
// 1. GeoPackage létrehozása
|
||||||
final gpkgPath = p.join(workDir.path, '$name.gpkg');
|
final gpkgPath = p.join(workDir.path, '$name.gpkg');
|
||||||
await _buildGpkg(gpkgPath, projectId);
|
await _buildGpkg(gpkgPath, projectId, since);
|
||||||
|
|
||||||
// 2. Médiafájlok összegyűjtése
|
// 2. Médiafájlok összegyűjtése
|
||||||
final mediaDir = Directory(p.join(workDir.path, 'media'));
|
final mediaDir = Directory(p.join(workDir.path, 'media'));
|
||||||
await _collectMedia(projectId, mediaDir);
|
await _collectMedia(projectId, mediaDir, since);
|
||||||
|
|
||||||
// 3. ZIP csomagolás
|
// 3. ZIP csomagolás
|
||||||
final zipPath = p.join(tmpDir.path, '${name}_$ts.zip');
|
final zipPath = p.join(tmpDir.path, '${name}_$ts.zip');
|
||||||
@@ -65,13 +65,13 @@ class GeoPackageExporter {
|
|||||||
|
|
||||||
// ── GeoPackage (.gpkg) létrehozása ───────────────────────────────
|
// ── GeoPackage (.gpkg) létrehozása ───────────────────────────────
|
||||||
|
|
||||||
Future<void> _buildGpkg(String path, int? projectId) async {
|
Future<void> _buildGpkg(String path, int? projectId, DateTime? since) async {
|
||||||
final db = await openDatabase(path);
|
final db = await openDatabase(path);
|
||||||
try {
|
try {
|
||||||
await _initGpkg(db);
|
await _initGpkg(db);
|
||||||
await _exportNoteItems(db, projectId);
|
await _exportNoteItems(db, projectId, since);
|
||||||
await _exportMeasuredPoints(db, projectId);
|
await _exportMeasuredPoints(db, projectId, since);
|
||||||
await _exportTracks(db, projectId);
|
await _exportTracks(db, projectId, since);
|
||||||
} finally {
|
} finally {
|
||||||
await db.close();
|
await db.close();
|
||||||
}
|
}
|
||||||
@@ -187,11 +187,17 @@ class GeoPackageExporter {
|
|||||||
|
|
||||||
// ── NoteItem exportok ─────────────────────────────────────────────
|
// ── NoteItem exportok ─────────────────────────────────────────────
|
||||||
|
|
||||||
Future<void> _exportNoteItems(Database db, int? projectId) async {
|
Future<void> _exportNoteItems(
|
||||||
|
Database db, int? projectId, DateTime? since) async {
|
||||||
final items = await AppDatabase.instance.listNoteItems(projectId);
|
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 filtered = since != null
|
||||||
final polygons = items.where((i) => i.type == NoteType.polygon).toList();
|
? 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 (points.isNotEmpty) await _exportPoints(db, points);
|
||||||
if (lines.isNotEmpty) await _exportLines(db, lines);
|
if (lines.isNotEmpty) await _exportLines(db, lines);
|
||||||
@@ -310,12 +316,19 @@ class GeoPackageExporter {
|
|||||||
|
|
||||||
// ── Bemért pontok exportja ────────────────────────────────────────
|
// ── Bemért pontok exportja ────────────────────────────────────────
|
||||||
|
|
||||||
Future<void> _exportMeasuredPoints(Database db, int? projectId) async {
|
Future<void> _exportMeasuredPoints(
|
||||||
|
Database db, int? projectId, DateTime? since) async {
|
||||||
final points = projectId != null
|
final points = projectId != null
|
||||||
? await AppDatabase.instance.listMeasuredPoints(projectId)
|
? await AppDatabase.instance.listMeasuredPoints(projectId)
|
||||||
: <MeasuredPoint>[];
|
: <MeasuredPoint>[];
|
||||||
if (points.isEmpty) return;
|
if (points.isEmpty) return;
|
||||||
|
|
||||||
|
final filtered = since != null
|
||||||
|
? points.where((p) => p.timestamp.isAfter(since)).toList()
|
||||||
|
: points;
|
||||||
|
|
||||||
|
if (filtered.isEmpty) return;
|
||||||
|
|
||||||
await db.execute('''
|
await db.execute('''
|
||||||
CREATE TABLE measured_points (
|
CREATE TABLE measured_points (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
@@ -353,13 +366,20 @@ class GeoPackageExporter {
|
|||||||
|
|
||||||
// ── Track exportja ────────────────────────────────────────────────
|
// ── Track exportja ────────────────────────────────────────────────
|
||||||
|
|
||||||
Future<void> _exportTracks(Database db, int? projectId) async {
|
Future<void> _exportTracks(
|
||||||
|
Database db, int? projectId, DateTime? since) async {
|
||||||
final tracks = await AppDatabase.instance.listTracks();
|
final tracks = await AppDatabase.instance.listTracks();
|
||||||
final filtered = projectId != null
|
var filtered = projectId != null
|
||||||
? tracks.where((t) => t.projectId == projectId).toList()
|
? tracks.where((t) => t.projectId == projectId).toList()
|
||||||
: tracks;
|
: tracks;
|
||||||
if (filtered.isEmpty) return;
|
if (filtered.isEmpty) return;
|
||||||
|
|
||||||
|
if (since != null) {
|
||||||
|
filtered = filtered.where((t) => t.startTime.isAfter(since)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filtered.isEmpty) return;
|
||||||
|
|
||||||
await db.execute('''
|
await db.execute('''
|
||||||
CREATE TABLE tracks (
|
CREATE TABLE tracks (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
@@ -395,7 +415,8 @@ class GeoPackageExporter {
|
|||||||
|
|
||||||
// ── Médiafájlok másolása ──────────────────────────────────────────
|
// ── Médiafájlok másolása ──────────────────────────────────────────
|
||||||
|
|
||||||
Future<void> _collectMedia(int? projectId, Directory mediaDir) async {
|
Future<void> _collectMedia(
|
||||||
|
int? projectId, Directory mediaDir, DateTime? since) async {
|
||||||
if (projectId == null) return;
|
if (projectId == null) return;
|
||||||
|
|
||||||
final photos = Directory(p.join(mediaDir.path, 'photos'));
|
final photos = Directory(p.join(mediaDir.path, 'photos'));
|
||||||
@@ -404,7 +425,12 @@ class GeoPackageExporter {
|
|||||||
await audios.create(recursive: true);
|
await audios.create(recursive: true);
|
||||||
|
|
||||||
final items = await AppDatabase.instance.listNoteItems(projectId);
|
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
|
// Fotók
|
||||||
final photoList = await AppDatabase.instance.listNotePhotos(item.id!);
|
final photoList = await AppDatabase.instance.listNotePhotos(item.id!);
|
||||||
for (final photo in photoList) {
|
for (final photo in photoList) {
|
||||||
|
|||||||
@@ -1895,6 +1895,9 @@ class MapSurveyController extends GetxController implements StyleEditable {
|
|||||||
showGeometryLabels.value = !showGeometryLabels.value;
|
showGeometryLabels.value = !showGeometryLabels.value;
|
||||||
|
|
||||||
Future<void> exportProject() async {
|
Future<void> exportProject() async {
|
||||||
|
final since = await _showExportDateDialog();
|
||||||
|
if (since == false) return; // felhasználó megszakította
|
||||||
|
|
||||||
Get.dialog(
|
Get.dialog(
|
||||||
Center(
|
Center(
|
||||||
child: Material(
|
child: Material(
|
||||||
@@ -1932,6 +1935,59 @@ class MapSurveyController extends GetxController implements StyleEditable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Visszaad: DateTime (szűrt export), null (teljes export), false (mégse)
|
||||||
|
Future<dynamic> _showExportDateDialog() async {
|
||||||
|
return Get.dialog<dynamic>(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() {
|
void _subscribeToTeamPosition() {
|
||||||
_teamChannel = Supabase.instance.client
|
_teamChannel = Supabase.instance.client
|
||||||
.channel('public:terepi_seged_device_positions')
|
.channel('public:terepi_seged_device_positions')
|
||||||
|
|||||||
Reference in New Issue
Block a user