fix(watch): finalise correctif sync workoutHistory/exercise et distance live montre (#157)

This commit is contained in:
2026-07-29 11:22:17 +02:00
parent 6f913e4e8d
commit 30c6259748
28 changed files with 1658 additions and 248 deletions

View File

@ -99,7 +99,11 @@ final class _WatchSessionScreenState extends State<WatchSessionScreen> {
),
);
}
return PageView(controller: _pageController, children: pages);
return PageView(
controller: _pageController,
physics: const _WatchPageScrollPhysics(),
children: pages,
);
},
);
}
@ -220,7 +224,21 @@ final class _WatchSessionScreenState extends State<WatchSessionScreen> {
!_completionHapticTimerKeys.add(key)) {
return;
}
_triggerTimerCompletionHaptic();
}
void _triggerTimerCompletionHaptic() {
unawaited(HapticFeedback.heavyImpact());
unawaited(
Future<void>.delayed(const Duration(milliseconds: 140), () {
return HapticFeedback.heavyImpact();
}),
);
unawaited(
Future<void>.delayed(const Duration(milliseconds: 320), () {
return HapticFeedback.heavyImpact();
}),
);
}
Future<bool> _confirm({
@ -242,6 +260,47 @@ final class _WatchSessionScreenState extends State<WatchSessionScreen> {
}
}
final class _WatchPageScrollPhysics extends PageScrollPhysics {
const _WatchPageScrollPhysics({super.parent});
@override
_WatchPageScrollPhysics applyTo(ScrollPhysics? ancestor) {
return _WatchPageScrollPhysics(parent: buildParent(ancestor));
}
@override
Simulation? createBallisticSimulation(
ScrollMetrics position,
double velocity,
) {
if ((velocity <= 0.0 && position.pixels <= position.minScrollExtent) ||
(velocity >= 0.0 && position.pixels >= position.maxScrollExtent)) {
return super.createBallisticSimulation(position, velocity);
}
final viewport = position is PageMetrics
? position.viewportDimension * position.viewportFraction
: position.viewportDimension;
if (viewport <= 0) {
return null;
}
final target = (position.pixels / viewport).roundToDouble() * viewport;
final clampedTarget = target.clamp(
position.minScrollExtent,
position.maxScrollExtent,
);
if (clampedTarget == position.pixels) {
return null;
}
return ScrollSpringSimulation(
spring,
position.pixels,
clampedTarget,
velocity,
tolerance: toleranceFor(position),
);
}
}
final class _RoundScaffold extends StatelessWidget {
const _RoundScaffold({required this.child, this.notice, super.key});
@ -927,17 +986,21 @@ final class _ManualScoreContent extends StatelessWidget {
);
final target = projection.manualScoreTargetValue;
final targetLabel = projection.manualScoreTargetLabel;
final captionSegments = [
if (projection.manualScoreRepsTargetValue != null)
'Répétitions : ${projection.manualScoreRepsTargetValue}',
if (target != null && targetLabel != null && targetLabel.isNotEmpty)
'$targetLabel : ${_scoreText(target)}',
];
return _ScaledContent(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_ExerciseName(projection.exerciseName),
_StepNameBand(projection.stepName),
if (target != null &&
targetLabel != null &&
targetLabel.isNotEmpty) ...[
if (captionSegments.isNotEmpty) ...[
Text(
'$targetLabel : ${_scoreText(target)}',
captionSegments.join(' · '),
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,