diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..fd777d5 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "988487669355", + "project_id": "otthonnaptar-b9e74", + "storage_bucket": "otthonnaptar-b9e74.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:988487669355:android:a74debf7d71bb37d49c32e", + "android_client_info": { + "package_name": "hu.otthonnaptar.otthon_naptar" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBhoH8a2CxYZbwoEPllg-EoO0mGI0fW-jw" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/lib/app_shell.dart b/lib/app_shell.dart index 4644b04..7f7d624 100644 --- a/lib/app_shell.dart +++ b/lib/app_shell.dart @@ -15,6 +15,7 @@ class _OtthonAppState extends State { List syncedEvents = []; List todoSuggestions = []; JarvisSettings jarvisSettings = JarvisSettings.defaults(); + String googleServerClientId = googleCalendarServerClientId; WeatherSnapshot? weather; String themeId = 'sage'; bool loaded = false; @@ -40,9 +41,11 @@ class _OtthonAppState extends State { syncedEvents = settings.syncedEvents; todoSuggestions = settings.todoSuggestions; jarvisSettings = settings.jarvisSettings; + googleServerClientId = settings.googleServerClientId; themeId = settings.themeId; loaded = true; }); + _loadRemoteAppConfig(); } Future _saveSettings() async { @@ -54,10 +57,39 @@ class _OtthonAppState extends State { syncedEvents: syncedEvents, todoSuggestions: todoSuggestions, jarvisSettings: jarvisSettings, + googleServerClientId: googleServerClientId, ), ); } + Future _loadRemoteAppConfig() async { + final apiToken = jarvisSettings.apiToken.trim(); + if (apiToken.isEmpty) return; + + try { + final baseUri = Uri.parse(normalizeJarvisUrl(jarvisSettings.apiUrl)); + final uri = baseUri.replace(path: '/api/app-config', query: ''); + final response = await http + .get(uri, headers: {'X-Otthon-Token': apiToken}) + .timeout(const Duration(seconds: 10)); + if (response.statusCode != 200) return; + final payload = jsonDecode(response.body); + if (payload is! Map) return; + final remoteGoogleClientId = + payload['googleCalendarServerClientId'] as String?; + if (remoteGoogleClientId == null || + remoteGoogleClientId.trim().isEmpty || + remoteGoogleClientId == googleServerClientId) { + return; + } + if (!mounted) return; + setState(() => googleServerClientId = remoteGoogleClientId.trim()); + _saveSettings(); + } catch (_) { + // Offline mode keeps the locally cached app configuration. + } + } + void _updatePeople(List nextPeople) { setState(() => people = nextPeople); _saveSettings(); @@ -88,6 +120,7 @@ class _OtthonAppState extends State { void _updateJarvisSettings(JarvisSettings nextSettings) { setState(() => jarvisSettings = nextSettings); _saveSettings(); + _loadRemoteAppConfig(); } Future _loadWeather() async { @@ -132,6 +165,7 @@ class _OtthonAppState extends State { syncedEvents: syncedEvents, todoSuggestions: todoSuggestions, jarvisSettings: jarvisSettings, + googleServerClientId: googleServerClientId, weather: weather, themeId: themeId, loaded: loaded, @@ -154,6 +188,7 @@ class HomeShell extends StatefulWidget { required this.syncedEvents, required this.todoSuggestions, required this.jarvisSettings, + required this.googleServerClientId, required this.weather, required this.themeId, required this.loaded, @@ -170,6 +205,7 @@ class HomeShell extends StatefulWidget { final List syncedEvents; final List todoSuggestions; final JarvisSettings jarvisSettings; + final String googleServerClientId; final WeatherSnapshot? weather; final String themeId; final bool loaded; @@ -352,6 +388,7 @@ class _HomeShellState extends State { cachedEvents: widget.syncedEvents, people: widget.people, jarvisSettings: widget.jarvisSettings, + serverClientId: widget.googleServerClientId, onChanged: widget.onGoogleConnectionsChanged, onSyncedEventsChanged: widget.onSyncedEventsChanged, ), diff --git a/lib/data.dart b/lib/data.dart index 033043f..54639c5 100644 --- a/lib/data.dart +++ b/lib/data.dart @@ -125,6 +125,7 @@ class AppJsonStore { syncedEvents: const [], todoSuggestions: const [], jarvisSettings: JarvisSettings.defaults(), + googleServerClientId: googleCalendarServerClientId, ); await save(settings); return settings; @@ -141,6 +142,7 @@ class AppJsonStore { syncedEvents: const [], todoSuggestions: const [], jarvisSettings: JarvisSettings.defaults(), + googleServerClientId: googleCalendarServerClientId, ); } } @@ -161,6 +163,7 @@ class AppSettings { required this.syncedEvents, required this.todoSuggestions, required this.jarvisSettings, + required this.googleServerClientId, }); final List people; @@ -169,6 +172,7 @@ class AppSettings { final List syncedEvents; final List todoSuggestions; final JarvisSettings jarvisSettings; + final String googleServerClientId; factory AppSettings.fromJson(Map json) { final rawPeople = json['people']; @@ -204,6 +208,8 @@ class AppSettings { jarvisSettings: rawJarvisSettings is Map ? JarvisSettings.fromJson(rawJarvisSettings) : JarvisSettings.defaults(), + googleServerClientId: + json['googleServerClientId'] as String? ?? googleCalendarServerClientId, ); } @@ -216,6 +222,7 @@ class AppSettings { 'syncedEvents': syncedEvents.map((event) => event.toJson()).toList(), 'todoSuggestions': todoSuggestions, 'jarvisSettings': jarvisSettings.toJson(), + 'googleServerClientId': googleServerClientId, }; } diff --git a/lib/google_calendar_page.dart b/lib/google_calendar_page.dart index 7c7eb5a..e32e96b 100644 --- a/lib/google_calendar_page.dart +++ b/lib/google_calendar_page.dart @@ -7,6 +7,7 @@ class AccountsPage extends StatefulWidget { required this.cachedEvents, required this.people, required this.jarvisSettings, + required this.serverClientId, required this.onChanged, required this.onSyncedEventsChanged, }); @@ -15,6 +16,7 @@ class AccountsPage extends StatefulWidget { final List cachedEvents; final List people; final JarvisSettings jarvisSettings; + final String serverClientId; final ValueChanged> onChanged; final ValueChanged> onSyncedEventsChanged; @@ -51,9 +53,10 @@ class _AccountsPageState extends State { statusMessage = 'Google napt\u00e1rkapcsolat el\u0151k\u00e9sz\u00edt\u00e9se...'; }); - final configuredClientId = await _loadGoogleServerClientId(); + runtimeServerClientId = widget.serverClientId.trim().isNotEmpty + ? widget.serverClientId.trim() + : await _loadGoogleServerClientId(); if (!mounted) return; - runtimeServerClientId = configuredClientId?.trim(); await _initializeGoogle(); } @@ -147,8 +150,9 @@ class _AccountsPageState extends State { try { if (!initialized) { - final configuredClientId = await _loadGoogleServerClientId(); - runtimeServerClientId = configuredClientId?.trim(); + runtimeServerClientId = widget.serverClientId.trim().isNotEmpty + ? widget.serverClientId.trim() + : await _loadGoogleServerClientId(); await _ensureGoogleInitialized(); initialized = true; }