fix(watch): corrige applicationId et nettoie la config de build montre

Répare la régression de packaging introduite par le reset/remerge de
develop : l'APK montre était packagée avec com.gametime.app au lieu de
com.gametime.watch (namespace correct mais applicationId hérité du
téléphone), ce qui cassait la détection du bridge. Aligne applicationId
sur com.gametime.watch, nettoie la config de signing partagée sur les
deux modules android/app et watch_app/android/app, et ajuste
use_cases + watch_session_screen en conséquence.

Validé : APK montre release package = com.gametime.watch, même SHA-256
de certificat sur les deux APKs (70cc69e8...45c7815), tests use_cases et
watch_session_screen OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 12:18:48 +02:00
parent 6e110a9fb9
commit 2e40694de4
6 changed files with 192 additions and 60 deletions

View File

@ -5647,41 +5647,68 @@ double _estimatedCaloriesKcal({
}
final class WorkoutHistoryUseCases {
const WorkoutHistoryUseCases({required this.repository, required this.clock});
WorkoutHistoryUseCases({required this.repository, required this.clock});
final WorkoutHistoryRepository repository;
final Clock clock;
final _pendingHeartRateSummaries = <String, WatchSensorSummary>{};
Future<WorkoutHistory?> findById(String id) => repository.findById(id);
Future<WorkoutHistory?> findById(String id) async {
final history = await repository.findById(id);
if (history == null) {
return null;
}
final changed = await _applyPendingHeartRateSummaries([history]);
return changed ? repository.findById(id) : history;
}
Future<List<WorkoutHistory>> listActive() => repository.listActive();
Future<List<WorkoutHistory>> listActive() async {
final histories = await repository.listActive();
final changed = await _applyPendingHeartRateSummaries(histories);
return changed ? repository.listActive() : histories;
}
Future<void> delete(String id) => repository.delete(id, clock.now());
Future<void> updateHeartRateSummary(WatchSensorSummary summary) async {
if (summary.sampleCount < 3 ||
summary.averageHeartRateBpm == null ||
summary.maxHeartRateBpm == null) {
return;
}
if (summary.sessionId.trim().isEmpty ||
summary.averageHeartRateBpm! <= 0 ||
summary.maxHeartRateBpm! <= 0) {
if (!_isUsableHeartRateSummary(summary)) {
return;
}
final sessionId = summary.sessionId.trim();
final histories = await repository.listActive();
WorkoutHistory? history;
for (final candidate in histories) {
if (candidate.metadata.id == summary.sessionId ||
candidate.sourceActiveWorkoutSessionId == summary.sessionId) {
history = candidate;
break;
final applied = await _applyHeartRateSummary(histories, summary);
if (applied) {
_pendingHeartRateSummaries.remove(sessionId);
return;
}
if (!_hasHistoryForSummary(histories, summary)) {
_pendingHeartRateSummaries.putIfAbsent(sessionId, () => summary);
}
}
Future<bool> _applyPendingHeartRateSummaries(
List<WorkoutHistory> histories,
) async {
var changed = false;
for (final summary in _pendingHeartRateSummaries.values.toList()) {
final applied = await _applyHeartRateSummary(histories, summary);
if (applied) {
_pendingHeartRateSummaries.remove(summary.sessionId.trim());
changed = true;
}
}
return changed;
}
Future<bool> _applyHeartRateSummary(
List<WorkoutHistory> histories,
WatchSensorSummary summary,
) async {
final history = _findHistoryForSummary(histories, summary);
if (history == null ||
history.averageHeartRateBpm != null ||
history.maxHeartRateBpm != null) {
return;
return false;
}
await repository.patchHeartRateSummary(
historyId: history.metadata.id,
@ -5689,6 +5716,37 @@ final class WorkoutHistoryUseCases {
maxHeartRateBpm: summary.maxHeartRateBpm!,
patchedAt: clock.now(),
);
return true;
}
bool _hasHistoryForSummary(
List<WorkoutHistory> histories,
WatchSensorSummary summary,
) {
return _findHistoryForSummary(histories, summary) != null;
}
WorkoutHistory? _findHistoryForSummary(
List<WorkoutHistory> histories,
WatchSensorSummary summary,
) {
final sessionId = summary.sessionId.trim();
for (final candidate in histories) {
if (candidate.metadata.id == sessionId ||
candidate.sourceActiveWorkoutSessionId == sessionId) {
return candidate;
}
}
return null;
}
bool _isUsableHeartRateSummary(WatchSensorSummary summary) {
return summary.sampleCount >= 3 &&
summary.sessionId.trim().isNotEmpty &&
summary.averageHeartRateBpm != null &&
summary.averageHeartRateBpm! > 0 &&
summary.maxHeartRateBpm != null &&
summary.maxHeartRateBpm! > 0;
}
}