From 17e83c032ac1fed957a258924e97d2bec9cdc42a Mon Sep 17 00:00:00 2001 From: zsolt Date: Thu, 13 Aug 2026 14:26:55 +0200 Subject: [PATCH] Add automatic Google calendar sync --- lib/google_calendar_page.dart | 55 +++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/lib/google_calendar_page.dart b/lib/google_calendar_page.dart index 937c47e..2bf69d1 100644 --- a/lib/google_calendar_page.dart +++ b/lib/google_calendar_page.dart @@ -28,21 +28,30 @@ class AccountsPage extends StatefulWidget { class _AccountsPageState extends State with WidgetsBindingObserver { + static const googleAutoSyncInterval = Duration(minutes: 5); + static const googleResumeSyncInterval = Duration(minutes: 2); + List googleCalendars = []; bool loadingCalendars = false; bool syncing = false; bool waitingForGoogleAuthReturn = false; + Timer? googleAutoSyncTimer; String? statusMessage; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); + googleAutoSyncTimer = Timer.periodic( + googleAutoSyncInterval, + (_) => _autoSyncSelectedCalendars(), + ); _loadGoogleConnectionStatus(); } @override void dispose() { + googleAutoSyncTimer?.cancel(); WidgetsBinding.instance.removeObserver(this); super.dispose(); } @@ -66,6 +75,10 @@ class _AccountsPageState extends State if (state == AppLifecycleState.resumed && waitingForGoogleAuthReturn) { waitingForGoogleAuthReturn = false; _loadGoogleConnectionStatus(); + return; + } + if (state == AppLifecycleState.resumed) { + _autoSyncSelectedCalendars(minAge: googleResumeSyncInterval); } } @@ -106,6 +119,30 @@ class _AccountsPageState extends State return null; } + bool _canAutoSync() { + final current = connection; + return current != null && + current.accountEmail.isNotEmpty && + current.enabledCalendarIds.isNotEmpty && + !syncing && + !loadingCalendars && + _jarvisConfigError() == null; + } + + Future _autoSyncSelectedCalendars({ + Duration minAge = googleAutoSyncInterval, + }) async { + final current = connection; + if (!_canAutoSync() || current == null) return; + + final lastSync = current.lastSync; + if (lastSync != null && DateTime.now().difference(lastSync) < minAge) { + return; + } + + await _syncSelectedCalendars(automatic: true); + } + Future _loadGoogleConnectionStatus() async { setState(() { loadingCalendars = true; @@ -287,9 +324,10 @@ class _AccountsPageState extends State } } - Future _syncSelectedCalendars() async { + Future _syncSelectedCalendars({bool automatic = false}) async { final current = connection; if (current == null || current.enabledCalendarIds.isEmpty) { + if (automatic) return; setState( () => statusMessage = 'V\u00e1lassz ki legal\u00e1bb egy Google napt\u00e1rat.', @@ -299,7 +337,9 @@ class _AccountsPageState extends State setState(() { syncing = true; - statusMessage = 'Google esem\u00e9nyek beolvas\u00e1sa...'; + statusMessage = automatic + ? 'Automatikus Google szinkron fut...' + : 'Google esem\u00e9nyek beolvas\u00e1sa...'; }); try { @@ -377,14 +417,17 @@ class _AccountsPageState extends State ]); setState(() { syncing = false; - statusMessage = - '${synced.length} Google esem\u00e9ny szinkroniz\u00e1lva \u00e9s JSON cache-be mentve.' - '${syncDetails.isEmpty ? '' : ' R\u00e9szletek: ${syncDetails.join('; ')}.'}'; + statusMessage = automatic + ? '${synced.length} Google esem\u00e9ny automatikusan friss\u00edtve.' + : '${synced.length} Google esem\u00e9ny szinkroniz\u00e1lva \u00e9s JSON cache-be mentve.' + '${syncDetails.isEmpty ? '' : ' R\u00e9szletek: ${syncDetails.join('; ')}.'}'; }); } catch (error) { setState(() { syncing = false; - statusMessage = 'A Google szinkron nem siker\u00fclt: $error'; + statusMessage = automatic + ? 'Az automatikus Google szinkron most nem siker\u00fclt, a kor\u00e1bbi cache marad: $error' + : 'A Google szinkron nem siker\u00fclt: $error'; }); } }