-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New: backgroundResultProvider checks bg activity
This introduces a (currently still basic) BackgroundResult class and a notifier that has checkForActivity() to check whether the background task had been active since the last time we checked. Currently this is done in ViewPage whenever the user opens some worksheet. Shows a snackbar when activity was detected.
- Loading branch information
Showing
11 changed files
with
208 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import 'package:app4training/data/globals.dart'; | ||
import 'package:app4training/data/languages.dart'; | ||
import 'package:app4training/data/updates.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
|
||
/// The results of the background task (if it ran and did something) | ||
/// Currently it holds just a bool but this will be extended | ||
/// to hold detailled information in case there was some activity | ||
@immutable | ||
class BackgroundResult { | ||
final bool foundActivity; | ||
|
||
const BackgroundResult(this.foundActivity); | ||
|
||
@override | ||
String toString() { | ||
return 'Background result: activity = $foundActivity'; | ||
} | ||
} | ||
|
||
class BackgroundResultNotifier extends Notifier<BackgroundResult> { | ||
@override | ||
BackgroundResult build() { | ||
return const BackgroundResult(false); | ||
} | ||
|
||
/// Check whether the background task found updates and if yes: read results | ||
/// Returns whether we found activity of the background task | ||
/// | ||
/// Implementation: Are the lastChecked dates | ||
/// in the SharedPreferences newer than what we have stored in languageStatus? | ||
/// (TODO see overview over synchronization with background isolate) | ||
/// | ||
/// Remark: languageStatusProviders must have been initialized already before, | ||
/// otherwise they're loading their lastChecked times from sharedPrefs now | ||
/// and can't detect any background activity | ||
Future<bool> checkForActivity() async { | ||
debugPrint("Checking for background activity"); | ||
bool foundBgActivity = false; | ||
|
||
// Reload SharedPreferences because they're cached | ||
// May need to change when SharedPreferences gets an API to directly | ||
// use it asynchronously: https://github.com/flutter/packages/pull/5210 | ||
await ref.read(sharedPrefsProvider).reload(); | ||
|
||
for (String languageCode in ref.read(availableLanguagesProvider)) { | ||
// We don't check languages that are not downloaded | ||
if (!ref.read(languageProvider(languageCode)).downloaded) continue; | ||
|
||
DateTime lcTimestampOrig = | ||
ref.read(languageStatusProvider(languageCode)).lastCheckedTimestamp; | ||
DateTime? lcTimestamp; | ||
String? lcRaw = | ||
ref.read(sharedPrefsProvider).getString('lastChecked-$languageCode'); | ||
if (lcRaw != null) { | ||
try { | ||
lcTimestamp = DateTime.parse(lcRaw).toUtc(); | ||
} on FormatException { | ||
debugPrint( | ||
'Error while trying to parse lastChecked timestamp: $lcRaw'); | ||
lcTimestamp = null; | ||
} | ||
} | ||
if ((lcTimestamp != null) && | ||
(lcTimestamp.compareTo(DateTime.now()) <= 0) && | ||
lcTimestamp.compareTo(lcTimestampOrig) > 0) { | ||
// It looks like there has been background activity! | ||
debugPrint( | ||
'Background activity detected: lastChecked was $lcTimestampOrig, sharedPrefs says $lcTimestamp'); | ||
foundBgActivity = true; | ||
} else { | ||
debugPrint( | ||
'No background activity. lastChecked: $lcTimestampOrig, sharedPrefs says $lcRaw'); | ||
} | ||
} | ||
debugPrint('Checking for background activity done'); | ||
state = BackgroundResult(foundBgActivity); | ||
return foundBgActivity; | ||
} | ||
} | ||
|
||
final backgroundResultProvider = | ||
NotifierProvider<BackgroundResultNotifier, BackgroundResult>(() { | ||
return BackgroundResultNotifier(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import 'package:app4training/background/background_result.dart'; | ||
import 'package:app4training/data/globals.dart'; | ||
import 'package:app4training/data/languages.dart'; | ||
import 'package:app4training/data/updates.dart'; | ||
import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:shared_preferences/shared_preferences.dart'; | ||
|
||
import 'languages_test.dart'; | ||
|
||
void main() { | ||
test('No background activity', () async { | ||
SharedPreferences.setMockInitialValues({}); | ||
final prefs = await SharedPreferences.getInstance(); | ||
|
||
final ref = ProviderContainer(overrides: [ | ||
languageProvider.overrideWith(() => TestLanguageController()), | ||
sharedPrefsProvider.overrideWith((ref) => prefs) | ||
]); | ||
|
||
expect(await ref.read(backgroundResultProvider.notifier).checkForActivity(), | ||
false); | ||
}); | ||
|
||
test('There was some background activity', () async { | ||
final oldTime = DateTime(2023, 2, 2).toUtc(); | ||
SharedPreferences.setMockInitialValues( | ||
{'lastChecked-de': oldTime.toIso8601String()}); | ||
final prefs = await SharedPreferences.getInstance(); | ||
|
||
final ref = ProviderContainer(overrides: [ | ||
languageProvider.overrideWith(() => TestLanguageController()), | ||
sharedPrefsProvider.overrideWith((ref) => prefs) | ||
]); | ||
|
||
expect(await ref.read(backgroundResultProvider.notifier).checkForActivity(), | ||
false); | ||
|
||
// Now we change the lastChecked timestamp for German | ||
final currentTime = DateTime.now().toUtc(); | ||
await prefs.setString('lastChecked-de', currentTime.toIso8601String()); | ||
expect(ref.read(languageStatusProvider('de')).lastCheckedTimestamp, | ||
equals(oldTime)); | ||
|
||
expect(await ref.read(backgroundResultProvider.notifier).checkForActivity(), | ||
true); | ||
|
||
// TODO: It would probably be good if checkForActivity also updates | ||
// the language status providers if necessary | ||
// expect(ref.read(languageStatusProvider('de')).lastCheckedTimestamp, | ||
// equals(currentTime)); | ||
}); | ||
|
||
test('Test edge case: invalid values', () async { | ||
final oldTime = DateTime(2023, 2, 2).toUtc(); | ||
SharedPreferences.setMockInitialValues( | ||
{'lastChecked-de': oldTime.toIso8601String()}); | ||
final prefs = await SharedPreferences.getInstance(); | ||
|
||
final ref = ProviderContainer(overrides: [ | ||
languageProvider.overrideWith(() => TestLanguageController()), | ||
sharedPrefsProvider.overrideWith((ref) => prefs) | ||
]); | ||
|
||
expect(await ref.read(backgroundResultProvider.notifier).checkForActivity(), | ||
false); | ||
|
||
// Now we set the lastChecked timestamp to an invalid value | ||
await prefs.setString('lastChecked-de', 'invalid'); | ||
expect(await ref.read(backgroundResultProvider.notifier).checkForActivity(), | ||
false); | ||
|
||
DateTime futureDate = DateTime.now().add(const Duration(days: 1)); | ||
await prefs.setString('lastChecked-de', futureDate.toIso8601String()); | ||
expect(await ref.read(backgroundResultProvider.notifier).checkForActivity(), | ||
false); | ||
|
||
await prefs.setString('lastChecked-de', DateTime(2023).toIso8601String()); | ||
expect(await ref.read(backgroundResultProvider.notifier).checkForActivity(), | ||
true); | ||
|
||
expect(ref.read(languageStatusProvider('de')).lastCheckedTimestamp, | ||
equals(oldTime)); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters