Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
# Dart file in the repo, which is a working-tree-wide change with nothing to do
# with reviewable diffs.
*.dart diff

# generated by tool/update_wger_exercises.dart
lib/ui2/activity/wger_exercises.g.dart linguist-generated=true
11 changes: 11 additions & 0 deletions NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,14 @@ in this repository. The Bluetooth protocol support in this project was
independently developed by observing the band's own Bluetooth communications;
see [the protocol repo's README](https://github.com/OpenStrap/protocol) for
methodology notes.

## wger exercise data

`lib/ui2/activity/wger_exercises.g.dart` contains selected fields (names,
aliases, muscles, equipment, categories) from the [wger](https://wger.de)
exercise database, limited to the movements listed in
`tool/wger_weightlifting_selection.dart`. Each entry is available under
CC BY-SA 3.0, CC BY-SA 4.0 or CC0, and each row keeps its source UUID and the
author/license credits of its base data and translations. This data stays under
those licenses, separate from the MIT-licensed code. Refresh with
`dart run tool/update_wger_exercises.dart`.
12 changes: 12 additions & 0 deletions docs/notice.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ <h2>Open Food Facts</h2>
purposes. Edge treats a scanned figure as something you entered, never as
something it measured, and drops any value that fails a basic
plausibility check rather than showing it to you.</p>

<h2 id="wger-exercise-data">wger exercise data</h2>

<p>The exercise picker includes selected fields (names, aliases, muscles,
equipment, categories) from the <a href="https://wger.de">wger</a>
exercise database. Each entry is available under
<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA 3.0</a>,
<a href="https://creativecommons.org/licenses/by-sa/4.0/">CC BY-SA 4.0</a>
or <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>,
and stays under that license, separate from Edge's MIT-licensed code. The
info button next to each exercise opens its wger record with authors and
license.</p>
</main>

<footer class="site">
Expand Down
40 changes: 39 additions & 1 deletion lib/data/db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4071,7 +4071,7 @@ class LocalDb {
/// which the UI states in as many words.
///
/// Derived on read, never stored: total volume, set/rep counts, 1RM
/// estimates, per-muscle volume, "vs last session", PR detection.
/// estimates, "vs last session", PR detection.
static Future<void> _createStrengthTables(Database db) async {
await db.execute('''
CREATE TABLE IF NOT EXISTS strength_set (
Expand Down Expand Up @@ -4154,6 +4154,44 @@ class LocalDb {
);
}

/// Newest-set and heaviest-set candidates per logged exercise, in two
/// queries. The caller keeps the first row per key (most reps wins a tie).
/// No window functions: minSdk 26 can ship SQLite older than 3.25.
static Future<({
List<Map<String, Object?>> previous,
List<Map<String, Object?>> best,
})> strengthHistoryCandidates() async {
final db = await instance;
final previous = await db.rawQuery('''
SELECT s.*
FROM strength_set s
JOIN (
SELECT exercise_key, MAX(COALESCE(at_ts, 0)) AS newest_at
FROM strength_set
GROUP BY exercise_key
) newest
ON newest.exercise_key = s.exercise_key
AND newest.newest_at = COALESCE(s.at_ts, 0)
ORDER BY s.exercise_key ASC, COALESCE(s.at_ts, 0) DESC,
s.session_id DESC, s.seq DESC
''');
final best = await db.rawQuery('''
SELECT s.*
FROM strength_set s
JOIN (
SELECT exercise_key, MAX(load_kg) AS best_load
FROM strength_set
WHERE load_kg IS NOT NULL
GROUP BY exercise_key
) heaviest
ON heaviest.exercise_key = s.exercise_key
AND heaviest.best_load = s.load_kg
ORDER BY s.exercise_key ASC, COALESCE(s.reps, 0) DESC,
COALESCE(s.at_ts, 0) DESC, s.session_id DESC, s.seq DESC
''');
return (previous: previous, best: best);
}

// ── USER-DATA STORE (journal / cycle / workouts / notifications) ────────────
// On-device user-entered + locally-generated data. All keyed for idempotent
// upserts; none of it round-trips to a server (cloud excised).
Expand Down
12 changes: 12 additions & 0 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2000,8 +2000,20 @@
"activitySummaryTabOverview": "Übersicht",
"activitySummaryTabSplits": "Zwischenzeiten",
"activitySummaryTabGraphs": "Grafiken",
"activityExercisePickerChooseTitle": "Übung auswählen",
"activityExercisePickerChangeTitle": "Übung wechseln",
"activityExercisePickerSearchLabel": "Übungen suchen",
"activityExercisePickerSearchHint": "{count} Übungen durchsuchen",
"activityExercisePickerCommonFilter": "Häufig",
"activityExercisePickerAllFilter": "Alle",
"activityExercisePickerNoMatch": "Keine passenden Übungen",
"activityExercisePickerWgerCredit": "Übungskatalog von wger",
"activityExercisePickerSourceLabel": "Quelle und Lizenzen für {exercise} ansehen",
"activityLiveAddALap": "Bahn hinzufügen",
"activityLiveAddExerciseTitle": "Übung hinzufügen",
"activityLiveChooseExerciseBody": "Wähle die erste Übung aus, bevor du einen Satz erfasst.",
"activityLiveChangeExercise": "Übung wechseln",
"activityExerciseCategory": "{category, select, Abs{Bauch} Arms{Arme} Back{Rücken} Calves{Waden} Chest{Brust} Legs{Beine} Shoulders{Schultern} other{{category}}}",
"activityLiveAllowLocation": "Standort erlauben",
"activityLiveBestLabel": "Bestwert",
"activityLiveBodyweightExcludedNote": "Körpergewicht — nicht im Volumen enthalten",
Expand Down
63 changes: 63 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -10463,6 +10463,52 @@
"@activitySummaryTabGraphs": {
"description": "Sub-tab label for the Graphs tab on the activity summary screen"
},
"activityExercisePickerChooseTitle": "Choose exercise",
"@activityExercisePickerChooseTitle": {
"description": "Title of the strength exercise picker when selecting a new exercise."
},
"activityExercisePickerChangeTitle": "Change exercise",
"@activityExercisePickerChangeTitle": {
"description": "Title of the strength exercise picker when replacing or switching from the current exercise."
},
"activityExercisePickerSearchLabel": "Search exercises",
"@activityExercisePickerSearchLabel": {
"description": "Accessibility label for the strength exercise search field."
},
"activityExercisePickerSearchHint": "Search {count} exercises",
"@activityExercisePickerSearchHint": {
"description": "Placeholder in the strength exercise search field.",
"placeholders": {
"count": {
"type": "int"
}
}
},
"activityExercisePickerCommonFilter": "Common",
"@activityExercisePickerCommonFilter": {
"description": "Filter showing Edge's short common-exercise list."
},
"activityExercisePickerAllFilter": "All",
"@activityExercisePickerAllFilter": {
"description": "Filter showing the whole strength exercise catalogue."
},
"activityExercisePickerNoMatch": "No exercises match that",
"@activityExercisePickerNoMatch": {
"description": "Empty result shown for an exercise search or category filter."
},
"activityExercisePickerWgerCredit": "Exercise catalogue from wger",
"@activityExercisePickerWgerCredit": {
"description": "Attribution under the strength exercise picker."
},
"activityExercisePickerSourceLabel": "View source and credits for {exercise}",
"@activityExercisePickerSourceLabel": {
"description": "Accessibility label and tooltip for a wger exercise's exact source record.",
"placeholders": {
"exercise": {
"type": "String"
}
}
},
"activityLiveAddALap": "Add a lap",
"@activityLiveAddALap": {
"description": "Live swim screen: accessibility label for the tap-a-lap button."
Expand All @@ -10471,6 +10517,23 @@
"@activityLiveAddExerciseTitle": {
"description": "Live strength screen: title of the sheet for adding another exercise."
},
"activityLiveChooseExerciseBody": "Pick the first exercise before logging a set.",
"@activityLiveChooseExerciseBody": {
"description": "Empty live-strength state before an exercise has been selected."
},
"activityLiveChangeExercise": "Change exercise",
"@activityLiveChangeExercise": {
"description": "Accessibility label for changing the current strength exercise."
},
"activityExerciseCategory": "{category, select, Abs{Abs} Arms{Arms} Back{Back} Calves{Calves} Chest{Chest} Legs{Legs} Shoulders{Shoulders} other{{category}}}",
"@activityExerciseCategory": {
"description": "Strength exercise category name, used as a picker filter and row detail.",
"placeholders": {
"category": {
"type": "String"
}
}
},
"activityLiveAllowLocation": "Allow location",
"@activityLiveAllowLocation": {
"description": "Live measured session: fix action when location permission was denied."
Expand Down
12 changes: 12 additions & 0 deletions lib/l10n/app_es.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2012,8 +2012,20 @@
"activitySummaryTabOverview": "Resumen",
"activitySummaryTabSplits": "Parciales",
"activitySummaryTabGraphs": "Gráficos",
"activityExercisePickerChooseTitle": "Elegir ejercicio",
"activityExercisePickerChangeTitle": "Cambiar ejercicio",
"activityExercisePickerSearchLabel": "Buscar ejercicios",
"activityExercisePickerSearchHint": "Buscar entre {count} ejercicios",
"activityExercisePickerCommonFilter": "Comunes",
"activityExercisePickerAllFilter": "Todos",
"activityExercisePickerNoMatch": "No hay ejercicios coincidentes",
"activityExercisePickerWgerCredit": "Catálogo de ejercicios de wger",
"activityExercisePickerSourceLabel": "Ver la fuente y las licencias de {exercise}",
"activityLiveAddALap": "Añadir un largo",
"activityLiveAddExerciseTitle": "Añadir ejercicio",
"activityLiveChooseExerciseBody": "Elige el primer ejercicio antes de registrar una serie.",
"activityLiveChangeExercise": "Cambiar ejercicio",
"activityExerciseCategory": "{category, select, Abs{Abdominales} Arms{Brazos} Back{Espalda} Calves{Pantorrillas} Chest{Pecho} Legs{Piernas} Shoulders{Hombros} other{{category}}}",
"activityLiveAllowLocation": "Permitir ubicación",
"activityLiveBestLabel": "Mejor",
"activityLiveBodyweightExcludedNote": "Peso corporal — excluido del volumen",
Expand Down
12 changes: 12 additions & 0 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2000,8 +2000,20 @@
"activitySummaryTabOverview": "Aperçu",
"activitySummaryTabSplits": "Temps intermédiaires",
"activitySummaryTabGraphs": "Graphiques",
"activityExercisePickerChooseTitle": "Choisir un exercice",
"activityExercisePickerChangeTitle": "Changer d’exercice",
"activityExercisePickerSearchLabel": "Rechercher des exercices",
"activityExercisePickerSearchHint": "Rechercher parmi {count} exercices",
"activityExercisePickerCommonFilter": "Courants",
"activityExercisePickerAllFilter": "Tous",
"activityExercisePickerNoMatch": "Aucun exercice correspondant",
"activityExercisePickerWgerCredit": "Catalogue d’exercices de wger",
"activityExercisePickerSourceLabel": "Voir la source et les licences de {exercise}",
"activityLiveAddALap": "Ajouter une longueur",
"activityLiveAddExerciseTitle": "Ajouter un exercice",
"activityLiveChooseExerciseBody": "Choisissez le premier exercice avant d’enregistrer une série.",
"activityLiveChangeExercise": "Changer d’exercice",
"activityExerciseCategory": "{category, select, Abs{Abdos} Arms{Bras} Back{Dos} Calves{Mollets} Chest{Pectoraux} Legs{Jambes} Shoulders{Épaules} other{{category}}}",
"activityLiveAllowLocation": "Autoriser la localisation",
"activityLiveBestLabel": "Meilleur",
"activityLiveBodyweightExcludedNote": "Poids du corps — exclu du volume",
Expand Down
12 changes: 12 additions & 0 deletions lib/l10n/app_hi.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2000,8 +2000,20 @@
"activitySummaryTabOverview": "अवलोकन",
"activitySummaryTabSplits": "स्प्लिट",
"activitySummaryTabGraphs": "ग्राफ़",
"activityExercisePickerChooseTitle": "व्यायाम चुनें",
"activityExercisePickerChangeTitle": "व्यायाम बदलें",
"activityExercisePickerSearchLabel": "व्यायाम खोजें",
"activityExercisePickerSearchHint": "{count} व्यायाम खोजें",
"activityExercisePickerCommonFilter": "सामान्य",
"activityExercisePickerAllFilter": "सभी",
"activityExercisePickerNoMatch": "कोई मेल खाता व्यायाम नहीं",
"activityExercisePickerWgerCredit": "wger का व्यायाम कैटलॉग",
"activityExercisePickerSourceLabel": "{exercise} का स्रोत और लाइसेंस देखें",
"activityLiveAddALap": "एक चक्कर जोड़ें",
"activityLiveAddExerciseTitle": "व्यायाम जोड़ें",
"activityLiveChooseExerciseBody": "सेट दर्ज करने से पहले पहला व्यायाम चुनें।",
"activityLiveChangeExercise": "व्यायाम बदलें",
"activityExerciseCategory": "{category, select, Abs{पेट} Arms{बाहें} Back{पीठ} Calves{पिंडलियाँ} Chest{छाती} Legs{पैर} Shoulders{कंधे} other{{category}}}",
"activityLiveAllowLocation": "लोकेशन की अनुमति दें",
"activityLiveBestLabel": "सर्वश्रेष्ठ",
"activityLiveBodyweightExcludedNote": "बॉडीवेट — वॉल्यूम में शामिल नहीं",
Expand Down
12 changes: 12 additions & 0 deletions lib/l10n/app_zh.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2000,8 +2000,20 @@
"activitySummaryTabOverview": "概览",
"activitySummaryTabSplits": "分段",
"activitySummaryTabGraphs": "图表",
"activityExercisePickerChooseTitle": "选择动作",
"activityExercisePickerChangeTitle": "更换动作",
"activityExercisePickerSearchLabel": "搜索动作",
"activityExercisePickerSearchHint": "搜索 {count} 个动作",
"activityExercisePickerCommonFilter": "常用",
"activityExercisePickerAllFilter": "全部",
"activityExercisePickerNoMatch": "没有匹配的动作",
"activityExercisePickerWgerCredit": "动作目录来自 wger",
"activityExercisePickerSourceLabel": "查看 {exercise} 的来源和许可",
"activityLiveAddALap": "增加一趟",
"activityLiveAddExerciseTitle": "添加动作",
"activityLiveChooseExerciseBody": "记录一组前,请先选择第一个动作。",
"activityLiveChangeExercise": "更换动作",
"activityExerciseCategory": "{category, select, Abs{腹部} Arms{手臂} Back{背部} Calves{小腿} Chest{胸部} Legs{腿部} Shoulders{肩部} other{{category}}}",
"activityLiveAllowLocation": "允许定位",
"activityLiveBestLabel": "最佳",
"activityLiveBodyweightExcludedNote": "自重 — 不计入训练量",
Expand Down
Loading