Files
MobilApp/lib/services/project_service.dart
T

227 lines
7.4 KiB
Dart
Raw Normal View History

import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:uuid/uuid.dart';
import '../models/project.dart';
import 'app_database.dart';
2026-07-07 02:21:08 +02:00
import 'ts_sync_service.dart';
class ProjectService extends GetxService {
static ProjectService get to => Get.find();
final activeProject = Rxn<Project>();
final projects = <Project>[].obs;
int? get activeProjectId => activeProject.value?.id;
@override
Future<void> onInit() async {
super.onInit();
await _loadProjects();
await _restoreActiveProject();
}
Future<void> _loadProjects() async {
projects.value = await AppDatabase.instance.listProjects();
}
// Az utoljára aktív projektet tárolja a SharedPreferences
Future<void> _restoreActiveProject() async {
final prefs = await SharedPreferences.getInstance();
final savedId = prefs.getInt('active_project_id');
if (savedId != null) {
final project = await AppDatabase.instance.getProject(savedId);
if (project != null && project.status == ProjectStatus.active) {
activeProject.value = project;
return;
}
}
// Fallback: az első aktív projekt
if (projects.isNotEmpty) {
await setActiveProject(projects.first);
}
}
Future<void> setActiveProject(Project project) async {
activeProject.value = project;
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('active_project_id', project.id!);
// Frissítjük az updated_at-et hogy a lista tetejére kerüljön
await AppDatabase.instance.updateProject(project.copyWith());
await _loadProjects();
}
Future<Project> createProject({
required String name,
String client = '',
String description = '',
ProjectCrs crs = ProjectCrs.eov,
String color = '#185FA5',
}) async {
final now = DateTime.now();
final project = Project(
uuid: const Uuid().v4(),
name: name,
client: client,
description: description,
crs: crs,
color: color,
createdAt: now,
updatedAt: now,
);
final id = await AppDatabase.instance.insertProject(project);
final saved = project.copyWith();
await _loadProjects();
return await AppDatabase.instance.getProject(id) ?? saved;
}
2026-07-07 02:21:08 +02:00
/// Közös (szinkronizált) projekt.
///
/// OFFLINE-FIRST: csak lokálisan jön létre (sync_status = 'pending'),
/// a feltöltést a TsSyncService végzi, amint van hálózat — így a
/// projekt-létrehozás net nélkül is működik, és nem ír többé
/// közvetlenül a régi Supabase-táblába.
Future<Project> createOnlineProject({
required String name,
String client = '',
ProjectCrs crs = ProjectCrs.eov,
String color = '#185FA5',
}) async {
final project = Project(
uuid: const Uuid().v4(),
name: name,
client: client,
crs: crs,
color: color,
isLocalOnly: false, // ← szinkronizált
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
// Lokálisan mentjük
final id = await AppDatabase.instance.insertProject(project);
2026-07-07 02:21:08 +02:00
// // Supabase-be is
// await Supabase.instance.client
// .from('TerepiSeged_Projects')
// .insert(project.toMap());
await _loadProjects();
2026-07-07 02:21:08 +02:00
// Ha van net, azonnal fel is megy (és owner-tagság is létrejön).
if (Get.isRegistered<TsSyncService>()) {
TsSyncService.to.syncNow();
}
return await AppDatabase.instance.getProject(id) ?? project;
}
/// Lokális projekt — soha nem kerül Supabase-be
Future<Project> createLocalProject({
required String name,
String client = '',
ProjectCrs crs = ProjectCrs.eov,
String color = '#185FA5',
}) async {
final project = Project(
uuid: const Uuid().v4(),
name: name,
client: client,
crs: crs,
color: color,
isLocalOnly: true, // ← csak lokális
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
// Csak lokálisan
final id = await AppDatabase.instance.insertProject(project);
await _loadProjects();
return await AppDatabase.instance.getProject(id) ?? project;
}
2026-07-07 02:21:08 +02:00
// ═════════════════════════════════════════════════════════════════
// Közös projektek — listázás és csatlakozás
// ═════════════════════════════════════════════════════════════════
/// A Supabase-en elérhető közös projektek listája
/// (név, tulajdonos, tagszám, is_member) — a ts_shared_projects view-ból.
Future<List<Map<String, dynamic>>> fetchSharedProjects() async {
final rows = await Supabase.instance.client
.from('terepi_seged_shared_projects')
.select()
.order('name', ascending: true);
return List<Map<String, dynamic>>.from(rows);
}
/// Csatlakozás egy közös projekthez (egyszerűsített modell):
/// 1. tagság-sor beszúrása (az RLS csak saját magunkat engedi felvenni),
/// 2. a projekt lokális sora létrejön a TÁVOLI uuid-dal — innentől a
/// szinkron ugyanúgy kezeli, mint a sajátokat,
/// 3. azonnali szinkron, hogy a projekt eddigi adatai lejöjjenek.
Future<Project> joinSharedProject(Map<String, dynamic> sharedRow) async {
final client = Supabase.instance.client;
final projectUuid = sharedRow['id'] as String;
// 1. Tagság (idempotens: ha már tag, nem hiba).
await client.from('terepi_seged_project_members').upsert(
{
'project_id': projectUuid,
'user_id': client.auth.currentUser!.id,
'role': 'editor',
},
ignoreDuplicates: true,
);
// 2. Lokális projekt-sor a távoli uuid-dal.
final localId =
await AppDatabase.instance.upsertProjectFromRemote(sharedRow);
await _loadProjects();
// 3. Adatok letöltése háttérben.
if (Get.isRegistered<TsSyncService>()) {
TsSyncService.to.syncNow();
}
return (await AppDatabase.instance.getProject(localId))!;
}
/// Kilépés egy közös projektből: a tagság törlődik a szerveren,
/// a lokális adat megmarad (archiválható külön).
Future<void> leaveSharedProject(Project project) async {
final client = Supabase.instance.client;
await client
.from('terepi_seged_project_members')
.delete()
.eq('project_id', project.uuid)
.eq('user_id', client.auth.currentUser!.id);
}
// ═════════════════════════════════════════════════════════════════
Future<void> reloadProjects() => _loadProjects();
Future<Map<String, int>> getStats(int projectId) =>
AppDatabase.instance.getProjectStats(projectId);
Future<void> archiveProject(int id) async {
await AppDatabase.instance.archiveProject(id);
if (activeProject.value?.id == id) {
activeProject.value = projects.isNotEmpty
? projects.firstWhereOrNull((p) => p.id != id)
: null;
}
}
Future<void> updateProject(Project project) async {
await AppDatabase.instance.updateProject(project);
await _loadProjects();
if (activeProject.value?.id == project.id) {
activeProject.value = project;
}
}
}