From 0845290929f4168fc663f9ba5a8ef296b70cf424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horv=C3=A1th=20Gergely?= Date: Fri, 30 Jan 2026 10:41:26 +0100 Subject: [PATCH] Add logging, await token callback and widget refresh Fixes async token handling and improves observability: await the callback in KretaClient to ensure proper async flow, add informative logs for token expiry/refresh and warn on empty 200/201 API responses. Enhance token refresh flow in token_grant with detailed info/warning/severe logs and exception logging for easier debugging. Update widget DB helper to force fresh fetches for timetables/grades when updating widget cache, avoid writing empty caches and add debug prints for counts and cache status. Wire widget refresh into LiveActivityService background fetch (with import and try/catch logging) so iOS widgets get refreshed during background processing. --- firka/lib/helpers/api/client/kreta_client.dart | 15 ++++++++++++--- firka/lib/helpers/api/token_grant.dart | 7 +++++++ firka/lib/helpers/db/widget.dart | 15 +++++++++++---- firka/lib/helpers/live_activity_service.dart | 9 +++++++++ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/firka/lib/helpers/api/client/kreta_client.dart b/firka/lib/helpers/api/client/kreta_client.dart index 73a35a2e..fb16a176 100644 --- a/firka/lib/helpers/api/client/kreta_client.dart +++ b/firka/lib/helpers/api/client/kreta_client.dart @@ -66,7 +66,7 @@ class KretaClient { } _tokenMutex = true; try { - return callback(); + return await callback(); } finally { _tokenMutex = false; } @@ -78,7 +78,7 @@ class KretaClient { if (now.millisecondsSinceEpoch >= model.expiryDate!.millisecondsSinceEpoch) { - logger.finest("Token expired, refreshing: $model"); + logger.info("Token expired at ${model.expiryDate}, refreshing for user: ${model.studentId}"); var extended = await extendToken(model); var tokenModel = TokenModel.fromResp(extended); @@ -86,7 +86,7 @@ class KretaClient { await isar.tokenModels.put(tokenModel); }); - logger.finest("Token refreshed and saved: $model"); + logger.info("Token refreshed successfully. New expiry: ${tokenModel.expiryDate}"); model = tokenModel; } @@ -116,6 +116,15 @@ class KretaClient { if (!url.endsWith("TanuloAdatlap")) { logger.finest("Response: ${resp.statusCode} ${resp.data}"); } + + if (resp.statusCode == 200 || resp.statusCode == 201) { + final responseData = resp.data; + if (responseData == null || + (responseData is List && responseData.isEmpty) || + (responseData is Map && responseData.isEmpty)) { + logger.warning("API returned ${resp.statusCode} with empty data for: $url - possible stale session"); + } + } } catch (ex) { if (ex is Error) { logger.shout( diff --git a/firka/lib/helpers/api/token_grant.dart b/firka/lib/helpers/api/token_grant.dart index c1707520..cd956d25 100644 --- a/firka/lib/helpers/api/token_grant.dart +++ b/firka/lib/helpers/api/token_grant.dart @@ -41,6 +41,8 @@ Future getAccessToken(String code) async { } Future extendToken(TokenModel model) async { + logger.info("Extending token for user: ${model.studentId}, institute: ${model.iss}"); + final headers = { "content-type": "application/x-www-form-urlencoded; charset=UTF-8", "accept": "*/*", @@ -60,16 +62,21 @@ Future extendToken(TokenModel model) async { switch (response.statusCode) { case 200: + logger.info("Token extended successfully for user: ${model.studentId}"); return TokenGrantResponse.fromJson(response.data); case 400: + logger.warning("Token refresh failed (400) - refresh token expired for user: ${model.studentId}"); throw TokenExpiredException(); case 401: + logger.warning("Token refresh failed (401) - invalid grant for user: ${model.studentId}"); throw InvalidGrantException(); default: + logger.severe("Token refresh failed with unexpected status: ${response.statusCode} for user: ${model.studentId}"); throw Exception( "Failed to get access token, response code: ${response.statusCode}"); } } catch (e) { + logger.severe("Token refresh exception for user: ${model.studentId}: $e"); rethrow; } } diff --git a/firka/lib/helpers/db/widget.dart b/firka/lib/helpers/db/widget.dart index ce0aafc5..3200e6a5 100644 --- a/firka/lib/helpers/db/widget.dart +++ b/firka/lib/helpers/db/widget.dart @@ -64,13 +64,16 @@ class WidgetCacheHelper { final start = now.subtract(Duration(days: 7)); final end = now.add(Duration(days: 14)); - final lessons = await client.getTimeTable(start, end); + final lessons = await client.getTimeTable(start, end, forceCache: false); final widgetFile = File(p.join(dataDir.path, "widget_state.json")); if (lessons.response != null) { + debugPrint('Android widget cache: ${lessons.response!.length} lessons (cached: ${lessons.cached})'); widgetFile.writeAsString( jsonEncode(WidgetCacheHelper.toJson(style, lessons.response!))); + } else { + debugPrint('Android widget cache: No lessons to cache'); } } @@ -137,7 +140,6 @@ class WidgetCacheHelper { theme = isLightMode.value ? 'light' : 'dark'; } - // Get today's and tomorrow's lessons final now = timeNow(); final todayMidnight = DateTime(now.year, now.month, now.day); final tomorrowMidnight = todayMidnight.add(Duration(days: 1)); @@ -145,19 +147,24 @@ class WidgetCacheHelper { final todayResponse = await client.getTimeTable( todayMidnight, todayMidnight.add(Duration(hours: 23, minutes: 59)), + forceCache: false, ); final tomorrowResponse = await client.getTimeTable( tomorrowMidnight, tomorrowMidnight.add(Duration(hours: 23, minutes: 59)), + forceCache: false, ); final todayLessons = todayResponse.response ?? []; final tomorrowLessons = tomorrowResponse.response ?? []; - // Get grades - final gradesResponse = await client.getGrades(); + debugPrint('iOS widget refresh: ${todayLessons.length} today lessons, ${tomorrowLessons.length} tomorrow lessons'); + + final gradesResponse = await client.getGrades(forceCache: false); final grades = gradesResponse.response ?? []; + debugPrint('iOS widget refresh: ${grades.length} grades fetched (cached: ${gradesResponse.cached})'); + // Calculate subject averages final Map subjectAverages = {}; final Set subjectUids = {}; diff --git a/firka/lib/helpers/live_activity_service.dart b/firka/lib/helpers/live_activity_service.dart index b13fdc94..a29cdfb5 100644 --- a/firka/lib/helpers/live_activity_service.dart +++ b/firka/lib/helpers/live_activity_service.dart @@ -5,6 +5,7 @@ import 'package:firka/helpers/api/client/live_activity_backend_client.dart'; import 'package:firka/helpers/api/model/generic.dart'; import 'package:firka/helpers/api/model/timetable.dart'; import 'package:firka/helpers/db/models/app_settings_model.dart'; +import 'package:firka/helpers/db/widget.dart'; import 'package:firka/helpers/live_activity_manager.dart'; import 'package:firka/helpers/settings.dart'; import 'package:firka/ui/phone/screens/live_activity/live_activity_consent_screen.dart'; @@ -443,6 +444,14 @@ class LiveActivityService { } } + try { + _logger.info('Background fetch: refreshing iOS widgets...'); + await WidgetCacheHelper.refreshIOSWidgets(client, initData.settings); + _logger.info('Background fetch: iOS widgets refreshed successfully'); + } catch (e) { + _logger.warning('Background fetch: failed to refresh iOS widgets: $e'); + } + bool foundFirstSchoolDay = false; for (int dayOffset = 1; dayOffset <= 5; dayOffset++) { final candidateDay = endOfWeek.add(Duration(days: dayOffset));