import 'dart:developer'; import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; import 'package:terepi_seged/models/project.dart'; import 'package:terepi_seged/services/app_database.dart'; import 'package:terepi_seged/services/app_logger.dart'; /// Induláskor eldönti, hogy a navigációs képernyőt is meg kell-e nyitni. /// /// Mind a négy feltételnek teljesülnie kell: /// 1. A felhasználó be van jelentkezve (a munkamenet a készüléken tárolt, /// ez offline is eldönthető). /// 2. Az utoljára aktív projekt FELHŐS (nem csak helyi), aktív, és már /// szinkronizált (sync_status == 'synced'). /// 3. A szerver elérhető — ezt maga a lekérdezés bizonyítja (offline hibára /// fut). /// 4. A `terepi_seged_app_config` táblában megtalálható a /// `nav_autostart:` kulcs. Az érték tetszőleges (pl. 'igen'), /// csak a kulcs megléte számít. A járművet (V1, V2…) NEM állítja be, az /// marad a helyi érték. /// /// OFFLINE-FIRST: bármilyen hiba, időtúllépés vagy hiányzó adat esetén a /// válasz `false`, az app a megszokott módon indul. Sosem dob kivételt. class NavAutoStartService { NavAutoStartService._(); static const keyPrefix = 'nav_autostart:'; static const _channel = MethodChannel('hu.app_dev.terepi_seged/deviceInfo'); static bool _no(String reason) { // ignore: avoid_print print('🚀 NavAutoStart: NEM — $reason'); return false; } static Future shouldStartNavigation() async { try { final androidId = await _androidId(); if (androidId == null || androidId.isEmpty) { return _no('nincs ANDROID_ID'); } // ignore: avoid_print print('🚀 NavAutoStart: androidId=$androidId'); if (Supabase.instance.client.auth.currentUser == null) { return _no('nincs bejelentkezett felhasználó'); } if (!await _activeProjectIsOnline()) return false; final row = await Supabase.instance.client .from('terepi_seged_app_config') .select('key') .eq('key', '$keyPrefix$androidId') .maybeSingle() .timeout(const Duration(seconds: 3)); if (row == null) { return _no('nincs sor a kulccsal: $keyPrefix$androidId'); } AppLogger.event('nav_autostart'); // ignore: avoid_print print('🚀 NavAutoStart: IGEN'); return true; } catch (e) { return _no('hiba / időtúllépés: $e'); } } /// Az utoljára aktív projektet a ProjectService is a SharedPreferences-ből /// állítja vissza, ezért itt közvetlenül azt vizsgáljuk — így nem függ a /// ProjectService aszinkron indulásának időzítésétől. static Future _activeProjectIsOnline() async { final prefs = await SharedPreferences.getInstance(); final id = prefs.getInt('active_project_id'); if (id == null) return _no('nincs mentett aktív projekt'); final project = await AppDatabase.instance.getProject(id); if (project == null) return _no('a projekt nincs a helyi adatbázisban'); if (project.isLocalOnly) return _no('az aktív projekt csak helyi'); if (project.status != ProjectStatus.active) { return _no('a projekt nem aktív (${project.status})'); } final sync = await AppDatabase.instance.getProjectSyncStatus(id); if (sync != 'synced') return _no('sync_status=$sync (nem synced)'); return true; } /// Settings.Secure.ANDROID_ID — ugyanaz a csatorna, mint amit a /// DeviceIdentityService használ. static Future _androidId() async { try { return await _channel.invokeMethod('getAndroidId'); } catch (_) { return null; } } }