feat(watch): clôture lot #91 - fréquence cardiaque live, notifications de séance et finitions montre

Consolide le lot applicatif watch companion validé :
- télémétrie fréquence cardiaque live remontée montre -> téléphone
  (collecteur watch, adapter Wear Data Layer, persistance Drift,
  propagation aux écrans historique/programme/profil/exécution)
- notifications de séance en arrière-plan côté téléphone (service
  foreground de statut + passerelle applicative)
- finitions montre : chrono d'étape, score d'étape, retrait du bouton
  "lancer une séance", thème, icônes et polices watch_app

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 05:56:12 +02:00
parent c65a5a76a9
commit 65d43b9768
80 changed files with 12292 additions and 892 deletions

View File

@ -0,0 +1,76 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:gametime/application/application.dart';
import 'package:gametime/infrastructure/remote/remote.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
void main() {
test(
'defaultBaseUrl keeps localhost outside Android without env override',
() {
expect(
HttpApiClient.defaultBaseUrlFor(isAndroid: false),
'http://localhost:8080',
);
},
);
test('defaultBaseUrl uses Android emulator host without env override', () {
expect(
HttpApiClient.defaultBaseUrlFor(isAndroid: true),
'http://10.0.2.2:8080',
);
});
test('defaultBaseUrl keeps env override on Android', () {
expect(
HttpApiClient.defaultBaseUrlFor(
isAndroid: true,
configuredBaseUrl: ' http://192.168.1.42:8080 ',
),
'http://192.168.1.42:8080',
);
});
test('postJson maps server errors to server failure', () async {
final client = HttpApiClient(
baseUrl: Uri.parse('http://api.example.test'),
client: MockClient(
(_) async => http.Response('{"error":"internal"}', 500),
),
);
await expectLater(
client.postJson('/auth/login'),
throwsA(
isA<RemoteAuthException>()
.having(
(error) => error.failure,
'failure',
RemoteAuthFailure.server,
)
.having((error) => error.message, 'message', 'internal'),
),
);
});
test('postJson maps transport failures to network failure', () async {
final client = HttpApiClient(
baseUrl: Uri.parse('http://api.example.test'),
client: MockClient((_) async => throw http.ClientException('refused')),
);
await expectLater(
client.postJson('/auth/login'),
throwsA(
isA<RemoteAuthException>()
.having(
(error) => error.failure,
'failure',
RemoteAuthFailure.network,
)
.having((error) => error.message, 'message', 'refused'),
),
);
});
}