MobilApp/lib/services/note_photo_service.dart

147 lines
4.9 KiB
Dart

// lib/services/note_photo_service.dart
//
// Fotó kezelő service:
// - Kamera / galéria hozzáférés (image_picker)
// - Fájl mentés külső tárhelyre
// - SQLite CRUD
// - Opcionális Supabase Storage szinkron
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import '../models/note_item_photo.dart';
import '../services/app_database.dart';
class NotePhotoService extends GetxService {
static NotePhotoService get to => Get.find();
final _picker = ImagePicker();
String? _photoDir;
@override
Future<void> onInit() async {
super.onInit();
await _initPhotoDir();
}
Future<void> _initPhotoDir() async {
final ext = await getExternalStorageDirectory();
final dir = Directory(p.join(ext!.path, 'photos'));
if (!await dir.exists()) await dir.create(recursive: true);
_photoDir = dir.path;
}
// ── Fotó készítése kamerával ─────────────────────────────────────
Future<NoteItemPhoto?> takePhoto(int noteItemId) async {
return _pickAndSave(
noteItemId: noteItemId,
source: ImageSource.camera,
);
}
// ── Fotó választása galériából ───────────────────────────────────
Future<NoteItemPhoto?> pickFromGallery(int noteItemId) async {
return _pickAndSave(
noteItemId: noteItemId,
source: ImageSource.gallery,
);
}
// ── Közös mentési logika ─────────────────────────────────────────
Future<NoteItemPhoto?> _pickAndSave({
required int noteItemId,
required ImageSource source,
}) async {
try {
final picked = await _picker.pickImage(
source: source,
imageQuality: 85, // tömörítés a tárhelyért
maxWidth: 2048,
maxHeight: 2048,
);
if (picked == null) return null; // felhasználó visszalépett
// GPS pozíció a fotókészítés pillanatában
final pos = await _currentPosition();
// Fájl másolása az app saját könyvtárába
final fileName =
'photo_${noteItemId}_${DateTime.now().millisecondsSinceEpoch}.jpg';
final destPath = p.join(_photoDir!, fileName);
await File(picked.path).copy(destPath);
// SQLite mentés
final photo = NoteItemPhoto(
noteItemId: noteItemId,
localPath: destPath,
latitude: pos?.latitude,
longitude: pos?.longitude,
createdAt: DateTime.now(),
);
final id = await AppDatabase.instance.insertNotePhoto(photo);
return NoteItemPhoto(
id: id,
noteItemId: photo.noteItemId,
localPath: photo.localPath,
latitude: photo.latitude,
longitude: photo.longitude,
createdAt: photo.createdAt,
);
} catch (e) {
debugPrint('NotePhotoService hiba: $e');
Get.snackbar('Hiba', 'Fotó mentése sikertelen.',
snackPosition: SnackPosition.BOTTOM);
return null;
}
}
// ── Fotó törlése ─────────────────────────────────────────────────
Future<void> deletePhoto(NoteItemPhoto photo) async {
// Fájl törlése
final file = File(photo.localPath);
if (await file.exists()) await file.delete();
// SQLite törlése
await AppDatabase.instance.deleteNotePhoto(photo.id!);
}
// ── Felirat frissítése ────────────────────────────────────────────
Future<NoteItemPhoto> updateCaption(
NoteItemPhoto photo, String caption) async {
final updated = photo.copyWith(caption: caption);
await AppDatabase.instance.updateNotePhoto(updated);
return updated;
}
// ── GPS pozíció ──────────────────────────────────────────────────
Future<Position?> _currentPosition() async {
try {
return await Geolocator.getCurrentPosition(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.medium,
timeLimit: Duration(seconds: 3),
),
).timeout(const Duration(seconds: 3));
} catch (_) {
return Geolocator.getLastKnownPosition();
}
}
// ── Fotók betöltése ──────────────────────────────────────────────
Future<List<NoteItemPhoto>> loadPhotos(int noteItemId) =>
AppDatabase.instance.listNotePhotos(noteItemId);
}