Cache Jarvis app config on startup

This commit is contained in:
zsolt 2026-08-13 02:28:02 +02:00
parent eb3d7cd446
commit 0cde10d2c7
4 changed files with 81 additions and 4 deletions

View File

@ -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"
}

View File

@ -15,6 +15,7 @@ class _OtthonAppState extends State<OtthonApp> {
List<CalendarEvent> syncedEvents = []; List<CalendarEvent> syncedEvents = [];
List<String> todoSuggestions = []; List<String> todoSuggestions = [];
JarvisSettings jarvisSettings = JarvisSettings.defaults(); JarvisSettings jarvisSettings = JarvisSettings.defaults();
String googleServerClientId = googleCalendarServerClientId;
WeatherSnapshot? weather; WeatherSnapshot? weather;
String themeId = 'sage'; String themeId = 'sage';
bool loaded = false; bool loaded = false;
@ -40,9 +41,11 @@ class _OtthonAppState extends State<OtthonApp> {
syncedEvents = settings.syncedEvents; syncedEvents = settings.syncedEvents;
todoSuggestions = settings.todoSuggestions; todoSuggestions = settings.todoSuggestions;
jarvisSettings = settings.jarvisSettings; jarvisSettings = settings.jarvisSettings;
googleServerClientId = settings.googleServerClientId;
themeId = settings.themeId; themeId = settings.themeId;
loaded = true; loaded = true;
}); });
_loadRemoteAppConfig();
} }
Future<void> _saveSettings() async { Future<void> _saveSettings() async {
@ -54,10 +57,39 @@ class _OtthonAppState extends State<OtthonApp> {
syncedEvents: syncedEvents, syncedEvents: syncedEvents,
todoSuggestions: todoSuggestions, todoSuggestions: todoSuggestions,
jarvisSettings: jarvisSettings, jarvisSettings: jarvisSettings,
googleServerClientId: googleServerClientId,
), ),
); );
} }
Future<void> _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<String, dynamic>) 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<Person> nextPeople) { void _updatePeople(List<Person> nextPeople) {
setState(() => people = nextPeople); setState(() => people = nextPeople);
_saveSettings(); _saveSettings();
@ -88,6 +120,7 @@ class _OtthonAppState extends State<OtthonApp> {
void _updateJarvisSettings(JarvisSettings nextSettings) { void _updateJarvisSettings(JarvisSettings nextSettings) {
setState(() => jarvisSettings = nextSettings); setState(() => jarvisSettings = nextSettings);
_saveSettings(); _saveSettings();
_loadRemoteAppConfig();
} }
Future<void> _loadWeather() async { Future<void> _loadWeather() async {
@ -132,6 +165,7 @@ class _OtthonAppState extends State<OtthonApp> {
syncedEvents: syncedEvents, syncedEvents: syncedEvents,
todoSuggestions: todoSuggestions, todoSuggestions: todoSuggestions,
jarvisSettings: jarvisSettings, jarvisSettings: jarvisSettings,
googleServerClientId: googleServerClientId,
weather: weather, weather: weather,
themeId: themeId, themeId: themeId,
loaded: loaded, loaded: loaded,
@ -154,6 +188,7 @@ class HomeShell extends StatefulWidget {
required this.syncedEvents, required this.syncedEvents,
required this.todoSuggestions, required this.todoSuggestions,
required this.jarvisSettings, required this.jarvisSettings,
required this.googleServerClientId,
required this.weather, required this.weather,
required this.themeId, required this.themeId,
required this.loaded, required this.loaded,
@ -170,6 +205,7 @@ class HomeShell extends StatefulWidget {
final List<CalendarEvent> syncedEvents; final List<CalendarEvent> syncedEvents;
final List<String> todoSuggestions; final List<String> todoSuggestions;
final JarvisSettings jarvisSettings; final JarvisSettings jarvisSettings;
final String googleServerClientId;
final WeatherSnapshot? weather; final WeatherSnapshot? weather;
final String themeId; final String themeId;
final bool loaded; final bool loaded;
@ -352,6 +388,7 @@ class _HomeShellState extends State<HomeShell> {
cachedEvents: widget.syncedEvents, cachedEvents: widget.syncedEvents,
people: widget.people, people: widget.people,
jarvisSettings: widget.jarvisSettings, jarvisSettings: widget.jarvisSettings,
serverClientId: widget.googleServerClientId,
onChanged: widget.onGoogleConnectionsChanged, onChanged: widget.onGoogleConnectionsChanged,
onSyncedEventsChanged: widget.onSyncedEventsChanged, onSyncedEventsChanged: widget.onSyncedEventsChanged,
), ),

View File

@ -125,6 +125,7 @@ class AppJsonStore {
syncedEvents: const [], syncedEvents: const [],
todoSuggestions: const [], todoSuggestions: const [],
jarvisSettings: JarvisSettings.defaults(), jarvisSettings: JarvisSettings.defaults(),
googleServerClientId: googleCalendarServerClientId,
); );
await save(settings); await save(settings);
return settings; return settings;
@ -141,6 +142,7 @@ class AppJsonStore {
syncedEvents: const [], syncedEvents: const [],
todoSuggestions: const [], todoSuggestions: const [],
jarvisSettings: JarvisSettings.defaults(), jarvisSettings: JarvisSettings.defaults(),
googleServerClientId: googleCalendarServerClientId,
); );
} }
} }
@ -161,6 +163,7 @@ class AppSettings {
required this.syncedEvents, required this.syncedEvents,
required this.todoSuggestions, required this.todoSuggestions,
required this.jarvisSettings, required this.jarvisSettings,
required this.googleServerClientId,
}); });
final List<Person> people; final List<Person> people;
@ -169,6 +172,7 @@ class AppSettings {
final List<CalendarEvent> syncedEvents; final List<CalendarEvent> syncedEvents;
final List<String> todoSuggestions; final List<String> todoSuggestions;
final JarvisSettings jarvisSettings; final JarvisSettings jarvisSettings;
final String googleServerClientId;
factory AppSettings.fromJson(Map<String, dynamic> json) { factory AppSettings.fromJson(Map<String, dynamic> json) {
final rawPeople = json['people']; final rawPeople = json['people'];
@ -204,6 +208,8 @@ class AppSettings {
jarvisSettings: rawJarvisSettings is Map<String, dynamic> jarvisSettings: rawJarvisSettings is Map<String, dynamic>
? JarvisSettings.fromJson(rawJarvisSettings) ? JarvisSettings.fromJson(rawJarvisSettings)
: JarvisSettings.defaults(), : JarvisSettings.defaults(),
googleServerClientId:
json['googleServerClientId'] as String? ?? googleCalendarServerClientId,
); );
} }
@ -216,6 +222,7 @@ class AppSettings {
'syncedEvents': syncedEvents.map((event) => event.toJson()).toList(), 'syncedEvents': syncedEvents.map((event) => event.toJson()).toList(),
'todoSuggestions': todoSuggestions, 'todoSuggestions': todoSuggestions,
'jarvisSettings': jarvisSettings.toJson(), 'jarvisSettings': jarvisSettings.toJson(),
'googleServerClientId': googleServerClientId,
}; };
} }

View File

@ -7,6 +7,7 @@ class AccountsPage extends StatefulWidget {
required this.cachedEvents, required this.cachedEvents,
required this.people, required this.people,
required this.jarvisSettings, required this.jarvisSettings,
required this.serverClientId,
required this.onChanged, required this.onChanged,
required this.onSyncedEventsChanged, required this.onSyncedEventsChanged,
}); });
@ -15,6 +16,7 @@ class AccountsPage extends StatefulWidget {
final List<CalendarEvent> cachedEvents; final List<CalendarEvent> cachedEvents;
final List<Person> people; final List<Person> people;
final JarvisSettings jarvisSettings; final JarvisSettings jarvisSettings;
final String serverClientId;
final ValueChanged<List<GoogleCalendarConnection>> onChanged; final ValueChanged<List<GoogleCalendarConnection>> onChanged;
final ValueChanged<List<CalendarEvent>> onSyncedEventsChanged; final ValueChanged<List<CalendarEvent>> onSyncedEventsChanged;
@ -51,9 +53,10 @@ class _AccountsPageState extends State<AccountsPage> {
statusMessage = 'Google napt\u00e1rkapcsolat el\u0151k\u00e9sz\u00edt\u00e9se...'; 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; if (!mounted) return;
runtimeServerClientId = configuredClientId?.trim();
await _initializeGoogle(); await _initializeGoogle();
} }
@ -147,8 +150,9 @@ class _AccountsPageState extends State<AccountsPage> {
try { try {
if (!initialized) { if (!initialized) {
final configuredClientId = await _loadGoogleServerClientId(); runtimeServerClientId = widget.serverClientId.trim().isNotEmpty
runtimeServerClientId = configuredClientId?.trim(); ? widget.serverClientId.trim()
: await _loadGoogleServerClientId();
await _ensureGoogleInitialized(); await _ensureGoogleInitialized();
initialized = true; initialized = true;
} }