mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-12 08:50:53 +01:00
Some checks failed
dependency freshness / dependencies on newest stable (push) Has been cancelled
md-naming / markdown naming convention (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / lock-popup-safety (push) Has been cancelled
release-apk / release (APK) (push) Has been cancelled
The between-set break never finished once the phone's screen was off. Three independent causes (worked through on-device on 2026-09-12; left uncommitted awaiting the go-ahead, committed here as-is plus one pin bump): 1. The countdown was not wall-clock: `_breakRemaining--` on a Timer.periodic, which Android throttles and Doze suspends in a backgrounded isolate, so the counter stalled and _onBreakFinished() never fired. Now a BreakClock deadline on the wall clock. 2. An expired break was silently dropped on restore (`if (remaining > 0)` only) — now cued and logged. 3. No notification infrastructure at all: no package, no POST_NOTIFICATIONS / FOREGROUND_SERVICE / WAKE_LOCK. Now: flutter_foreground_task runs the countdown in a service isolate that survives BACK and the screen lock; flutter_local_notifications shows an ongoing "Workout A · break m:ss / Next: …" notification with −1 rep / Done actions and a "Break over" alert on its own channel (raw break_end sound, vibration). Button presses go through a persisted BreakIntent queue the screen drains on resume, so a press with the app killed is not lost. Finish and Reset stop the service; a startup reaper handles the crash case. Verified on the phone with the screen off and locked: service alive and ticking while Dozing, both notifications on the lock screen, channel importance 5 with the break_end sound. Not verifiable from adb (receiver is RECEIVER_NOT_EXPORTED): an actual action-button tap, and a true recents swipe — see stronglift_replacement/TODO-workout-app-v2.md. Also fixed en route: the break-end sound had never played in any widget test (AssetSource needs path_provider, which nothing faked, and the failure was swallowed by catchError); the queue's prune wrote back a stale list. This commit additionally: - takes the freshness gate's bump flutter_local_notifications 22.3.1; - restores web/package.json to HEAD (the tree held a stale pre-bump copy); - gives scripts/check_flutter_coverage.sh a FLUTTER_TEST_CONCURRENCY knob: the default one-isolate-per-core run peaks over 4 GiB and is OOM-killed under the resource cap. Default behaviour unchanged. Gate: flutter analyze clean, 511 tests, 3187/3187 lines (100%), pre-commit green. Not re-installed on the phone for the 22.3.1 pin: no device attached at commit time. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C7vgacLhb4WJjxuVj2QLEP
56 lines
1.6 KiB
Dart
56 lines
1.6 KiB
Dart
/// Fakes `path_provider` so `AssetSource` playback works in widget tests.
|
|
///
|
|
/// `audioplayers` copies an asset into the temporary directory before it can
|
|
/// play it, so without this every break-end cue in a widget test dies with
|
|
/// `MissingPluginException` — swallowed by `_playBreakEndCue`'s catch, which
|
|
/// means the sound silently never played and no test could tell.
|
|
library;
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
|
|
|
|
class _FakePathProvider extends PathProviderPlatform {
|
|
_FakePathProvider(this._root);
|
|
|
|
final String _root;
|
|
|
|
@override
|
|
Future<String?> getTemporaryPath() async => _root;
|
|
|
|
@override
|
|
Future<String?> getApplicationSupportPath() async => _root;
|
|
|
|
@override
|
|
Future<String?> getApplicationDocumentsPath() async => _root;
|
|
|
|
@override
|
|
Future<String?> getApplicationCachePath() async => _root;
|
|
|
|
@override
|
|
Future<String?> getLibraryPath() async => _root;
|
|
|
|
@override
|
|
Future<String?> getDownloadsPath() async => _root;
|
|
|
|
@override
|
|
Future<String?> getExternalStoragePath() async => _root;
|
|
|
|
@override
|
|
Future<List<String>?> getExternalCachePaths() async => [_root];
|
|
|
|
@override
|
|
Future<List<String>?> getExternalStoragePaths({
|
|
StorageDirectory? type,
|
|
}) async => [_root];
|
|
}
|
|
|
|
/// Points every `path_provider` lookup at a throwaway directory.
|
|
///
|
|
/// Returns the directory so a test can inspect what was written there.
|
|
Directory installFakePathProvider() {
|
|
final dir = Directory.systemTemp.createTempSync('workout_app_test_');
|
|
PathProviderPlatform.instance = _FakePathProvider(dir.path);
|
|
return dir;
|
|
}
|