feat(exécution): clarifie Durée et Temps réalisé, renomme Durée par défaut (s)

Sépare la notion de Durée (paramètre configuré) de Temps réalisé (résultat
mesuré au chronomètre), renomme le champ « Temps par défaut (s) » en
« Durée par défaut (s) » dans la bibliothèque d'exercices, et limite
l'exécution à un seul chrono visible à la fois. Le mode Score chrono est
conservé tel quel comme mode du score.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 09:37:44 +02:00
parent 6d86700348
commit e3c7ca0dab
11 changed files with 316 additions and 56 deletions

View File

@ -242,7 +242,7 @@ final class _WorkoutExecutionScreenState extends State<WorkoutExecutionScreen> {
),
),
],
if (_exercise.stopwatchScoreEnabled) ...[
if (_shouldShowScoreStopwatchInput) ...[
const SizedBox(height: 8),
SizedBox(
height: 96,
@ -265,7 +265,7 @@ final class _WorkoutExecutionScreenState extends State<WorkoutExecutionScreen> {
: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (_exercise.stopwatchScoreEnabled) ...[
if (_shouldShowScoreStopwatchInput) ...[
_ScoreStopwatchInput(
elapsedLabel: _formatScoreStopwatch(
Duration(milliseconds: _scoreStopwatchElapsedMs),
@ -501,6 +501,14 @@ final class _WorkoutExecutionScreenState extends State<WorkoutExecutionScreen> {
return hasGlobalTimer && !_hasSetExecutionStarted;
}
bool get _usesSetTimerForStopwatchScore {
return _exercise.timeEnabled && _exercise.stopwatchScoreEnabled;
}
bool get _shouldShowScoreStopwatchInput {
return _exercise.stopwatchScoreEnabled && !_usesSetTimerForStopwatchScore;
}
bool get _hasSetExecutionStarted {
if (_setTimer != null) {
return true;
@ -1248,18 +1256,19 @@ final class _WorkoutExecutionScreenState extends State<WorkoutExecutionScreen> {
if (!skipped &&
!finishWithoutChrono &&
_exercise.stopwatchScoreEnabled &&
!_usesSetTimerForStopwatchScore &&
_scoreStopwatch == null &&
_manualScoreTimeMs == null) {
final action = await showDialog<_MissingStopwatchAction>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Chrono non lancé'),
content: const Text("Tu nas pas démarré le chrono de cette série."),
title: const Text('Aucun temps chronométré'),
content: const Text('Tu nas pas démarré le chrono score.'),
actions: [
TextButton(
onPressed: () =>
Navigator.of(context).pop(_MissingStopwatchAction.start),
child: const Text('Démarrer'),
child: const Text('Démarrer le chrono'),
),
FilledButton(
onPressed: () => Navigator.of(
@ -1311,8 +1320,9 @@ final class _WorkoutExecutionScreenState extends State<WorkoutExecutionScreen> {
if (!skipped &&
_exercise.stopwatchScoreEnabled &&
actualScoreTimeMs == null) {
final state = _scoreStopwatch;
actualScoreTimeMs = state?.accumulatedMs;
actualScoreTimeMs = _usesSetTimerForStopwatchScore
? setTimer?.accumulatedMs
: _scoreStopwatch?.accumulatedMs;
}
await widget.activeUseCases.recordCurrentSetResult(
sessionId: _session.metadata.id,
@ -1747,7 +1757,7 @@ final class SetMeasureInput extends StatelessWidget {
padding: const EdgeInsets.all(24),
child: Column(
children: [
const Text('Temps'),
const Text('Durée'),
const SizedBox(height: 8),
Text(
exercise.targetTimeSeconds == null
@ -1902,8 +1912,8 @@ final class _ExecutionContextHeader extends StatelessWidget {
const SizedBox(height: 4),
Text(
setTimerComplete
? 'Temps de série terminé : $setTimerLabel'
: 'Temps de série : $setTimerLabel',
? 'Durée de série terminée : $setTimerLabel'
: 'Durée de série : $setTimerLabel',
style: theme.textTheme.labelLarge?.copyWith(
color: theme.colorScheme.primary,
),
@ -3568,7 +3578,9 @@ final class _EditSetResultSheetState extends State<_EditSetResultSheet> {
if (widget.exercise.timeEnabled) ...[
TextField(
controller: _timeController,
decoration: const InputDecoration(labelText: 'Temps réalisé (s)'),
decoration: const InputDecoration(
labelText: 'Durée réalisée (s)',
),
keyboardType: TextInputType.number,
),
const SizedBox(height: 12),
@ -3586,7 +3598,7 @@ final class _EditSetResultSheetState extends State<_EditSetResultSheet> {
controller: _scoreController,
decoration: InputDecoration(
labelText: widget.exercise.stopwatchScoreEnabled
? 'Temps réalisé (chrono score, s)'
? 'Temps réalisé (s)'
: widget.exercise.scoreUnit == null
? 'Score'
: 'Score (${widget.exercise.scoreUnit})',