Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,8 @@ class _AutoScorerSettingsPageState
// improve detection). Off by default — we never silently store photos.
SwitchListTile(
secondary: const Icon(Icons.fiber_manual_record_outlined),
title: const Text('Record for debugging & training'),
subtitle: const Text(
'Store board photos and the detection stream so scoring bugs '
'can be replayed off-device and the model improved. Stays on '
'this device until you export.'),
title: Text(l10n.autoScorerRecordTitle),
subtitle: Text(l10n.autoScorerRecordSubtitle),
value: recordingOn,
onChanged: recordingBusy ? null : _setRecording,
),
Expand All @@ -119,14 +116,17 @@ class _AutoScorerSettingsPageState
// and only enabled — while data collection is on.
ListTile(
leading: const Icon(Icons.filter_alt_outlined),
title: const Text('What to capture'),
title: Text(l10n.autoScorerCaptureModeTitle),
subtitle: Padding(
padding: const EdgeInsets.only(top: 8),
child: SegmentedButton<CaptureMode>(
segments: const [
ButtonSegment(value: CaptureMode.all, label: Text('All')),
segments: [
ButtonSegment(
value: CaptureMode.partial, label: Text('Mistakes only')),
value: CaptureMode.all,
label: Text(l10n.autoScorerCaptureModeAll)),
ButtonSegment(
value: CaptureMode.partial,
label: Text(l10n.autoScorerCaptureModeMistakes)),
],
selected: {captureMode.value ?? CaptureMode.partial},
onSelectionChanged: (!collectOn || captureMode.isLoading)
Expand All @@ -139,7 +139,7 @@ class _AutoScorerSettingsPageState
),
ListTile(
leading: const Icon(Icons.ios_share),
title: const Text('Export recordings'),
title: Text(l10n.autoScorerExportTitle),
subtitle: _exporting
? Padding(
padding: const EdgeInsets.only(top: 8),
Expand All @@ -148,47 +148,42 @@ class _AutoScorerSettingsPageState
children: [
LinearProgressIndicator(value: _exportProgress),
const SizedBox(height: 4),
Text(
'Building zip… ${StatFormatter.fmtPct(_exportProgress, decimals: 0)}'),
Text(l10n.autoScorerExportProgress(
StatFormatter.fmtPct(_exportProgress,
decimals: 0))),
],
),
)
: const Text(
'Share one zip of captured frames and recorded sessions.'),
: Text(l10n.autoScorerExportSubtitle),
onTap: _exporting ? null : () => _export(context),
),
const Divider(),
// Detection thresholds (#377 §3). The model's recall is measured at a
// near-zero eval threshold, so a lower operating threshold recovers
// borderline cal points / darts; expose both so they can be tuned
// against the calibration overlay's per-cal confidence readout.
const Padding(
padding: EdgeInsets.fromLTRB(16, 8, 16, 0),
child: Text('Detection thresholds',
style: TextStyle(fontWeight: FontWeight.bold)),
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
child: Text(l10n.autoScorerThresholdsTitle,
style: const TextStyle(fontWeight: FontWeight.bold)),
),
// Plain-language help (#686 4a): orient a non-expert before they touch
// the sliders, framed as the recall/false-positive trade-off.
const Padding(
padding: EdgeInsets.fromLTRB(16, 4, 16, 8),
child: Text(
'How sure the camera must be before it counts a detection. '
'Lower = catches more darts/calibration points but risks false '
'hits; higher = only confident detections but may miss some. '
'Leave at the default unless detection is consistently missing '
'or over-counting.'),
Padding(
padding: const EdgeInsets.fromLTRB(16, 4, 16, 8),
child: Text(l10n.autoScorerThresholdsHelp),
),
_ConfidenceSlider(
icon: Icons.crop_free,
label: 'Calibration confidence',
label: l10n.autoScorerCalConfidenceLabel,
value: calConf.value ?? kDefaultConfidence,
enabled: !calConf.isLoading,
onChanged: (v) =>
ref.read(autoScorerCalConfidenceProvider.notifier).set(v),
),
_ConfidenceSlider(
icon: Icons.my_location,
label: 'Dart confidence',
label: l10n.autoScorerDartConfidenceLabel,
value: dartConf.value ?? kDefaultConfidence,
enabled: !dartConf.isLoading,
onChanged: (v) =>
Expand All @@ -206,10 +201,11 @@ class _AutoScorerSettingsPageState
/// both stores.
Future<void> _export(BuildContext context) async {
final messenger = ScaffoldMessenger.of(context);
final l10n = AppLocalizations.of(context);
final store = await ref.read(captureStoreProvider.future);
if (!store.isSupported) {
messenger.showSnackBar(
const SnackBar(content: Text('Export is not available here.')));
SnackBar(content: Text(l10n.autoScorerExportUnavailable)));
return;
}
final captures = await store.list();
Expand Down Expand Up @@ -238,7 +234,7 @@ class _AutoScorerSettingsPageState

if (captures.isEmpty && sessionFiles.isEmpty) {
messenger.showSnackBar(
const SnackBar(content: Text('Nothing to export yet.')));
SnackBar(content: Text(l10n.autoScorerExportNothing)));
return;
}
final frameCount = captures.length;
Expand All @@ -259,7 +255,7 @@ class _AutoScorerSettingsPageState
// letting it crash to a red screen — #468 wants the export to fail
// gracefully with a message — and don't share a partial/missing zip.
messenger.showSnackBar(
const SnackBar(content: Text('Export failed. Please try again.')));
SnackBar(content: Text(l10n.autoScorerExportFailed)));
return;
} finally {
if (mounted) setState(() => _exporting = false);
Expand All @@ -273,26 +269,23 @@ class _AutoScorerSettingsPageState
final clear = await showDialog<bool>(
context: context,
builder: (dialogContext) => AlertDialog(
title: const Text('Clear exported data?'),
content: Text(
'Exported $frameCount frame${frameCount == 1 ? '' : 's'} and '
'$sessionCount session${sessionCount == 1 ? '' : 's'}. Clear them '
'from this device so they are not exported again?'),
title: Text(l10n.autoScorerClearTitle),
content: Text(l10n.autoScorerClearBody(frameCount, sessionCount)),
actions: [
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(false),
child: const Text('Keep')),
child: Text(l10n.autoScorerClearKeep)),
FilledButton(
onPressed: () => Navigator.of(dialogContext).pop(true),
child: const Text('Clear')),
child: Text(l10n.autoScorerClearConfirm)),
],
),
);
if (clear == true) {
await store.clear();
if (sessionStore.isSupported) await sessionStore.clear();
messenger.showSnackBar(
const SnackBar(content: Text('Cleared exported recordings')));
SnackBar(content: Text(l10n.autoScorerClearedToast)));
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions lib/l10n/arb/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,26 @@
"autoScorerUseSubtitle": "Kameragestützte Dart-Eingabe bei X01 und Cricket (beta).",
"autoScorerAutoAdvanceTitle": "Aufnahme automatisch weitergeben, wenn das Board frei ist",
"autoScorerAutoAdvanceSubtitle": "Wenn alle Darts entfernt sind, wird automatisch zum nächsten Spieler gewechselt, statt NEXT zu drücken.",
"autoScorerRecordTitle": "Für Debugging & Training aufzeichnen",
"autoScorerRecordSubtitle": "Speichert Board-Fotos und den Erkennungsstream, damit Scoring-Fehler außerhalb des Geräts erneut abgespielt und das Modell verbessert werden können. Bleibt auf diesem Gerät, bis du exportierst.",
"autoScorerCaptureModeTitle": "Was aufnehmen",
"autoScorerCaptureModeAll": "Alle",
"autoScorerCaptureModeMistakes": "Nur Fehler",
"autoScorerExportTitle": "Aufzeichnungen exportieren",
"autoScorerExportSubtitle": "Teile ein einzelnes ZIP mit den erfassten Frames und aufgezeichneten Sitzungen.",
"autoScorerExportProgress": "ZIP wird erstellt… {pct}",
"autoScorerThresholdsTitle": "Erkennungsschwellen",
"autoScorerThresholdsHelp": "Wie sicher die Kamera sein muss, bevor sie eine Erkennung zählt. Niedriger = erfasst mehr Darts/Kalibrierungspunkte, riskiert aber Fehltreffer; höher = nur sichere Erkennungen, verpasst aber möglicherweise einige. Belasse den Standardwert, außer die Erkennung fehlt oder zählt dauerhaft zu viel.",
"autoScorerCalConfidenceLabel": "Kalibrierungs-Konfidenz",
"autoScorerDartConfidenceLabel": "Dart-Konfidenz",
"autoScorerExportUnavailable": "Export ist hier nicht verfügbar.",
"autoScorerExportNothing": "Noch nichts zum Exportieren.",
"autoScorerExportFailed": "Export fehlgeschlagen. Bitte versuche es erneut.",
"autoScorerClearTitle": "Exportierte Daten löschen?",
"autoScorerClearBody": "{frameCount, plural, one{1 Frame} other{{frameCount} Frames}} und {sessionCount, plural, one{1 Sitzung} other{{sessionCount} Sitzungen}} exportiert. Vom Gerät löschen, damit sie nicht erneut exportiert werden?",
"autoScorerClearKeep": "Behalten",
"autoScorerClearConfirm": "Löschen",
"autoScorerClearedToast": "Exportierte Aufzeichnungen gelöscht",
"autoScorerSetupTipsTile": "Tipps zur Kameraeinrichtung",
"autoScorerSetupTipsTileSubtitle": "So rahmst du das Board für beste Ergebnisse ein.",
"autoScorerTip1Title": "Fülle den Rahmen",
Expand Down
93 changes: 93 additions & 0 deletions lib/l10n/arb/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,99 @@
"@autoScorerAutoAdvanceSubtitle": {
"description": "Subtitle for the auto-advance toggle"
},
"autoScorerRecordTitle": "Record for debugging & training",
"@autoScorerRecordTitle": {
"description": "Toggle: record board photos + detection stream for debugging and model training"
},
"autoScorerRecordSubtitle": "Store board photos and the detection stream so scoring bugs can be replayed off-device and the model improved. Stays on this device until you export.",
"@autoScorerRecordSubtitle": {
"description": "Subtitle for the record-for-debugging toggle"
},
"autoScorerCaptureModeTitle": "What to capture",
"@autoScorerCaptureModeTitle": {
"description": "Label for the capture-mode selector (which frames to store)"
},
"autoScorerCaptureModeAll": "All",
"@autoScorerCaptureModeAll": {
"description": "Capture-mode option: store every detected dart frame"
},
"autoScorerCaptureModeMistakes": "Mistakes only",
"@autoScorerCaptureModeMistakes": {
"description": "Capture-mode option: store only frames the user corrects"
},
"autoScorerExportTitle": "Export recordings",
"@autoScorerExportTitle": {
"description": "Tile: export captured frames and recorded sessions as a zip"
},
"autoScorerExportSubtitle": "Share one zip of captured frames and recorded sessions.",
"@autoScorerExportSubtitle": {
"description": "Subtitle for the export tile"
},
"autoScorerExportProgress": "Building zip… {pct}",
"@autoScorerExportProgress": {
"description": "Inline progress on the export tile while the zip is being built; pct is an already-formatted percentage",
"placeholders": {
"pct": {
"type": "String"
}
}
},
"autoScorerThresholdsTitle": "Detection thresholds",
"@autoScorerThresholdsTitle": {
"description": "Section header for the detection-confidence sliders"
},
"autoScorerThresholdsHelp": "How sure the camera must be before it counts a detection. Lower = catches more darts/calibration points but risks false hits; higher = only confident detections but may miss some. Leave at the default unless detection is consistently missing or over-counting.",
"@autoScorerThresholdsHelp": {
"description": "Plain-language help under the detection-thresholds header"
},
"autoScorerCalConfidenceLabel": "Calibration confidence",
"@autoScorerCalConfidenceLabel": {
"description": "Slider label: calibration-point detection confidence threshold"
},
"autoScorerDartConfidenceLabel": "Dart confidence",
"@autoScorerDartConfidenceLabel": {
"description": "Slider label: dart detection confidence threshold"
},
"autoScorerExportUnavailable": "Export is not available here.",
"@autoScorerExportUnavailable": {
"description": "Snackbar: export not supported on this platform"
},
"autoScorerExportNothing": "Nothing to export yet.",
"@autoScorerExportNothing": {
"description": "Snackbar: no captured frames or sessions to export"
},
"autoScorerExportFailed": "Export failed. Please try again.",
"@autoScorerExportFailed": {
"description": "Snackbar: the export zip could not be written"
},
"autoScorerClearTitle": "Clear exported data?",
"@autoScorerClearTitle": {
"description": "Dialog title: offer to clear data after a successful export"
},
"autoScorerClearBody": "Exported {frameCount, plural, one{1 frame} other{{frameCount} frames}} and {sessionCount, plural, one{1 session} other{{sessionCount} sessions}}. Clear them from this device so they are not exported again?",
"@autoScorerClearBody": {
"description": "Dialog body after export: how many frames/sessions were exported, offering to clear them",
"placeholders": {
"frameCount": {
"type": "int"
},
"sessionCount": {
"type": "int"
}
}
},
"autoScorerClearKeep": "Keep",
"@autoScorerClearKeep": {
"description": "Dialog action: keep exported data on device"
},
"autoScorerClearConfirm": "Clear",
"@autoScorerClearConfirm": {
"description": "Dialog action: clear exported data from device"
},
"autoScorerClearedToast": "Cleared exported recordings",
"@autoScorerClearedToast": {
"description": "Snackbar: exported recordings were cleared from the device"
},
"autoScorerSetupTipsTile": "Camera setup tips",
"@autoScorerSetupTipsTile": {
"description": "Tile/title: camera setup tips"
Expand Down
20 changes: 20 additions & 0 deletions lib/l10n/arb/app_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,26 @@
"autoScorerUseSubtitle": "Entrada de dardos asistida por cámara en X01 y Cricket (beta).",
"autoScorerAutoAdvanceTitle": "Avanzar el turno automáticamente al despejar la diana",
"autoScorerAutoAdvanceSubtitle": "Cuando se retiran todos los dardos, pasa al siguiente jugador automáticamente en vez de pulsar NEXT.",
"autoScorerRecordTitle": "Grabar para depuración y entrenamiento",
"autoScorerRecordSubtitle": "Almacena fotos de la diana y el flujo de detección para que los errores de puntuación puedan reproducirse fuera del dispositivo y mejorar el modelo. Permanece en este dispositivo hasta que exportes.",
"autoScorerCaptureModeTitle": "Qué capturar",
"autoScorerCaptureModeAll": "Todo",
"autoScorerCaptureModeMistakes": "Solo errores",
"autoScorerExportTitle": "Exportar grabaciones",
"autoScorerExportSubtitle": "Comparte un único zip con los fotogramas capturados y las sesiones grabadas.",
"autoScorerExportProgress": "Creando zip… {pct}",
"autoScorerThresholdsTitle": "Umbrales de detección",
"autoScorerThresholdsHelp": "Cuánta seguridad necesita la cámara antes de contar una detección. Más bajo = detecta más dardos/puntos de calibración pero arriesga falsos positivos; más alto = solo detecciones fiables pero puede perder algunas. Deja el valor predeterminado salvo que la detección falle o cuente de más de forma constante.",
"autoScorerCalConfidenceLabel": "Confianza de calibración",
"autoScorerDartConfidenceLabel": "Confianza de dardos",
"autoScorerExportUnavailable": "La exportación no está disponible aquí.",
"autoScorerExportNothing": "Aún no hay nada que exportar.",
"autoScorerExportFailed": "La exportación falló. Inténtalo de nuevo.",
"autoScorerClearTitle": "¿Borrar los datos exportados?",
"autoScorerClearBody": "Exportados {frameCount, plural, one{1 fotograma} other{{frameCount} fotogramas}} y {sessionCount, plural, one{1 sesión} other{{sessionCount} sesiones}}. ¿Borrarlos de este dispositivo para que no se exporten de nuevo?",
"autoScorerClearKeep": "Conservar",
"autoScorerClearConfirm": "Borrar",
"autoScorerClearedToast": "Grabaciones exportadas borradas",
"autoScorerSetupTipsTile": "Consejos para configurar la cámara",
"autoScorerSetupTipsTileSubtitle": "Cómo encuadrar la diana para obtener mejores resultados.",
"autoScorerTip1Title": "Llena el encuadre",
Expand Down
20 changes: 20 additions & 0 deletions lib/l10n/arb/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,26 @@
"autoScorerUseSubtitle": "Saisie des fléchettes assistée par caméra sur X01 et Cricket (beta).",
"autoScorerAutoAdvanceTitle": "Passer la volée automatiquement quand la cible est dégagée",
"autoScorerAutoAdvanceSubtitle": "Quand toutes les fléchettes sont retirées, passe au joueur suivant automatiquement au lieu d'appuyer sur NEXT.",
"autoScorerRecordTitle": "Enregistrer pour le débogage et l'entraînement",
"autoScorerRecordSubtitle": "Stocke des photos de la cible et le flux de détection afin que les erreurs de score puissent être rejouées hors de l'appareil et que le modèle soit amélioré. Reste sur cet appareil jusqu'à l'export.",
"autoScorerCaptureModeTitle": "Que capturer",
"autoScorerCaptureModeAll": "Tout",
"autoScorerCaptureModeMistakes": "Erreurs uniquement",
"autoScorerExportTitle": "Exporter les enregistrements",
"autoScorerExportSubtitle": "Partager un seul zip des images capturées et des sessions enregistrées.",
"autoScorerExportProgress": "Création du zip… {pct}",
"autoScorerThresholdsTitle": "Seuils de détection",
"autoScorerThresholdsHelp": "À quel point la caméra doit être sûre avant de compter une détection. Plus bas = détecte plus de fléchettes/points de calibration mais risque des faux positifs ; plus haut = uniquement les détections fiables mais peut en manquer. Laissez la valeur par défaut sauf si la détection manque ou surcompte systématiquement.",
"autoScorerCalConfidenceLabel": "Confiance de calibration",
"autoScorerDartConfidenceLabel": "Confiance des fléchettes",
"autoScorerExportUnavailable": "L'export n'est pas disponible ici.",
"autoScorerExportNothing": "Rien à exporter pour l'instant.",
"autoScorerExportFailed": "Échec de l'export. Veuillez réessayer.",
"autoScorerClearTitle": "Effacer les données exportées ?",
"autoScorerClearBody": "{frameCount, plural, one{1 image} other{{frameCount} images}} et {sessionCount, plural, one{1 session} other{{sessionCount} sessions}} exportées. Les effacer de cet appareil afin qu'elles ne soient pas exportées à nouveau ?",
"autoScorerClearKeep": "Conserver",
"autoScorerClearConfirm": "Effacer",
"autoScorerClearedToast": "Enregistrements exportés effacés",
"autoScorerSetupTipsTile": "Conseils de placement de la caméra",
"autoScorerSetupTipsTileSubtitle": "Comment cadrer la cible pour de meilleurs résultats.",
"autoScorerTip1Title": "Remplissez le cadre",
Expand Down
Loading