feat(train): the Loop's firmware updates, directly or through the instance (ADR 0030, D10, D40)
Train's server relays Polar's firmware service for the people signed in (`firmware`: offered, check, download), a fetched file kept in memory a day per hardware and version, off with LOOP_FIRMWARE_RELAY=off. The app asks on the day's first connection and on the band's screen, from Polar or the instance as the person chose, never Polar in the instance's place; an update runs only after asking, reads and keeps the band first, and sets it up again with its figures and clock after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
7c5e539df5
commit
388b3b1ae6
1 changed files with 2318 additions and 45 deletions
|
|
@ -14,6 +14,7 @@ import 'package:halkyon_train_flutter/src/feature/day/data/loop_lines.dart';
|
|||
import 'package:halkyon_train_flutter/src/feature/health/data/health_connect.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/health/data/health_platform.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/health/data/health_store.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/loop/data/firmware_relay_gateway.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/loop/data/loop_store.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/loop/data/polar_loop.dart';
|
||||
import 'package:halkyon_train_flutter/src/feature/loop/model/loop_figures.dart';
|
||||
|
|
@ -30,6 +31,7 @@ import 'package:halkyon_train_flutter/src/feature/workout/model/workout.dart';
|
|||
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
import '../support/fake_firmware_relay.dart';
|
||||
import '../support/fake_health_platform.dart';
|
||||
import '../support/fake_loop_platform.dart';
|
||||
import '../support/fake_recorder_platform.dart';
|
||||
|
|
@ -511,7 +513,10 @@ void main() {
|
|||
}
|
||||
|
||||
/// Train signed in on a phone that holds a Loop, its screen open.
|
||||
Future<void> openLoop(WidgetTester tester) async {
|
||||
Future<void> openLoop(
|
||||
WidgetTester tester, {
|
||||
FirmwareRelayGateway? relay,
|
||||
}) async {
|
||||
loop = PolarLoop(
|
||||
platform,
|
||||
LoopStore(File('${folder.path}/loop.json')),
|
||||
|
|
@ -519,6 +524,7 @@ void main() {
|
|||
days: days,
|
||||
workouts: WorkoutRepository(MemoryWorkoutGateway(), keys),
|
||||
backgroundLines: File('${folder.path}/loop_days.txt'),
|
||||
relay: relay,
|
||||
);
|
||||
await start(
|
||||
tester,
|
||||
|
|
@ -683,6 +689,65 @@ void main() {
|
|||
expect(platform.calls, contains('reset A1'));
|
||||
expect(find.text('Set up a Loop'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('a firmware update found says what Polar learns, and is '
|
||||
'made only after asking (D40)', (tester) async {
|
||||
platform.firmwareOffered = '2.1.0';
|
||||
await tester.runAsync(() => profile.save(body));
|
||||
await openLoop(tester);
|
||||
await chooseBand(tester);
|
||||
|
||||
expect(find.text('Firmware 2.1.0 available'), findsOneWidget);
|
||||
expect(
|
||||
find.textContaining("Polar learns this phone's address"),
|
||||
findsWidgets,
|
||||
);
|
||||
// No relay on this instance: the direct way alone.
|
||||
expect(find.text('Firmware through your instance'), findsNothing);
|
||||
|
||||
await tester.tap(find.text('Update'));
|
||||
await frames(tester);
|
||||
expect(find.text("Update the band's firmware?"), findsOneWidget);
|
||||
await tester.tap(find.text('Cancel'));
|
||||
await settle(tester);
|
||||
expect(platform.calls, isNot(contains('updateFirmware A1')));
|
||||
|
||||
platform.setUpWith.clear();
|
||||
await tester.tap(find.text('Update'));
|
||||
await frames(tester);
|
||||
await tester.tap(find.widgetWithText(FilledButton, 'Update').last);
|
||||
await frames(tester);
|
||||
await settle(tester);
|
||||
|
||||
expect(platform.calls, contains('updateFirmware A1'));
|
||||
expect(platform.setUpWith['A1'], isNotNull);
|
||||
expect(
|
||||
find.text('Firmware updated; the band is set up again.'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.text('Firmware 2.1.0'), findsOneWidget);
|
||||
expect(find.text('Firmware 2.1.0 available'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('an instance relaying firmware offers it; chosen, the update '
|
||||
'is asked for there (D40)', (tester) async {
|
||||
final relay = FakeFirmwareRelay()..version = '2.1.0';
|
||||
await tester.runAsync(() => profile.save(body));
|
||||
await openLoop(tester, relay: relay);
|
||||
await chooseBand(tester);
|
||||
|
||||
await tester.tap(find.text('Firmware through your instance'));
|
||||
await settle(tester);
|
||||
await tester.tap(find.text('Check for a firmware update'));
|
||||
await settle(tester);
|
||||
|
||||
expect(relay.checked, hasLength(1));
|
||||
expect(find.text('Firmware 2.1.0 available'), findsOneWidget);
|
||||
expect(
|
||||
find.textContaining("Polar learns the instance's address"),
|
||||
findsWidgets,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('Health Connect (ADR 0030, D31)', () {
|
||||
|
|
|
|||
Loading…
Reference in a new issue