diff --git a/AUTHORS.md b/AUTHORS.md index 57161720..bc73c98b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -16,6 +16,8 @@ - Nenza Nurfirmansyah - - Florian Schmitz - - Adam Bujdoš - +- Aman Negi - +- Sandi Milohanic - ## Translators @@ -58,3 +60,7 @@ - Bahasa Indonesia - Nenza Nurfirmansyah (73) + +- Croatian + + - Sandi Milohaic diff --git a/README.md b/README.md index bf569752..02d42047 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Install Flutter, and all its dependencies, and create a new virtual device: The app currently uses flutter 3.3 ### 3 -Create a new file ``wger.properties`` in ``android/fastlane/envfiles``: +Create a new file ``wger.properties`` in ``fastlane/metadata/envfiles/``: ```properties WGER_API_KEY=123456 diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/ca/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..98727fe6 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/ca/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..a709535a Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/ca/images/phoneScreenshots/03 - gym mode.png index a5499a34..77a32ae6 100644 Binary files a/fastlane/metadata/android/ca/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/ca/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/ca/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..9962dfcb Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/ca/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 13492691..00000000 Binary files a/fastlane/metadata/android/ca/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/ca/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..52416d89 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/ca/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index aae07e9a..00000000 Binary files a/fastlane/metadata/android/ca/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/ca/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..6964f550 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..50b66818 Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..39fb76ef Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/03 - gym mode.png index 5228d44c..ec485e37 100644 Binary files a/fastlane/metadata/android/de-DE/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..34abbabb Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 891275f5..00000000 Binary files a/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..7054ec0f Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 6f840f7e..00000000 Binary files a/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..67276164 Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..81cc43d1 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - workout plan.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - workout plan.png deleted file mode 100644 index d6f10a7b..00000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - workout plan.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..dc4beb18 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout log.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout log.png deleted file mode 100644 index 7e7ebb40..00000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout log.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/03 - gym mode.png index 36ec11c4..5657ad28 100644 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/en-US/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..d30370ea Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index d789fdae..00000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..6e7a4e28 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 8e416462..00000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..77f2fd80 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..d4b3377c Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..f2329bdf Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/03 - gym mode.png index 86fff622..1b47693b 100644 Binary files a/fastlane/metadata/android/es-ES/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..18c8addc Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 74f6f2f5..00000000 Binary files a/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..92351e1a Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 5e643abe..00000000 Binary files a/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..90876b7f Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..5b4d368e Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..57be41cf Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/03 - gym mode.png index 132dfc13..dc5a15b4 100644 Binary files a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..ff96636b Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 448273ea..00000000 Binary files a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..5531d10f Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 733e2945..00000000 Binary files a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..3fc7e5f2 Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..1ad80265 Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..8c5f8092 Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/03 - gym mode.png index ee9bdbff..534ea5d9 100644 Binary files a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..b755a51f Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 82f915b2..00000000 Binary files a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..fc72223c Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 88dbab71..00000000 Binary files a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..9384afeb Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/hr/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..eea4f510 Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/hr/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..27d87a7c Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/hr/images/phoneScreenshots/03 - gym mode.png index a94a0635..81768dd5 100644 Binary files a/fastlane/metadata/android/hr/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/hr/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/hr/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..85e1ea7d Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/hr/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 950ded97..00000000 Binary files a/fastlane/metadata/android/hr/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/hr/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..5f0eca56 Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/hr/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 355bc81f..00000000 Binary files a/fastlane/metadata/android/hr/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/hr/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..abd6f12e Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..975489c1 Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..a9b40055 Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/03 - gym mode.png index 9279928d..81eed2e3 100644 Binary files a/fastlane/metadata/android/it-IT/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..668acf81 Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 3e96d569..00000000 Binary files a/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..07ad0aab Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 1bf193f5..00000000 Binary files a/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..6d0bf959 Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..829e09c3 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..b7dbe679 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/03 - gym mode.png index 36ec11c4..5657ad28 100644 Binary files a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..9163fe98 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 4c93fcf1..00000000 Binary files a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..17264a56 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 552579db..00000000 Binary files a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..b43170f0 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..1f573101 Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..ee559ac8 Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/03 - gym mode.png index 1d2c51e9..aed84b19 100644 Binary files a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..204dc92f Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 4cbe600a..00000000 Binary files a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..a594cc7e Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 4068856b..00000000 Binary files a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..cc5b0f20 Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..223e5648 Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..502b5eae Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/03 - gym mode.png index c7bd85a0..fe146f8f 100644 Binary files a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..0652ffda Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index ddce94aa..00000000 Binary files a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..8b2e08a0 Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index e75b552e..00000000 Binary files a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..9a2a569e Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..6bc759d1 Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..acee5627 Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/03 - gym mode.png index 4d67a221..f0ff41c8 100644 Binary files a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..6b6a251e Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index bf8e14b2..00000000 Binary files a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..354888b7 Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 085ed780..00000000 Binary files a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..2637e2be Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..ded1a193 Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..b0a07ed4 Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/03 - gym mode.png index c5a5c9dc..5519899a 100644 Binary files a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..ac6ad9b9 Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 3f38e08a..00000000 Binary files a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..d6ee6274 Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 13418912..00000000 Binary files a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..7909e9be Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/uk/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..cf4f93b9 Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/uk/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..c72fdca6 Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/uk/images/phoneScreenshots/03 - gym mode.png index c10ff6c7..013a7e11 100644 Binary files a/fastlane/metadata/android/uk/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/uk/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/uk/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..53f59ec6 Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/uk/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 0f380080..00000000 Binary files a/fastlane/metadata/android/uk/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/uk/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..ee52a888 Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/uk/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index e5c14e5f..00000000 Binary files a/fastlane/metadata/android/uk/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/uk/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..e4e65b93 Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..a5b9e1f3 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..f741a2a1 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/03 - gym mode.png index 6be13823..2f7c43ba 100644 Binary files a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..d7845bf5 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index 34f8a419..00000000 Binary files a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..663fbbff Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index 614cf50f..00000000 Binary files a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..3812a2f8 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/06 - weight.png differ diff --git a/integration_test/1_dashboard.dart b/integration_test/1_dashboard.dart new file mode 100644 index 00000000..314ad305 --- /dev/null +++ b/integration_test/1_dashboard.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/body_weight.dart'; +import 'package:wger/providers/measurement.dart'; +import 'package:wger/providers/nutrition.dart'; +import 'package:wger/providers/workout_plans.dart'; +import 'package:wger/screens/dashboard.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/measurements/measurement_categories_screen_test.mocks.dart'; +import '../test/nutrition/nutritional_plan_form_test.mocks.dart'; +import '../test/workout/weight_unit_form_widget_test.mocks.dart'; +import '../test/workout/workout_form_test.mocks.dart'; +import '../test_data/body_weight.dart'; +import '../test_data/measurements.dart'; +import '../test_data/nutritional_plans.dart'; +import '../test_data/workouts.dart'; + +Widget createDashboardScreen({locale = 'en'}) { + final mockWorkoutProvider = MockWorkoutPlansProvider(); + when(mockWorkoutProvider.activePlan).thenReturn(getWorkout()); + + final Map logs = { + 'results': [ + { + 'id': 1, + 'workout': 1, + 'date': '2022-12-01', + 'impression': '3', + 'time_start': '17:00', + 'time_end': '19:00' + } + ] + }; + when(mockWorkoutProvider.fetchSessionData()).thenAnswer((a) => Future.value(logs)); + + final mockNutritionProvider = MockNutritionPlansProvider(); + when(mockNutritionProvider.currentPlan).thenAnswer((realInvocation) => getNutritionalPlan()); + when(mockNutritionProvider.items).thenReturn([getNutritionalPlan()]); + + final mockWeightProvider = MockBodyWeightProvider(); + when(mockWeightProvider.items).thenReturn(getWeightEntries()); + + final mockMeasurementProvider = MockMeasurementProvider(); + when(mockMeasurementProvider.categories).thenReturn(getMeasurementCategories()); + + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => mockWorkoutProvider, + ), + ChangeNotifierProvider( + create: (context) => mockNutritionProvider, + ), + ChangeNotifierProvider( + create: (context) => mockWeightProvider, + ), + ChangeNotifierProvider( + create: (context) => mockMeasurementProvider, + ), + ], + child: MaterialApp( + locale: Locale(locale), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: wgerTheme, + home: DashboardScreen(), + ), + ); +} diff --git a/integration_test/2_workout.dart b/integration_test/2_workout.dart new file mode 100644 index 00000000..753c2578 --- /dev/null +++ b/integration_test/2_workout.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/workout_plans.dart'; +import 'package:wger/screens/workout_plan_screen.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/workout/workout_form_test.mocks.dart'; +import '../test_data/workouts.dart'; + +Widget createWorkoutDetailScreen({locale = 'en'}) { + final key = GlobalKey(); + + final mockWorkoutProvider = MockWorkoutPlansProvider(); + final workout = getWorkout(); + when(mockWorkoutProvider.activePlan).thenReturn(workout); + when(mockWorkoutProvider.fetchAndSetWorkoutPlanFull(1)).thenAnswer((_) => Future.value(workout)); + + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => mockWorkoutProvider, + ), + ], + child: MaterialApp( + locale: Locale(locale), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: wgerTheme, + navigatorKey: key, + home: TextButton( + onPressed: () => key.currentState!.push( + MaterialPageRoute( + settings: RouteSettings(arguments: getWorkout()), + builder: (_) => WorkoutPlanScreen(), + ), + ), + child: const SizedBox(), + ), + ), + ); +} diff --git a/integration_test/3_gym_mode.dart b/integration_test/3_gym_mode.dart new file mode 100644 index 00000000..cc85b890 --- /dev/null +++ b/integration_test/3_gym_mode.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/exercises.dart'; +import 'package:wger/providers/workout_plans.dart'; +import 'package:wger/screens/gym_mode.dart'; +import 'package:wger/screens/workout_plan_screen.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/other/base_provider_test.mocks.dart'; +import '../test/utils.dart'; +import '../test/workout/gym_mode_screen_test.mocks.dart'; +import '../test_data/exercises.dart'; +import '../test_data/workouts.dart'; + +Widget createGymModeScreen({locale = 'en'}) { + final key = GlobalKey(); + final client = MockClient(); + final bases = getTestExerciseBases(); + final workout = getWorkout(); + + final mockExerciseProvider = MockExercisesProvider(); + + when(mockExerciseProvider.findExerciseBaseById(1)).thenReturn(bases[0]); // bench press + when(mockExerciseProvider.findExerciseBaseById(6)).thenReturn(bases[5]); // side raises + //when(mockExerciseProvider.findExerciseBaseById(2)).thenReturn(bases[1]); // crunches + //when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(bases[2]); // dead lift + + return ChangeNotifierProvider( + create: (context) => WorkoutPlansProvider( + testAuthProvider, + mockExerciseProvider, + [workout], + client, + ), + child: ChangeNotifierProvider( + create: (context) => mockExerciseProvider, + child: MaterialApp( + locale: Locale(locale), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + navigatorKey: key, + theme: wgerTheme, + home: TextButton( + onPressed: () => key.currentState!.push( + MaterialPageRoute( + settings: RouteSettings(arguments: workout.days.first), + builder: (_) => GymModeScreen(), + ), + ), + child: const SizedBox(), + ), + routes: { + WorkoutPlanScreen.routeName: (ctx) => WorkoutPlanScreen(), + }, + ), + ), + ); +} diff --git a/integration_test/4_measurements.dart b/integration_test/4_measurements.dart new file mode 100644 index 00000000..2df66d20 --- /dev/null +++ b/integration_test/4_measurements.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/measurement.dart'; +import 'package:wger/screens/measurement_categories_screen.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/measurements/measurement_categories_screen_test.mocks.dart'; +import '../test_data/measurements.dart'; + +Widget createMeasurementScreen({locale = 'en'}) { + final mockMeasurementProvider = MockMeasurementProvider(); + when(mockMeasurementProvider.categories).thenReturn(getMeasurementCategories()); + + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => mockMeasurementProvider, + ), + ], + child: MaterialApp( + locale: Locale(locale), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: wgerTheme, + home: MeasurementCategoriesScreen(), + ), + ); +} diff --git a/integration_test/nutritional_plan.dart b/integration_test/5_nutritional_plan.dart similarity index 100% rename from integration_test/nutritional_plan.dart rename to integration_test/5_nutritional_plan.dart diff --git a/integration_test/weight.dart b/integration_test/6_weight.dart similarity index 100% rename from integration_test/weight.dart rename to integration_test/6_weight.dart diff --git a/integration_test/app_test.dart b/integration_test/app_test.dart index 5b7ecc96..feeeeea9 100644 --- a/integration_test/app_test.dart +++ b/integration_test/app_test.dart @@ -4,9 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'gym_mode.dart'; -import 'nutritional_plan.dart'; -import 'weight.dart'; +import '1_dashboard.dart'; +import '2_workout.dart'; +import '3_gym_mode.dart'; +import '4_measurements.dart'; +import '5_nutritional_plan.dart'; +import '6_weight.dart'; Future takeScreenshot(tester, binding, String language, String name) async { if (Platform.isAndroid) { @@ -17,23 +20,35 @@ Future takeScreenshot(tester, binding, String language, String name) async .takeScreenshot('fastlane/metadata/android/$language/images/phoneScreenshots/$name.png'); } -// Available languages in weblate for the android metadata +// Available languages in weblate for the android metadata (not necessarily +// those for which the application is translated) const languages = [ + //'de-DE', + + // Note: it seems if too many languages are processed at once, some processes + // disappear and no images are written. Doing this in smaller steps works fine + + /* 'ca', 'de-DE', 'en-US', 'es-ES', 'fr-FR', + */ + /* 'hi-IN', 'hr', 'it-IT', 'pt-BR', 'nb-NO', + */ + /* 'pl-PL', 'ru-RU', 'tr-TR', 'uk', 'zh-CN' + */ ]; void main() { @@ -43,6 +58,18 @@ void main() { for (final language in languages) { final languageCode = language.split('-')[0]; + testWidgets('dashboard screen - $language', (WidgetTester tester) async { + await tester.pumpWidget(createDashboardScreen(locale: languageCode)); + await takeScreenshot(tester, binding, language, '01 - dashboard'); + }); + + testWidgets('workout detail screen - $language', (WidgetTester tester) async { + await tester.pumpWidget(createWorkoutDetailScreen(locale: languageCode)); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + await takeScreenshot(tester, binding, language, '02 - workout detail'); + }); + testWidgets('gym mode screen - $language', (WidgetTester tester) async { await tester.pumpWidget(createGymModeScreen(locale: languageCode)); await tester.tap(find.byType(TextButton)); @@ -50,17 +77,22 @@ void main() { await takeScreenshot(tester, binding, language, '03 - gym mode'); }); + testWidgets('measurement screen - $language', (WidgetTester tester) async { + await tester.pumpWidget(createMeasurementScreen(locale: languageCode)); + await takeScreenshot(tester, binding, language, '04 - measurements'); + }); + testWidgets('nutritional plan detail - $language', (WidgetTester tester) async { await tester.pumpWidget(createNutritionalPlanScreen(locale: languageCode)); await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); - await takeScreenshot(tester, binding, language, '04 - nutritional plan'); + await takeScreenshot(tester, binding, language, '05 - nutritional plan'); }); testWidgets('body weight screen - $language', (WidgetTester tester) async { await tester.pumpWidget(createWeightScreen(locale: languageCode)); await tester.pumpAndSettle(); - await takeScreenshot(tester, binding, language, '05 - weight'); + await takeScreenshot(tester, binding, language, '06 - weight'); }); } }); diff --git a/integration_test/gym_mode.dart b/integration_test/gym_mode.dart deleted file mode 100644 index 192deb95..00000000 --- a/integration_test/gym_mode.dart +++ /dev/null @@ -1,246 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:mockito/mockito.dart'; -import 'package:provider/provider.dart'; -import 'package:wger/models/exercises/exercise.dart'; -import 'package:wger/models/workouts/day.dart'; -import 'package:wger/models/workouts/set.dart'; -import 'package:wger/models/workouts/setting.dart'; -import 'package:wger/models/workouts/workout_plan.dart'; -import 'package:wger/providers/exercises.dart'; -import 'package:wger/providers/workout_plans.dart'; -import 'package:wger/screens/gym_mode.dart'; -import 'package:wger/screens/workout_plan_screen.dart'; -import 'package:wger/theme/theme.dart'; - -import '../test/other/base_provider_test.mocks.dart'; -import '../test/utils.dart'; -import '../test/workout/gym_mode_screen_test.mocks.dart'; -import '../test_data/exercises.dart'; -import '../test_data/workouts.dart'; - -Widget createGymModeScreen({locale = 'en'}) { - final key = GlobalKey(); - final client = MockClient(); - final bases = getTestExerciseBases(); - - final squats = bases[0]; - final squatsEn = Exercise( - id: 1, - uuid: 'uuid', - creationDate: DateTime(2021, 1, 15), - name: 'Squats', - description: 'add clever text', - baseId: tBase1.id, - language: tLanguage1, - ); - squats.exercises = [squatsEn]; - - final benchPress = bases[1]; - final benchPressEn = Exercise( - id: 1, - uuid: 'uuid', - creationDate: DateTime(2021, 1, 15), - name: 'Bench press', - description: 'add clever text', - baseId: tBase1.id, - language: tLanguage1, - ); - benchPress.exercises = [benchPressEn]; - - final deadLift = bases[2]; - final deadLiftEn = Exercise( - id: 1, - uuid: 'uuid', - creationDate: DateTime(2021, 1, 15), - name: 'Dead Lift', - description: 'add clever text', - baseId: tBase1.id, - language: tLanguage1, - ); - deadLift.exercises = [deadLiftEn]; - - final crunches = bases[3]; - final crunchesEn = Exercise( - id: 1, - uuid: 'uuid', - creationDate: DateTime(2021, 1, 15), - name: 'Crunches', - description: 'add clever text', - baseId: tBase1.id, - language: tLanguage1, - ); - crunches.exercises = [crunchesEn]; - - final mockExerciseProvider = MockExercisesProvider(); - when(mockExerciseProvider.findExerciseBaseById(1)).thenReturn(squats); - when(mockExerciseProvider.findExerciseBaseById(2)).thenReturn(benchPress); - when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(crunches); - - final setting1 = Setting( - setId: 1, - order: 1, - exerciseBaseId: 1, - repetitionUnitId: 1, - reps: 5, - weightUnitId: 1, - comment: 'ddd', - rir: '2', - ); - setting1.repetitionUnit = repetitionUnit1; - setting1.weightUnit = weightUnit1; - setting1.exerciseBase = squats; - setting1.weight = 100; - - final setting2 = Setting( - setId: 1, - order: 1, - exerciseBaseId: 2, - repetitionUnitId: 1, - reps: 6, - weightUnitId: 1, - comment: 'ddd', - rir: '1.5', - ); - setting2.repetitionUnit = repetitionUnit1; - setting2.weightUnit = weightUnit1; - setting2.exerciseBase = benchPress; - setting2.weight = 80; - - final setting2b = Setting( - setId: 1, - order: 1, - exerciseBaseId: 2, - repetitionUnitId: 1, - reps: 8, - weightUnitId: 1, - comment: 'ddd', - rir: '2', - ); - setting2b.repetitionUnit = repetitionUnit1; - setting2b.weightUnit = weightUnit1; - setting2b.exerciseBase = benchPress; - setting2b.weight = 60; - - final setting3 = Setting( - setId: 1, - order: 1, - exerciseBaseId: 2, - repetitionUnitId: 1, - reps: 20, - weightUnitId: 1, - comment: '', - rir: null, - ); - setting3.repetitionUnit = repetitionUnit1; - setting3.weightUnit = weightUnit1; - setting3.exerciseBase = crunches; - - final setting4 = Setting( - setId: 1, - order: 1, - exerciseBaseId: 2, - repetitionUnitId: 1, - reps: 8, - weightUnitId: 1, - comment: '', - rir: null, - ); - setting4.repetitionUnit = repetitionUnit1; - setting4.weightUnit = weightUnit1; - setting4.exerciseBase = deadLift; - setting4.weight = 120; - - final set1 = Set.withData( - id: 1, - day: 1, - sets: 3, - order: 1, - ); - set1.addExerciseBase(squats); - set1.settings.add(setting1); - set1.settings.add(setting1); - set1.settings.add(setting1); - set1.settings.add(setting1); - - final set2 = Set.withData( - id: 2, - day: 1, - sets: 3, - order: 1, - ); - set2.addExerciseBase(benchPress); - set2.settings.add(setting2); - set2.settings.add(setting2); - set2.settings.add(setting2b); - set2.settings.add(setting2b); - - final set3 = Set.withData( - id: 3, - day: 1, - sets: 3, - order: 1, - ); - set3.addExerciseBase(crunches); - set3.settings.add(setting3); - - final set4 = Set.withData( - id: 4, - day: 1, - sets: 3, - order: 1, - ); - set4.addExerciseBase(deadLift); - set4.settings.add(setting4); - set4.settings.add(setting4); - set4.settings.add(setting4); - set4.settings.add(setting4); - - final day1 = Day() - ..id = 1 - ..workoutId = 1 - ..description = 'test day 1' - ..daysOfWeek = [1, 2]; - day1.sets.add(set1); - day1.sets.add(set2); - day1.sets.add(set4); - day1.sets.add(set3); - - final workout = WorkoutPlan( - id: 1, - creationDate: DateTime(2021, 01, 01), - name: 'test workout 1', - days: [day1], - ); - - return ChangeNotifierProvider( - create: (context) => WorkoutPlansProvider( - testAuthProvider, - mockExerciseProvider, - [workout], - client, - ), - child: ChangeNotifierProvider( - create: (context) => mockExerciseProvider, - child: MaterialApp( - locale: Locale(locale), - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - navigatorKey: key, - theme: wgerTheme, - home: TextButton( - onPressed: () => key.currentState!.push( - MaterialPageRoute( - settings: RouteSettings(arguments: workout.days.first), - builder: (_) => GymModeScreen(), - ), - ), - child: const SizedBox(), - ), - routes: { - WorkoutPlanScreen.routeName: (ctx) => WorkoutPlanScreen(), - }, - ), - ), - ); -} diff --git a/lib/helpers/ui.dart b/lib/helpers/ui.dart index 5219c000..5c28b812 100644 --- a/lib/helpers/ui.dart +++ b/lib/helpers/ui.dart @@ -22,6 +22,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:provider/provider.dart'; import 'package:wger/exceptions/http_exception.dart'; +import 'package:wger/models/exercises/base.dart'; import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/workouts/log.dart'; import 'package:wger/providers/workout_plans.dart'; @@ -56,7 +57,15 @@ void showHttpExceptionErrorDialog(WgerHttpException exception, BuildContext cont final List errorList = []; for (final key in exception.errors!.keys) { // Error headers - errorList.add(Text(key, style: const TextStyle(fontWeight: FontWeight.bold))); + // Ensure that the error heading first letter is capitalized. + final String errorHeaderMsg = key[0].toUpperCase() + key.substring(1, key.length); + + errorList.add( + Text( + errorHeaderMsg, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ); // Error messages if (exception.errors![key] is String) { @@ -74,6 +83,7 @@ void showHttpExceptionErrorDialog(WgerHttpException exception, BuildContext cont builder: (ctx) => AlertDialog( title: Text(AppLocalizations.of(ctx).anErrorOccurred), content: Column( + crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [...errorList], ), @@ -93,8 +103,13 @@ void showHttpExceptionErrorDialog(WgerHttpException exception, BuildContext cont // showDialog(context: context, builder: (context) => Container()); } -dynamic showDeleteDialog(BuildContext context, String confirmDeleteName, Log log, Exercise exercise, - Map> _exerciseData) async { +dynamic showDeleteDialog( + BuildContext context, + String confirmDeleteName, + Log log, + Exercise exercise, + Map> exerciseData, +) async { final res = await showDialog( context: context, builder: (BuildContext contextDialog) { @@ -113,7 +128,7 @@ dynamic showDeleteDialog(BuildContext context, String confirmDeleteName, Log log style: TextStyle(color: Theme.of(context).errorColor), ), onPressed: () { - _exerciseData[exercise]!.removeWhere((el) => el.id == log.id); + exerciseData[exercise]!.removeWhere((el) => el.id == log.id); Provider.of(context, listen: false).deleteLog( log, ); diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 6574e9d7..7e0d9c3a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -194,9 +194,9 @@ "@logHelpEntriesUnits": {}, "logHelpEntries": "Gibt es an einem Tag mehrere Einträge mit der gleichen Anzahl von Wiederholungen, aber unterschiedlichen Gewichten, wird nur der Eintrag mit dem höheren Gewicht im Diagramm angezeigt.", "@logHelpEntries": {}, - "loginInstead": "Stattdessen anmelden", + "loginInstead": "Du hast bereits einen Account? Stattdessen anmelden", "@loginInstead": {}, - "registerInstead": "Stattdessen registrieren", + "registerInstead": "Du hast keinen Account? Jetzt registrieren", "@registerInstead": {}, "reset": "Zurücksetzen", "@reset": { @@ -575,11 +575,39 @@ "description": "Label for scan barcode button" }, "abs": "Bauch", + "@abs": {}, "arms": "Arme", + "@arms": {}, "back": "Rücken", + "@back": {}, "calves": "Waden", + "@calves": {}, "chest": "Brust", + "@chest": {}, "legs": "Beine", + "@legs": {}, "shoulders": "Schultern", - "barbell": "Langhantel" + "@shoulders": {}, + "barbell": "Langhantel", + "@barbell": {}, + "noMeasurementEntries": "Du hast keine Messeingaben", + "@noMeasurementEntries": {}, + "moreMeasurementEntries": "Neue Messung hinzufügen", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, + "selectEntry": "Bitte einen Eintrag auswählen", + "@selectEntry": {}, + "exercises": "Übung", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "userProfile": "Dein Profil", + "@userProfile": {}, + "exerciseList": "Trainingsplan", + "@exerciseList": {}, + "exerciseName": "Name der Übung", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index acf06b35..287fadff 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -65,9 +65,9 @@ "@reset": { "description": "Button text allowing the user to reset the entered values to the default" }, - "registerInstead": "Register instead", + "registerInstead": "Don't have an account? Register now", "@registerInstead": {}, - "loginInstead": "Log in instead", + "loginInstead": "Already have an account? Login", "@loginInstead": {}, "labelWorkoutPlans": "Workout plans", "@labelWorkoutPlans": { @@ -647,5 +647,6 @@ "back": "Back", "quads": "Quads", "arms": "Arms", - "sz_bar": "SZ-Bar" + "sz_bar": "SZ-Bar", + "aboutPageTitle": "About Wger" } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 70fbf904..961ceb40 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -568,5 +568,21 @@ "searchIngredient": "Cerca ingrediente", "@searchIngredient": { "description": "Label on ingredient search form" - } + }, + "userProfile": "Il tuo profilo", + "@userProfile": {}, + "exerciseList": "Lista esercizi", + "@exerciseList": {}, + "exercises": "Esercizi", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "exerciseName": "Nome Esercizio", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "previous": "Precedente", + "@previous": {}, + "next": "Successivo", + "@next": {} } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 9fd2ce77..07932a02 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -262,9 +262,9 @@ "@measurements": { "description": "Categories for the measurements such as biceps size, body fat, etc." }, - "registerInstead": "Zarejestruj zamiast", + "registerInstead": "Nie posiadasz konta? Zarejestruj się teraz", "@registerInstead": {}, - "loginInstead": "Zaloguj się zamiast tego", + "loginInstead": "Posiadasz konto? Zaloguj się", "@loginInstead": {}, "labelWorkoutPlans": "Plany treningowe", "@labelWorkoutPlans": { @@ -556,5 +556,146 @@ "enterValidNumber": "Proszę wprowadzić poprawny numer", "@enterValidNumber": { "description": "Error message when the user has submitted an invalid number (e.g. '3,.,.,.')" - } + }, + "noMeasurementEntries": "Nie masz wpisów pomiarowych", + "@noMeasurementEntries": {}, + "moreMeasurementEntries": "Dodaj nowy pomiar", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, + "enterMinCharacters": "Proszę wpisać co najmniej {min} znaków", + "@enterMinCharacters": { + "description": "Error message when the user hasn't entered the minimum amount characters in a form", + "type": "text", + "placeholders": { + "min": {} + } + }, + "baseNameEnglish": "Wszystkie ćwiczenia wymagają nazwy podstawowej w języku angielskim", + "@baseNameEnglish": {}, + "images": "Obrazy", + "@images": {}, + "language": "Język", + "@language": {}, + "add_exercise_image_license": "Obrazy muszą być zgodne z licencją CC BY SA. Jeśli masz wątpliwości przesyłaj tylko zdjęcia które sam zrobiłeś.", + "@add_exercise_image_license": {}, + "variations": "Wariacje", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "alsoKnownAs": "Znany również jako: {aliases}", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "unVerifiedEmail": "Niezweryfikowany adres e-mail", + "@unVerifiedEmail": {}, + "verifiedEmail": "Zweryfikowany adres e-mail", + "@verifiedEmail": {}, + "verifiedEmailReason": "Aby współtworzyć ćwiczenia musisz zweryfikować swój adres e-mail", + "@verifiedEmailReason": {}, + "verifiedEmailInfo": "Wiadomość weryfikacyjna została wysłana na adres {email}", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "alternativeNames": "Alternatywne nazwy", + "@alternativeNames": {}, + "oneNamePerLine": "Jedna nazwa w wierszu", + "@oneNamePerLine": {}, + "whatVariationsExist": "Czy istnieją wariacje tego ćwiczenia?", + "@whatVariationsExist": {}, + "previous": "Wstecz", + "@previous": {}, + "next": "Następny", + "@next": {}, + "addExercise": "Dodaj ćwiczenie", + "@addExercise": {}, + "translation": "Tłumaczenie", + "@translation": {}, + "contributeExercise": "Przekaż ćwiczenie", + "@contributeExercise": {}, + "translateExercise": "Przetłumacz to ćwiczenie teraz", + "@translateExercise": {}, + "minutes": "Minuty", + "@minutes": {}, + "kilometers": "Kilometry", + "@kilometers": {}, + "until_failure": "Aż do awarii", + "@until_failure": {}, + "seconds": "Sekundy", + "@seconds": {}, + "bench": "Ławka", + "@bench": {}, + "triceps": "Triceps", + "@triceps": {}, + "swiss_ball": "Piłka lekarska", + "@swiss_ball": {}, + "none__bodyweight_exercise_": "brak (ćwiczenie z masą ciała)", + "@none__bodyweight_exercise_": {}, + "pull_up_bar": "Drążek do podciągania", + "@pull_up_bar": {}, + "biceps": "Biceps", + "@biceps": {}, + "userProfile": "Twój profil", + "@userProfile": {}, + "exerciseList": "Lista ćwiczeń", + "@exerciseList": {}, + "exercises": "Ćwiczenia", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "exerciseName": "Nazwa ćwiczenia", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "selectEntry": "Wybierz wpis", + "@selectEntry": {}, + "incline_bench": "Ławka skośna", + "@incline_bench": {}, + "gym_mat": "Mata gimnastyczna", + "@gym_mat": {}, + "aboutPageTitle": "Więcej o Wger", + "@aboutPageTitle": {}, + "glutes": "Pośladki", + "@glutes": {}, + "baseData": "Podstawy po angielsku", + "@baseData": { + "description": "The base data for an exercise such as category, trained muscles, etc." + }, + "barbell": "Sztanga", + "@barbell": {}, + "lats": "Mięsień najszerszy pleców", + "@lats": {}, + "legs": "Nogi", + "@legs": {}, + "arms": "Ręce", + "@arms": {}, + "sz_bar": "Gryf łamany", + "@sz_bar": {}, + "miles": "Mile", + "@miles": {}, + "shoulders": "Barki", + "@shoulders": {}, + "calves": "Łydki", + "@calves": {}, + "hamstrings": "Mięsień dwugłowy uda", + "@hamstrings": {}, + "chest": "Klatka piersiowa", + "@chest": {}, + "back": "Plecy", + "@back": {}, + "lower_back": "Dolna część pleców", + "@lower_back": {}, + "kettlebell": "Kettle", + "@kettlebell": {}, + "dumbbell": "Hantla", + "@dumbbell": {}, + "abs": "Brzuch", + "@abs": {}, + "quads": "Mięsień czworogłowy uda", + "@quads": {} } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 143e10b4..44325e71 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -253,12 +253,6 @@ "@selectImage": { "description": "Label and error message when the user hasn't selected an image to save" }, - "takePicture": "Tirar uma foto", - "@takePicture": {}, - "chooseFromLibrary": "Escolha na biblioteca de fotos", - "@chooseFromLibrary": {}, - "gallery": "Galeria", - "@gallery": {}, "addImage": "Adicionar imagem", "@addImage": {}, "dataCopied": "Dados copiados para nova entrada", @@ -285,10 +279,6 @@ "@scanBarcode": { "description": "Label for scan barcode button" }, - "close": "Fechar", - "@close": { - "description": "Translation for close" - }, "register": "Registrar", "@register": { "description": "Text for registration button" @@ -556,5 +546,72 @@ "placeholders": { "productName": {} } - } + }, + "alsoKnownAs": "Também chamado de: {aliases}", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "verifiedEmail": "Email verificado", + "unVerifiedEmail": "Verificação pendente", + "verifiedEmailReason": "É necessário verificar seu email para contribuir com exercícios", + "verifiedEmailInfo": "Um email de verificação foi enviado para {email}", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "close": "Fechar", + "@close": { + "description": "Translation for close" + }, + "variations": "Variações", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "oneNamePerLine": "Somente um nome por linha", + "whatVariationsExist": "Se houver alguma, quais as possíveis variações para esse exercício?", + "takePicture": "Tirar uma foto", + "@takePicture": {}, + "chooseFromLibrary": "Escolher da galeria", + "@chooseFromLibrary": {}, + "gallery": "Galeria de fotos", + "@gallery": {}, + "addExercise": "Adicionar exercício", + "translation": "Tradução", + "translateExercise": "Traduzir este exercício", + "alternativeNames": "Outros nomes", + "images": "Imagens", + "language": "Idioma", + "previous": "Anterior", + "next": "Próximo", + "minutes": "Minutos", + "seconds": "Segundos", + "until_failure": "Até a falha", + "kilometers": "Quilômetros", + "glutes": "Glúteos", + "bench": "Supino", + "barbell": "Barra", + "triceps": "Tríceps", + "biceps": "Bíceps", + "dumbbell": "Haltere", + "abs": "Abdominal", + "chest": "Peito", + "shoulders": "Ombro", + "gym_mat": "Colchonete", + "incline_bench": "Supino inclinado", + "calves": "Panturrilha", + "legs": "Pernas", + "lats": "Dorsal", + "quads": "Quadríceps", + "hamstrings": "Posterior de coxa", + "arms": "Braços", + "pull_up_bar": "Barra fixa", + "lower_back": "Lombar", + "swiss_ball": "Bola suíça", + "kettlebell": "Kettlebell", + "none__bodyweight_exercise_": "nenhum (somente peso do corpo)", + "aboutPageTitle": "Sobre Wger" } diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index f7bbc05c..6709f870 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -55,9 +55,9 @@ "@labelBottomNavWorkout": { "description": "Label used in bottom navigation, use a short word" }, - "loginInstead": "Bunun yerine giriş yapın", + "loginInstead": "Zaten hesabınız var mı? Oturum açın", "@loginInstead": {}, - "registerInstead": "Bunun yerine kaydolun", + "registerInstead": "Hesabınız yok mu? Şimdi kaydolun", "@registerInstead": {}, "reset": "Sıfırla", "@reset": { @@ -556,5 +556,146 @@ "dataCopied": "Veriler yeni girişe kopyalandı", "@dataCopied": { "description": "Snackbar message to show on copying data to a new log entry" - } + }, + "alsoKnownAs": "{aliases} olarak da bilinir", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "exerciseList": "Egzersiz listesi", + "@exerciseList": {}, + "images": "Resimler", + "@images": {}, + "exerciseName": "Egzersiz Adı", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "enterMinCharacters": "Lütfen en az {min} karakter girin", + "@enterMinCharacters": { + "description": "Error message when the user hasn't entered the minimum amount characters in a form", + "type": "text", + "placeholders": { + "min": {} + } + }, + "add_exercise_image_license": "Görseller CC BY SA lisansı ile uyumlu olmalıdır. Emin değilseniz, yalnızca kendi çektiğiniz fotoğrafları yükleyin.", + "@add_exercise_image_license": {}, + "verifiedEmailReason": "Egzersizlere katkıda bulunmak için e-posta adresinizi doğrulamanız gerekiyor", + "@verifiedEmailReason": {}, + "alternativeNames": "Alternatif isimler", + "@alternativeNames": {}, + "minutes": "Dakika", + "@minutes": {}, + "seconds": "Saniye", + "@seconds": {}, + "verifiedEmailInfo": "{email} adresine bir doğrulama e-postası gönderildi", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "previous": "Önceki", + "@previous": {}, + "next": "Sonraki", + "@next": {}, + "translateExercise": "Bu egzersizi şimdi çevir", + "@translateExercise": {}, + "glutes": "Kalça kasları", + "@glutes": {}, + "kilometers": "Kilometre", + "@kilometers": {}, + "dumbbell": "Dambıl", + "@dumbbell": {}, + "bench": "Benç", + "@bench": {}, + "none__bodyweight_exercise_": "yok (vücut ağırlığı egzersizi)", + "@none__bodyweight_exercise_": {}, + "shoulders": "Omuzlar", + "@shoulders": {}, + "biceps": "Pazılar", + "@biceps": {}, + "arms": "Kollar", + "@arms": {}, + "incline_bench": "Eğim tezgahı", + "@incline_bench": {}, + "userProfile": "Profilin", + "@userProfile": {}, + "selectEntry": "Lütfen bir giriş seçin", + "@selectEntry": {}, + "baseNameEnglish": "Tüm egzersizlerin İngilizce bir ismi olmalıdır", + "@baseNameEnglish": {}, + "variations": "Varyasyonlar", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "verifiedEmail": "Doğrulanmış e-posta adresi", + "@verifiedEmail": {}, + "unVerifiedEmail": "Doğrulanmamış e-posta adresi", + "@unVerifiedEmail": {}, + "oneNamePerLine": "Satır başına bir ad", + "@oneNamePerLine": {}, + "whatVariationsExist": "Varsa, bu egzersizin hangi varyasyonları vardır?", + "@whatVariationsExist": {}, + "language": "Dil", + "@language": {}, + "addExercise": "Egzersiz ekle", + "@addExercise": {}, + "contributeExercise": "Egzersize katkıda bulunun", + "@contributeExercise": {}, + "until_failure": "Başarısız olana kadar", + "@until_failure": {}, + "barbell": "Halter", + "@barbell": {}, + "lower_back": "Alt sırt", + "@lower_back": {}, + "pull_up_bar": "Barfiks çubuğu", + "@pull_up_bar": {}, + "calves": "Baldırlar", + "@calves": {}, + "chest": "Göğüs", + "@chest": {}, + "triceps": "Triceps kasları", + "@triceps": {}, + "swiss_ball": "Egzersiz Topu", + "@swiss_ball": {}, + "hamstrings": "Hamstringler", + "@hamstrings": {}, + "gym_mat": "Spor matı", + "@gym_mat": {}, + "miles": "Mil", + "@miles": {}, + "kettlebell": "Kettlebell", + "@kettlebell": {}, + "abs": "Karın Kasları", + "@abs": {}, + "lats": "Lat kasları", + "@lats": {}, + "legs": "Bacaklar", + "@legs": {}, + "back": "Sırt", + "@back": {}, + "quads": "Quad kasları", + "@quads": {}, + "sz_bar": "Z-Bar", + "@sz_bar": {}, + "exercises": "Egzersizler", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "translation": "Çeviri", + "@translation": {}, + "baseData": "İngilizce'de temel bilgiler", + "@baseData": { + "description": "The base data for an exercise such as category, trained muscles, etc." + }, + "noMeasurementEntries": "Ölçüm girdiniz yok", + "@noMeasurementEntries": {}, + "moreMeasurementEntries": "Yeni ölçüm ekle", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, + "aboutPageTitle": "Wger Hakkında", + "@aboutPageTitle": {} } diff --git a/lib/main.dart b/lib/main.dart index 7998edad..1ceeefeb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -43,11 +43,11 @@ import 'package:wger/screens/nutritional_diary_screen.dart'; import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/screens/nutritional_plans_screen.dart'; import 'package:wger/screens/splash_screen.dart'; -import 'package:wger/screens/update_app_screen.dart'; import 'package:wger/screens/weight_screen.dart'; import 'package:wger/screens/workout_plan_screen.dart'; import 'package:wger/screens/workout_plans_screen.dart'; import 'package:wger/theme/theme.dart'; +import 'package:wger/widgets/core/about.dart'; import 'providers/auth.dart'; @@ -124,13 +124,7 @@ class MyApp extends StatelessWidget { title: 'wger', theme: wgerTheme, home: auth.isAuth - ? FutureBuilder( - future: auth.applicationUpdateRequired(), - builder: (ctx, snapshot) => - snapshot.connectionState == ConnectionState.done && snapshot.data == true - ? UpdateAppScreen() - : HomeTabsScreen(), - ) + ? HomeTabsScreen() : FutureBuilder( future: auth.tryAutoLogin(), builder: (ctx, authResultSnapshot) => @@ -155,6 +149,7 @@ class MyApp extends StatelessWidget { ExercisesScreen.routeName: (ctx) => const ExercisesScreen(), ExerciseDetailScreen.routeName: (ctx) => const ExerciseDetailScreen(), AddExerciseScreen.routeName: (ctx) => const AddExerciseScreen(), + AboutPage.routeName: (ctx) => const AboutPage(), }, localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, diff --git a/lib/models/workouts/workout_plan.dart b/lib/models/workouts/workout_plan.dart index 37efafd3..cb53ade8 100644 --- a/lib/models/workouts/workout_plan.dart +++ b/lib/models/workouts/workout_plan.dart @@ -18,7 +18,6 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:wger/models/exercises/base.dart'; -import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/workouts/day.dart'; import 'package:wger/models/workouts/log.dart'; @@ -95,7 +94,7 @@ class WorkoutPlan { if (!out.containsKey(date)) { out[date] = { 'session': null, - 'exercises': >{}, + 'exercises': >{}, }; } diff --git a/lib/providers/auth.dart b/lib/providers/auth.dart index e1f1f6db..10886042 100644 --- a/lib/providers/auth.dart +++ b/lib/providers/auth.dart @@ -34,6 +34,11 @@ import 'package:wger/helpers/consts.dart'; import 'helpers.dart'; +enum LoginActions { + update, + proceed, +} + class AuthProvider with ChangeNotifier { String? token; String? serverUrl; @@ -75,30 +80,35 @@ class AuthProvider with ChangeNotifier { serverVersion = responseData; } + Future initData(String serverUrl) async { + this.serverUrl = serverUrl; + await setApplicationVersion(); + await setServerVersion(); + } + /// (flutter) Application version Future setApplicationVersion() async { - final PackageInfo packageInfo = await PackageInfo.fromPlatform(); - applicationVersion = packageInfo; + applicationVersion = await PackageInfo.fromPlatform(); } /// Checking if there is a new version of the application. - Future applicationUpdateRequired([String? version]) async { - if (metadata.containsKey('wger.check_min_app_version') || + Future applicationUpdateRequired([String? version, Map? metadata]) async { + metadata ??= this.metadata; + if (!metadata.containsKey('wger.check_min_app_version') || metadata['wger.check_min_app_version'] == 'false') { return false; } final applicationCurrentVersion = version ?? applicationVersion!.version; - final response = await client.get(makeUri(serverUrl!, MIN_APP_VERSION_URL)); final currentVersion = Version.parse(applicationCurrentVersion); + final requiredAppVersion = Version.parse(jsonDecode(response.body)); - final requiredAppVersion = Version.parse(response.body); - return requiredAppVersion >= currentVersion; + return requiredAppVersion > currentVersion; } /// Registers a new user - Future register( + Future> register( {required String username, required String password, required String email, @@ -124,14 +134,23 @@ class AuthProvider with ChangeNotifier { throw WgerHttpException(responseData); } - login(username, password, serverUrl); + // If update is required don't log in user + if (await applicationUpdateRequired()) { + return {'action': LoginActions.update}; + } + + return login(username, password, serverUrl); } catch (error) { rethrow; } } /// Authenticates a user - Future login(String username, String password, String serverUrl) async { + Future> login( + String username, + String password, + String serverUrl, + ) async { await logout(shouldNotify: false); try { @@ -149,10 +168,15 @@ class AuthProvider with ChangeNotifier { throw WgerHttpException(responseData); } - // Log user in - this.serverUrl = serverUrl; - token = responseData['token']; + await initData(serverUrl); + // If update is required don't log in user + if (await applicationUpdateRequired()) { + return {'action': LoginActions.update}; + } + + // Log user in + token = responseData['token']; notifyListeners(); // store login data in shared preferences @@ -165,10 +189,9 @@ class AuthProvider with ChangeNotifier { 'serverUrl': this.serverUrl, }); - await setServerVersion(); - await setApplicationVersion(); prefs.setString('userData', userData); prefs.setString('lastServer', serverData); + return {'action': LoginActions.proceed}; } catch (error) { rethrow; } diff --git a/lib/providers/workout_plans.dart b/lib/providers/workout_plans.dart index fc08d6cf..e27c3b6a 100644 --- a/lib/providers/workout_plans.dart +++ b/lib/providers/workout_plans.dart @@ -25,6 +25,7 @@ import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/helpers/consts.dart'; +import 'package:wger/models/exercises/base.dart'; import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/workouts/day.dart'; import 'package:wger/models/workouts/log.dart'; @@ -297,13 +298,13 @@ class WorkoutPlansProvider extends WgerBaseProvider with ChangeNotifier { } } - Future> fetchLogData(WorkoutPlan workout, Exercise exercise) async { + Future> fetchLogData(WorkoutPlan workout, ExerciseBase base) async { final data = await fetch( makeUrl( _workoutPlansUrlPath, id: workout.id, objectMethod: 'log_data', - query: {'id': exercise.id.toString()}, + query: {'id': base.id.toString()}, ), ); return data; diff --git a/lib/screens/auth_screen.dart b/lib/screens/auth_screen.dart index 8050d850..27c006de 100644 --- a/lib/screens/auth_screen.dart +++ b/lib/screens/auth_screen.dart @@ -24,6 +24,8 @@ import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/misc.dart'; import 'package:wger/helpers/ui.dart'; +import 'package:wger/screens/update_app_screen.dart'; +import 'package:wger/theme/theme.dart'; import '../providers/auth.dart'; @@ -39,9 +41,18 @@ class AuthScreen extends StatelessWidget { Widget build(BuildContext context) { final deviceSize = MediaQuery.of(context).size; return Scaffold( - backgroundColor: Theme.of(context).primaryColor, + backgroundColor: wgerBackground, body: Stack( children: [ + Positioned( + top: 0, + right: 0, + left: 0, + child: Container( + height: 0.55 * deviceSize.height, + color: Theme.of(context).primaryColor, + ), + ), SingleChildScrollView( child: SizedBox( height: deviceSize.height, @@ -50,10 +61,10 @@ class AuthScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ - const Padding(padding: EdgeInsets.symmetric(vertical: 20)), + SizedBox(height: 0.15 * deviceSize.height), const Image( image: AssetImage('assets/images/logo-white.png'), - width: 120, + width: 85, ), Container( margin: const EdgeInsets.only(bottom: 20.0), @@ -61,21 +72,27 @@ class AuthScreen extends StatelessWidget { child: const Text( 'WGER', style: TextStyle( - color: Colors.white, - fontSize: 50, + color: Colors.white70, + fontSize: 30, fontFamily: 'OpenSansBold', fontWeight: FontWeight.bold, ), ), ), + SizedBox(height: 0.025 * deviceSize.height), const Flexible( - //flex: deviceSize.width > 600 ? 2 : 1, child: AuthCard(), ), ], ), ), ), + // Positioned( + // top: 0.4 * deviceSize.height, + // left: 15, + // right: 15, + // child: const , + // ), ], ), ); @@ -90,6 +107,9 @@ class AuthCard extends StatefulWidget { } class _AuthCardState extends State { + bool isObscure = true; + bool confirmIsObscure = true; + final GlobalKey _formKey = GlobalKey(); bool _canRegister = true; AuthMode _authMode = AuthMode.Login; @@ -139,19 +159,30 @@ class _AuthCardState extends State { try { // Login existing user + late Map res; if (_authMode == AuthMode.Login) { - await Provider.of(context, listen: false) + res = await Provider.of(context, listen: false) .login(_authData['username']!, _authData['password']!, _authData['serverUrl']!); // Register new user } else { - await Provider.of(context, listen: false).register( + res = await Provider.of(context, listen: false).register( username: _authData['username']!, password: _authData['password']!, email: _authData['email']!, serverUrl: _authData['serverUrl']!); } + // Check if update is required else continue normally + if (res.containsKey('action')) { + if (res['action'] == LoginActions.update && mounted) { + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => UpdateAppScreen()), + ); + return; + } + } + setState(() { _isLoading = false; }); @@ -161,10 +192,12 @@ class _AuthCardState extends State { _isLoading = false; }); } catch (error) { - showErrorDialog(error, context); - setState(() { - _isLoading = false; - }); + if (mounted) { + showErrorDialog(error, context); + setState(() { + _isLoading = false; + }); + } } } @@ -190,12 +223,12 @@ class _AuthCardState extends State { final deviceSize = MediaQuery.of(context).size; return Card( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.0), + borderRadius: BorderRadius.circular(15.0), ), elevation: 8.0, child: Container( - width: deviceSize.width * 0.75, - padding: const EdgeInsets.all(16.0), + width: deviceSize.width * 0.9, + padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 0.025 * deviceSize.height), child: Form( key: _formKey, child: SingleChildScrollView( @@ -205,9 +238,9 @@ class _AuthCardState extends State { TextFormField( key: const Key('inputUsername'), decoration: InputDecoration( - labelText: AppLocalizations.of(context).username, - errorMaxLines: 2, - ), + labelText: AppLocalizations.of(context).username, + errorMaxLines: 2, + prefixIcon: const Icon(Icons.account_circle)), autofillHints: const [AutofillHints.username], controller: _usernameController, textInputAction: TextInputAction.next, @@ -221,7 +254,7 @@ class _AuthCardState extends State { } return null; }, - inputFormatters: [FilteringTextInputFormatter.deny(new RegExp(r"\s\b|\b\s"))], + inputFormatters: [FilteringTextInputFormatter.deny(RegExp(r'\s\b|\b\s'))], onSaved: (value) { _authData['username'] = value!; }, @@ -229,7 +262,10 @@ class _AuthCardState extends State { if (_authMode == AuthMode.Signup) TextFormField( key: const Key('inputEmail'), - decoration: InputDecoration(labelText: AppLocalizations.of(context).email), + decoration: InputDecoration( + labelText: AppLocalizations.of(context).email, + prefixIcon: const Icon(Icons.mail), + ), autofillHints: const [AutofillHints.email], controller: _emailController, keyboardType: TextInputType.emailAddress, @@ -246,43 +282,63 @@ class _AuthCardState extends State { _authData['email'] = value!; }, ), - TextFormField( - key: const Key('inputPassword'), - decoration: InputDecoration(labelText: AppLocalizations.of(context).password), - autofillHints: const [AutofillHints.password], - obscureText: true, - controller: _passwordController, - textInputAction: TextInputAction.next, - validator: (value) { - if (value!.isEmpty || value.length < 8) { - return AppLocalizations.of(context).passwordTooShort; - } - return null; - }, - onFieldSubmitted: (value){ - _submit(context); - }, - onSaved: (value) { - _authData['password'] = value!; - }, - ), + StatefulBuilder(builder: (context, updateState) { + return TextFormField( + key: const Key('inputPassword'), + decoration: InputDecoration( + labelText: AppLocalizations.of(context).password, + prefixIcon: const Icon(Icons.password), + suffixIcon: IconButton( + icon: Icon(isObscure ? Icons.visibility_off : Icons.visibility), + onPressed: () { + isObscure = !isObscure; + updateState(() {}); + }, + ), + ), + autofillHints: const [AutofillHints.password], + obscureText: isObscure, + controller: _passwordController, + textInputAction: TextInputAction.next, + validator: (value) { + if (value!.isEmpty || value.length < 8) { + return AppLocalizations.of(context).passwordTooShort; + } + return null; + }, + onSaved: (value) { + _authData['password'] = value!; + }, + ); + }), if (_authMode == AuthMode.Signup) - TextFormField( - key: const Key('inputPassword2'), - decoration: - InputDecoration(labelText: AppLocalizations.of(context).confirmPassword), - controller: _password2Controller, - enabled: _authMode == AuthMode.Signup, - obscureText: true, - validator: _authMode == AuthMode.Signup - ? (value) { - if (value != _passwordController.text) { - return AppLocalizations.of(context).passwordsDontMatch; + StatefulBuilder(builder: (context, updateState) { + return TextFormField( + key: const Key('inputPassword2'), + decoration: InputDecoration( + labelText: AppLocalizations.of(context).confirmPassword, + prefixIcon: const Icon(Icons.password), + suffixIcon: IconButton( + icon: Icon(confirmIsObscure ? Icons.visibility_off : Icons.visibility), + onPressed: () { + confirmIsObscure = !confirmIsObscure; + updateState(() {}); + }, + ), + ), + controller: _password2Controller, + enabled: _authMode == AuthMode.Signup, + obscureText: confirmIsObscure, + validator: _authMode == AuthMode.Signup + ? (value) { + if (value != _passwordController.text) { + return AppLocalizations.of(context).passwordsDontMatch; + } + return null; } - return null; - } - : null, - ), + : null, + ); + }), // Off-stage widgets are kept in the tree, otherwise the server URL // would not be saved to _authData Offstage( @@ -338,37 +394,86 @@ class _AuthCardState extends State { const SizedBox( height: 20, ), - if (_isLoading) - const CircularProgressIndicator() - else - ElevatedButton( - key: const Key('actionButton'), - child: Text(_authMode == AuthMode.Login - ? AppLocalizations.of(context).login - : AppLocalizations.of(context).register), - onPressed: () { + GestureDetector( + onTap: () { + if (!_isLoading) { return _submit(context); - }, + } + }, + child: Container( + key: const Key('actionButton'), + width: double.infinity, + height: 0.065 * deviceSize.height, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30.0), + color: wgerPrimaryColor, + ), + child: Center( + child: _isLoading + ? const CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.white), + ) + : Text( + _authMode == AuthMode.Login + ? AppLocalizations.of(context).login + : AppLocalizations.of(context).register, + style: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + ), + ), + ), ), - TextButton( - key: const Key('toggleActionButton'), - child: Text( - _authMode == AuthMode.Login - ? AppLocalizations.of(context).registerInstead.toUpperCase() - : AppLocalizations.of(context).loginInstead.toUpperCase(), - ), - onPressed: _switchAuthMode, ), + SizedBox(height: 0.025 * deviceSize.height), + Builder( + key: const Key('toggleActionButton'), + builder: (context) { + final String text = _authMode != AuthMode.Signup + ? AppLocalizations.of(context).registerInstead + : AppLocalizations.of(context).loginInstead; + + return GestureDetector( + onTap: () { + _switchAuthMode(); + }, + child: Container( + color: Colors.transparent, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + text.substring(0, text.lastIndexOf('?') + 1), + ), + Text( + text.substring(text.lastIndexOf('?') + 1, text.length), + style: const TextStyle( + color: wgerPrimaryColor, + fontWeight: FontWeight.w700, + ), + ) + ], + ), + ), + ); + }, + ), + TextButton( - child: Text(_hideCustomServer - ? AppLocalizations.of(context).useCustomServer - : AppLocalizations.of(context).useDefaultServer), key: const Key('toggleCustomServerButton'), onPressed: () { setState(() { _hideCustomServer = !_hideCustomServer; }); }, + child: Text( + _hideCustomServer + ? AppLocalizations.of(context).useCustomServer + : AppLocalizations.of(context).useDefaultServer, + style: const TextStyle( + color: wgerPrimaryColor, + ), + ), ), ], ), diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart index c10ff0e0..4a4b1786 100644 --- a/lib/theme/theme.dart +++ b/lib/theme/theme.dart @@ -45,80 +45,96 @@ const materialSizes = { }; final ThemeData wgerTheme = ThemeData( - /* + /* * General stuff */ - primaryColor: wgerPrimaryColor, - scaffoldBackgroundColor: wgerBackground, + primaryColor: wgerPrimaryColor, + scaffoldBackgroundColor: wgerBackground, - // This makes the visual density adapt to the platform that you run - // the app on. For desktop platforms, the controls will be smaller and - // closer together (more dense) than on mobile platforms. - visualDensity: VisualDensity.adaptivePlatformDensity, + // This makes the visual density adapt to the platform that you run + // the app on. For desktop platforms, the controls will be smaller and + // closer together (more dense) than on mobile platforms. + visualDensity: VisualDensity.adaptivePlatformDensity, - // Show icons in the system's bar in light colors - appBarTheme: const AppBarTheme( - systemOverlayStyle: SystemUiOverlayStyle.dark, - color: wgerPrimaryColor, - ), + // Show icons in the system's bar in light colors + appBarTheme: const AppBarTheme( + systemOverlayStyle: SystemUiOverlayStyle.dark, + color: wgerPrimaryColor, + ), - /* + /* * Text theme */ - textTheme: TextTheme( - headline1: const TextStyle(fontFamily: 'OpenSansLight', color: Colors.black), - headline2: const TextStyle(fontFamily: 'OpenSansLight', color: Colors.black), - headline3: TextStyle( - fontSize: materialSizes['h3']! * 0.8, - fontFamily: 'OpenSansBold', - color: Colors.black, - ), - headline4: TextStyle( - fontSize: materialSizes['h4']! * 0.8, - fontFamily: 'OpenSansBold', - color: Colors.black, - ), - headline5: TextStyle( - fontSize: materialSizes['h5'], - fontFamily: 'OpenSansBold', - color: Colors.black, - ), - headline6: TextStyle( - fontSize: materialSizes['h6']! * 0.8, - fontFamily: 'OpenSansBold', - color: Colors.black, - ), + textTheme: TextTheme( + headline1: const TextStyle(fontFamily: 'OpenSansLight', color: Colors.black), + headline2: const TextStyle(fontFamily: 'OpenSansLight', color: Colors.black), + headline3: TextStyle( + fontSize: materialSizes['h3']! * 0.8, + fontFamily: 'OpenSansBold', + color: Colors.black, ), + headline4: TextStyle( + fontSize: materialSizes['h4']! * 0.8, + fontFamily: 'OpenSansBold', + color: Colors.black, + ), + headline5: TextStyle( + fontSize: materialSizes['h5'], + fontFamily: 'OpenSansBold', + color: Colors.black, + ), + headline6: TextStyle( + fontSize: materialSizes['h6']! * 0.8, + fontFamily: 'OpenSansBold', + color: Colors.black, + ), + ), - /* + /* * Button theme */ - textButtonTheme: TextButtonThemeData( - style: TextButton.styleFrom( - primary: wgerPrimaryButtonColor, - ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + primary: wgerPrimaryButtonColor, ), - outlinedButtonTheme: OutlinedButtonThemeData( - style: OutlinedButton.styleFrom( - foregroundColor: wgerPrimaryButtonColor, - visualDensity: VisualDensity.compact, - side: const BorderSide(color: wgerPrimaryButtonColor), - ), + ), + outlinedButtonTheme: OutlinedButtonThemeData( + style: OutlinedButton.styleFrom( + foregroundColor: wgerPrimaryButtonColor, + visualDensity: VisualDensity.compact, + side: const BorderSide(color: wgerPrimaryButtonColor), ), - elevatedButtonTheme: ElevatedButtonThemeData( - style: ElevatedButton.styleFrom( - backgroundColor: wgerPrimaryButtonColor, - ), + ), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: wgerPrimaryButtonColor, ), + ), - /* + /* * Forms, etc. */ - sliderTheme: const SliderThemeData( - activeTrackColor: wgerPrimaryButtonColor, - thumbColor: wgerPrimaryColor, + sliderTheme: const SliderThemeData( + activeTrackColor: wgerPrimaryButtonColor, + thumbColor: wgerPrimaryColor, + ), + colorScheme: ColorScheme.fromSwatch().copyWith(secondary: wgerSecondaryColor), + // Text Selection Theme + textSelectionTheme: TextSelectionThemeData( + cursorColor: wgerPrimaryColor, + selectionColor: wgerPrimaryColor.withOpacity(0.2), + selectionHandleColor: wgerPrimaryColor, + ), + // Text Fields Theme + inputDecorationTheme: InputDecorationTheme( + focusColor: wgerPrimaryColor, + iconColor: Colors.grey.shade600, + floatingLabelStyle: const TextStyle(color: wgerPrimaryColor), + focusedBorder: const UnderlineInputBorder( + borderSide: BorderSide(color: wgerPrimaryColor), ), - colorScheme: ColorScheme.fromSwatch().copyWith(secondary: wgerSecondaryColor)); + ), +); const wgerCalendarStyle = CalendarStyle( // Use `CalendarStyle` to customize the UI diff --git a/lib/widgets/core/about.dart b/lib/widgets/core/about.dart index bd72e9a9..d4b15e4a 100644 --- a/lib/widgets/core/about.dart +++ b/lib/widgets/core/about.dart @@ -22,99 +22,164 @@ import 'package:provider/provider.dart'; import 'package:wger/helpers/misc.dart'; import 'package:wger/providers/auth.dart'; -class WgerAboutListTile extends StatelessWidget { +class AboutPage extends StatefulWidget { + static String routeName = '/AboutPage'; + const AboutPage({Key? key}) : super(key: key); + + @override + State createState() => _AboutPageState(); +} + +class _AboutPageState extends State { @override Widget build(BuildContext context) { + final deviceSize = MediaQuery.of(context).size; final authProvider = Provider.of(context, listen: false); - return AboutListTile( - //dense: true, - icon: const Icon(Icons.info), - applicationName: 'wger', - applicationVersion: 'App: ${authProvider.applicationVersion!.version}\n' - 'Server: ${authProvider.serverVersion}', - applicationLegalese: '\u{a9} 2020 - 2021 contributors', - applicationIcon: Padding( - padding: const EdgeInsets.only(top: 10), - child: Image.asset( - 'assets/images/logo.png', - width: 60, + return Scaffold( + appBar: AppBar( + title: Text(AppLocalizations.of(context).aboutPageTitle), + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: double.infinity, + height: 0.125 * deviceSize.height, + // color: Colors.red, + child: Row( + // mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/logo.png', + width: 75, + ), + const SizedBox(width: 20), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'Wger', + style: TextStyle( + fontSize: 23, + fontWeight: FontWeight.w600, + ), + ), + Text('App: ${authProvider.applicationVersion!.version}\n' + 'Server: ${authProvider.serverVersion}'), + ], + ), + ], + ), + ), + Padding( + padding: EdgeInsets.only(left: 0.225 * deviceSize.width), + child: Text( + '\u{a9} 2020 - 2021 contributors', + style: Theme.of(context).textTheme.bodySmall, + ), + ), + SizedBox(height: 0.025 * deviceSize.height), + Text( + AppLocalizations.of(context).aboutDescription, + style: Theme.of(context).textTheme.bodyMedium!.copyWith(fontSize: 16), + ), + SizedBox(height: 0.04 * deviceSize.height), + ListTile( + leading: const Icon(Icons.code), + title: Text(AppLocalizations.of(context).aboutSourceTitle), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(AppLocalizations.of(context).aboutSourceText), + const Text( + 'https://github.com/wger-project', + style: TextStyle(color: Colors.blue), + ), + ], + ), + contentPadding: EdgeInsets.zero, + onTap: () async => launchURL('https://github.com/wger-project', context), + ), + const SizedBox(height: 10), + ListTile( + leading: const Icon(Icons.bug_report), + title: Text(AppLocalizations.of(context).aboutBugsTitle), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(AppLocalizations.of(context).aboutBugsText), + const Text( + 'https://github.com/wger-project/flutter/issues/new/choose', + style: TextStyle(color: Colors.blue), + ) + ], + ), + contentPadding: EdgeInsets.zero, + onTap: () async => + launchURL('https://github.com/wger-project/flutter/issues/new/choose', context), + ), + const SizedBox(height: 10), + ListTile( + leading: const Icon(Icons.chat), + title: Text(AppLocalizations.of(context).aboutContactUsTitle), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(AppLocalizations.of(context).aboutContactUsText), + const Text( + 'https://discord.gg/rPWFv6W', + style: TextStyle(color: Colors.blue), + ), + ], + ), + contentPadding: EdgeInsets.zero, + onTap: () async => launchURL('https://discord.gg/rPWFv6W', context), + ), + const SizedBox(height: 10), + ListTile( + leading: const Icon(Icons.translate), + title: Text(AppLocalizations.of(context).aboutTranslationTitle), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(AppLocalizations.of(context).aboutTranslationText), + const Text( + 'https://hosted.weblate.org/engage/wger/', + style: TextStyle(color: Colors.blue), + ), + ], + ), + contentPadding: EdgeInsets.zero, + onTap: () async => launchURL('https://hosted.weblate.org/engage/wger/', context), + ), + ListTile( + leading: const Icon(Icons.article), + title: const Text('View Licenses'), + contentPadding: EdgeInsets.zero, + onTap: () { + showLicensePage( + context: context, + applicationName: 'wger', + applicationVersion: 'App: ${authProvider.applicationVersion!.version}\n' + 'Server: ${authProvider.serverVersion}', + applicationLegalese: '\u{a9} 2020 - 2021 contributors', + applicationIcon: Padding( + padding: const EdgeInsets.only(top: 10), + child: Image.asset( + 'assets/images/logo.png', + width: 60, + ), + ), + ); + }, + ), + ], ), ), - - aboutBoxChildren: [ - const SizedBox(height: 10), - Text(AppLocalizations.of(context).aboutDescription), - const SizedBox(height: 20), - ListTile( - leading: const Icon(Icons.code), - title: Text(AppLocalizations.of(context).aboutSourceTitle), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(AppLocalizations.of(context).aboutSourceText), - const Text( - 'https://github.com/wger-project', - style: TextStyle(color: Colors.blue), - ), - ], - ), - contentPadding: EdgeInsets.zero, - onTap: () async => launchURL('https://github.com/wger-project', context), - ), - const SizedBox(height: 10), - ListTile( - leading: const Icon(Icons.bug_report), - title: Text(AppLocalizations.of(context).aboutBugsTitle), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(AppLocalizations.of(context).aboutBugsText), - const Text( - 'https://github.com/wger-project/flutter/issues/new/choose', - style: TextStyle(color: Colors.blue), - ) - ], - ), - contentPadding: EdgeInsets.zero, - onTap: () async => - launchURL('https://github.com/wger-project/flutter/issues/new/choose', context), - ), - const SizedBox(height: 10), - ListTile( - leading: const Icon(Icons.chat), - title: Text(AppLocalizations.of(context).aboutContactUsTitle), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(AppLocalizations.of(context).aboutContactUsText), - const Text( - 'https://discord.gg/rPWFv6W', - style: TextStyle(color: Colors.blue), - ), - ], - ), - contentPadding: EdgeInsets.zero, - onTap: () async => launchURL('https://discord.gg/rPWFv6W', context), - ), - const SizedBox(height: 10), - ListTile( - leading: const Icon(Icons.translate), - title: Text(AppLocalizations.of(context).aboutTranslationTitle), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(AppLocalizations.of(context).aboutTranslationText), - const Text( - 'https://hosted.weblate.org/engage/wger/', - style: TextStyle(color: Colors.blue), - ), - ], - ), - contentPadding: EdgeInsets.zero, - onTap: () async => launchURL('https://hosted.weblate.org/engage/wger/', context), - ), - ], ); } } diff --git a/lib/widgets/core/app_bar.dart b/lib/widgets/core/app_bar.dart index dcc9cca0..4dc28fbe 100644 --- a/lib/widgets/core/app_bar.dart +++ b/lib/widgets/core/app_bar.dart @@ -17,7 +17,6 @@ */ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:provider/provider.dart'; import 'package:wger/providers/auth.dart'; @@ -76,7 +75,13 @@ class MainAppBar extends StatelessWidget with PreferredSizeWidget { ); }, ), - WgerAboutListTile(), + ListTile( + leading: const Icon(Icons.info), + onTap: () { + Navigator.of(context).pushNamed(AboutPage.routeName); + }, + title: Text(AppLocalizations.of(context).aboutPageTitle), + ), const Divider(), ListTile( //dense: true, diff --git a/lib/widgets/gallery/overview.dart b/lib/widgets/gallery/overview.dart index b6fd6a27..8aac73f5 100644 --- a/lib/widgets/gallery/overview.dart +++ b/lib/widgets/gallery/overview.dart @@ -19,6 +19,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:wger/providers/gallery.dart'; @@ -35,76 +36,76 @@ class Gallery extends StatelessWidget { return Padding( padding: const EdgeInsets.all(5), - child: GridView.count( - crossAxisCount: 2, - mainAxisSpacing: 5, - crossAxisSpacing: 5, - children: List.generate(provider.images.length, (index) { - final currentImage = provider.images[index]; + child: MasonryGridView.count( + crossAxisCount: 2, + mainAxisSpacing: 5, + crossAxisSpacing: 5, + itemCount: provider.images.length, + itemBuilder: (context, index) { + final currentImage = provider.images[index]; - return GestureDetector( - onTap: () { - showModalBottomSheet( - builder: (context) => Material( - child: Container( - key: Key('image-${currentImage.id}-detail'), - padding: const EdgeInsets.all(10), - color: Colors.white, - child: Column( - children: [ - Text( - DateFormat.yMd(Localizations.localeOf(context).languageCode) - .format(currentImage.date), - style: Theme.of(context).textTheme.headline5, - ), - Expanded( - child: Image.network(currentImage.url!), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Text(currentImage.description), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - Provider.of(context, listen: false) - .deleteImage(currentImage); - Navigator.of(context).pop(); - }), - IconButton( - icon: const Icon(Icons.edit), - onPressed: () { - Navigator.pushNamed( - context, - FormScreen.routeName, - arguments: FormScreenArguments( - AppLocalizations.of(context).edit, - ImageForm(currentImage), - hasListView: true, - ), - ); - }), - ], - ) - ], + return GestureDetector( + onTap: () { + showModalBottomSheet( + builder: (context) => Material( + child: Container( + key: Key('image-${currentImage.id}-detail'), + padding: const EdgeInsets.all(10), + color: Colors.white, + child: Column( + children: [ + Text( + DateFormat.yMd(Localizations.localeOf(context).languageCode) + .format(currentImage.date), + style: Theme.of(context).textTheme.headline5, + ), + Expanded( + child: Image.network(currentImage.url!), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Text(currentImage.description), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + icon: const Icon(Icons.delete), + onPressed: () { + Provider.of(context, listen: false) + .deleteImage(currentImage); + Navigator.of(context).pop(); + }), + IconButton( + icon: const Icon(Icons.edit), + onPressed: () { + Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context).edit, + ImageForm(currentImage), + hasListView: true, + ), + ); + }), + ], + ) + ], + ), ), ), - ), - context: context, - ); - }, - child: FadeInImage( - key: Key('image-${currentImage.id}'), - placeholder: const AssetImage('assets/images/placeholder.png'), - image: NetworkImage(currentImage.url!), - fit: BoxFit.cover, - ), - ); - }), - ), + context: context, + ); + }, + child: FadeInImage( + key: Key('image-${currentImage.id}'), + placeholder: const AssetImage('assets/images/placeholder.png'), + image: NetworkImage(currentImage.url!), + fit: BoxFit.cover, + ), + ); + }), ); } } diff --git a/lib/widgets/measurements/categories_card.dart b/lib/widgets/measurements/categories_card.dart index 57cb9d7c..772a02dd 100644 --- a/lib/widgets/measurements/categories_card.dart +++ b/lib/widgets/measurements/categories_card.dart @@ -11,7 +11,7 @@ class CategoriesCard extends StatelessWidget { MeasurementCategory currentCategory; double? elevation; - CategoriesCard(this.currentCategory,{this.elevation}); + CategoriesCard(this.currentCategory, {this.elevation}); @override Widget build(BuildContext context) { @@ -31,9 +31,7 @@ class CategoriesCard extends StatelessWidget { padding: const EdgeInsets.all(10), height: 220, child: MeasurementChartWidget( - currentCategory.entries - .map((e) => MeasurementChartEntry(e.value, e.date)) - .toList(), + currentCategory.entries.map((e) => MeasurementChartEntry(e.value, e.date)).toList(), unit: currentCategory.unit, ), ), diff --git a/lib/widgets/workouts/log.dart b/lib/widgets/workouts/log.dart index 15f7e809..c0fd30c5 100644 --- a/lib/widgets/workouts/log.dart +++ b/lib/widgets/workouts/log.dart @@ -21,32 +21,32 @@ import 'package:flutter/widgets.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:wger/helpers/ui.dart'; -import 'package:wger/models/exercises/exercise.dart'; +import 'package:wger/models/exercises/base.dart'; import 'package:wger/models/workouts/log.dart'; import 'package:wger/models/workouts/session.dart'; import 'package:wger/providers/workout_plans.dart'; import 'package:wger/widgets/workouts/charts.dart'; class ExerciseLogChart extends StatelessWidget { - final Exercise _exercise; + final ExerciseBase _base; final DateTime _currentDate; - const ExerciseLogChart(this._exercise, this._currentDate); + const ExerciseLogChart(this._base, this._currentDate); @override Widget build(BuildContext context) { - final _workoutPlansData = Provider.of(context, listen: false); - final _workout = _workoutPlansData.currentPlan; + final workoutPlansData = Provider.of(context, listen: false); + final workout = workoutPlansData.currentPlan; - Future> _getChartEntries(BuildContext context) async { - return _workoutPlansData.fetchLogData(_workout!, _exercise); + Future> getChartEntries(BuildContext context) async { + return workoutPlansData.fetchLogData(workout!, _base); } return FutureBuilder( - future: _getChartEntries(context), + future: getChartEntries(context), builder: (context, AsyncSnapshot> snapshot) => SizedBox( height: 150, - child: snapshot.connectionState == ConnectionState.waiting && snapshot.hasData + child: snapshot.connectionState == ConnectionState.waiting ? const Center(child: CircularProgressIndicator()) : LogChartWidget(snapshot.data!, _currentDate), ), @@ -57,7 +57,7 @@ class ExerciseLogChart extends StatelessWidget { class DayLogWidget extends StatefulWidget { final DateTime _date; final WorkoutSession? _session; - final Map> _exerciseData; + final Map> _exerciseData; const DayLogWidget(this._date, this._exerciseData, this._session); @@ -81,17 +81,18 @@ class _DayLogWidgetState extends State { style: Theme.of(context).textTheme.headline5, ), if (widget._session != null) const Text('Session data here'), - ...widget._exerciseData.keys.map((exercise) { + ...widget._exerciseData.keys.map((base) { + final exercise = base.getExercise(Localizations.localeOf(context).languageCode); return Column( children: [ - if (widget._exerciseData[exercise]!.isNotEmpty) + if (widget._exerciseData[base]!.isNotEmpty) Text( exercise.name, style: Theme.of(context).textTheme.headline6, ) else Container(), - ...widget._exerciseData[exercise]! + ...widget._exerciseData[base]! .map( (log) => Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -108,7 +109,7 @@ class _DayLogWidgetState extends State { ), ) .toList(), - ExerciseLogChart(exercise, widget._date), + ExerciseLogChart(base, widget._date), const SizedBox(height: 30), ], ); diff --git a/lib/widgets/workouts/workout_logs.dart b/lib/widgets/workouts/workout_logs.dart index 77bab60c..1147c3c5 100644 --- a/lib/widgets/workouts/workout_logs.dart +++ b/lib/widgets/workouts/workout_logs.dart @@ -20,7 +20,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:wger/helpers/consts.dart'; -import 'package:wger/models/exercises/exercise.dart'; +import 'package:wger/models/exercises/base.dart'; import 'package:wger/models/workouts/log.dart'; import 'package:wger/models/workouts/session.dart'; import 'package:wger/models/workouts/workout_plan.dart'; @@ -95,7 +95,7 @@ class _WorkoutLogsState extends State { class WorkoutLogEvent { final DateTime dateTime; final WorkoutSession? session; - final Map> exercises; + final Map> exercises; WorkoutLogEvent(this.dateTime, this.session, this.exercises); } diff --git a/lib/widgets/workouts/workout_plan_detail.dart b/lib/widgets/workouts/workout_plan_detail.dart index fe9f0672..cf0fbd6e 100644 --- a/lib/widgets/workouts/workout_plan_detail.dart +++ b/lib/widgets/workouts/workout_plan_detail.dart @@ -40,10 +40,6 @@ class _WorkoutPlanDetailState extends State { children: [ if (widget._workoutPlan.days.isNotEmpty) ToggleButtons( - children: const [ - Icon(Icons.table_chart_outlined), - Icon(Icons.show_chart), - ], renderBorder: false, onPressed: (int index) { if (index == 1) { @@ -51,6 +47,10 @@ class _WorkoutPlanDetailState extends State { } }, isSelected: const [true, false], + children: const [ + Icon(Icons.table_chart_outlined), + Icon(Icons.show_chart), + ], ), if (widget._workoutPlan.description != '') Padding( diff --git a/pubspec.lock b/pubspec.lock index 05ddda09..fa0d7a01 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -84,7 +84,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.3.2" build_runner_core: dependency: transitive description: @@ -334,7 +334,7 @@ packages: name: flutter_calendar_carousel url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" + version: "2.4.1" flutter_driver: dependency: transitive description: flutter @@ -395,7 +395,7 @@ packages: name: flutter_launcher_icons url: "https://pub.dartlang.org" source: hosted - version: "0.10.0" + version: "0.11.0" flutter_layout_grid: dependency: transitive description: @@ -429,6 +429,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.7" + flutter_staggered_grid_view: + dependency: "direct main" + description: + name: flutter_staggered_grid_view + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.2" flutter_svg: dependency: "direct main" description: @@ -466,7 +473,7 @@ packages: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "3.1.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -595,7 +602,7 @@ packages: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.5.0" + version: "6.5.4" klizma: dependency: transitive description: @@ -672,7 +679,7 @@ packages: name: multi_select_flutter url: "https://pub.dartlang.org" source: hosted - version: "4.1.2" + version: "4.1.3" nested: dependency: transitive description: @@ -791,7 +798,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.3" + version: "6.0.4" pub_semver: dependency: transitive description: @@ -971,7 +978,7 @@ packages: name: table_calendar url: "https://pub.dartlang.org" source: hosted - version: "3.0.7" + version: "3.0.8" term_glyph: dependency: transitive description: @@ -1013,7 +1020,7 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.1.5" + version: "6.1.7" url_launcher_android: dependency: transitive description: @@ -1090,7 +1097,7 @@ packages: name: video_player url: "https://pub.dartlang.org" source: hosted - version: "2.4.7" + version: "2.4.8" video_player_android: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a25378ba..4a6c3a4d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,7 +37,7 @@ dependencies: collection: ^1.15.0-nullsafety.4 cupertino_icons: ^1.0.5 equatable: ^2.0.5 - flutter_calendar_carousel: ^2.4.0 + flutter_calendar_carousel: ^2.4.1 flutter_html: ^2.1.2 flutter_typeahead: ^4.1.1 font_awesome_flutter: ^10.2.1 @@ -47,15 +47,16 @@ dependencies: json_annotation: ^4.7.0 version: ^3.0.2 package_info: ^2.0.2 - provider: ^6.0.3 + provider: ^6.0.4 rive: ^0.9.1 shared_preferences: ^2.0.15 - table_calendar: ^3.0.7 - url_launcher: ^6.1.5 + table_calendar: ^3.0.8 + url_launcher: ^6.1.7 flutter_barcode_scanner: ^2.0.0 - video_player: ^2.4.7 + video_player: ^2.4.8 + flutter_staggered_grid_view: ^0.6.2 carousel_slider: ^4.1.1 - multi_select_flutter: ^4.1.2 + multi_select_flutter: ^4.1.3 flutter_svg: ^0.23.0+1 dev_dependencies: @@ -63,9 +64,9 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter - build_runner: ^2.2.1 - flutter_launcher_icons: ^0.10.0 - json_serializable: ^6.5.0 + build_runner: ^2.3.2 + flutter_launcher_icons: ^0.11.0 + json_serializable: ^6.5.4 mockito: ^5.3.2 network_image_mock: ^2.1.1 flutter_lints: ^2.0.1 diff --git a/test/auth/auth_provider_test.dart b/test/auth/auth_provider_test.dart index 8dc53fd9..93c280f6 100644 --- a/test/auth/auth_provider_test.dart +++ b/test/auth/auth_provider_test.dart @@ -15,6 +15,8 @@ void main() { path: 'api/v2/min-app-version/', ); + final testMetadata = {'wger.check_min_app_version': 'true'}; + setUp(() { mockClient = MockClient(); authProvider = AuthProvider(mockClient, false); @@ -25,8 +27,8 @@ void main() { test('app version higher than min version', () async { // arrange - when(mockClient.get(tVersionUri)).thenAnswer((_) => Future(() => Response('1.2.0', 200))); - final updateNeeded = await authProvider.applicationUpdateRequired('1.3.0'); + when(mockClient.get(tVersionUri)).thenAnswer((_) => Future(() => Response('"1.2.0"', 200))); + final updateNeeded = await authProvider.applicationUpdateRequired('1.3.0', testMetadata); // assert expect(updateNeeded, false); @@ -34,8 +36,8 @@ void main() { test('app version higher than min version', () async { // arrange - when(mockClient.get(tVersionUri)).thenAnswer((_) => Future(() => Response('1.3', 200))); - final updateNeeded = await authProvider.applicationUpdateRequired('1.1'); + when(mockClient.get(tVersionUri)).thenAnswer((_) => Future(() => Response('"1.3"', 200))); + final updateNeeded = await authProvider.applicationUpdateRequired('1.1', testMetadata); // assert expect(updateNeeded, true); @@ -43,8 +45,8 @@ void main() { test('app version higher than min version', () async { // arrange - when(mockClient.get(tVersionUri)).thenAnswer((_) => Future(() => Response('1.3.0', 200))); - final updateNeeded = await authProvider.applicationUpdateRequired('1.1'); + when(mockClient.get(tVersionUri)).thenAnswer((_) => Future(() => Response('"1.3.0"', 200))); + final updateNeeded = await authProvider.applicationUpdateRequired('1.1', testMetadata); // assert expect(updateNeeded, true); @@ -52,11 +54,11 @@ void main() { test('app version equal as min version', () async { // arrange - when(mockClient.get(tVersionUri)).thenAnswer((_) => Future(() => Response('1.3.0', 200))); - final updateNeeded = await authProvider.applicationUpdateRequired('1.3.0'); + when(mockClient.get(tVersionUri)).thenAnswer((_) => Future(() => Response('"1.3.0"', 200))); + final updateNeeded = await authProvider.applicationUpdateRequired('1.3.0', testMetadata); // assert - expect(updateNeeded, true); //!!! + expect(updateNeeded, false); }); }); } diff --git a/test/auth/auth_screen_test.dart b/test/auth/auth_screen_test.dart index 48a09181..b5b80433 100644 --- a/test/auth/auth_screen_test.dart +++ b/test/auth/auth_screen_test.dart @@ -64,7 +64,7 @@ void main() { expect(find.text('WGER'), findsOneWidget); // Verify that the correct buttons and input fields are shown: login - expect(find.text('REGISTER INSTEAD'), findsOneWidget); + expect(find.text('Register now'), findsOneWidget); expect(find.text('LOGIN INSTEAD'), findsNothing); // Check that the correct widgets are shown @@ -87,7 +87,7 @@ void main() { // Rebuild the widget after the state has changed. await tester.pump(); - expect(find.text('REGISTER INSTEAD'), findsNothing); + expect(find.text('Register now'), findsNothing); expect(find.text('LOGIN INSTEAD'), findsOneWidget); // Check that the correct widgets are shown diff --git a/test/exercises/exercise_provider_test.dart b/test/exercises/exercise_provider_test.dart index a7def15d..eabb9e49 100644 --- a/test/exercises/exercise_provider_test.dart +++ b/test/exercises/exercise_provider_test.dart @@ -239,8 +239,8 @@ void main() { test('A muscle is selected with no search term. Should not find results', () async { // arrange - Filters tFilters = filters.copyWith( - exerciseCategories: filters.exerciseCategories.copyWith(items: {data.tCategory4: true}), + final Filters tFilters = filters.copyWith( + exerciseCategories: filters.exerciseCategories.copyWith(items: {data.tCategory5: true}), ); // act diff --git a/test/exercises/exercises_detail_widget_test.dart b/test/exercises/exercises_detail_widget_test.dart index ca2f1ebc..f5a0f59a 100644 --- a/test/exercises/exercises_detail_widget_test.dart +++ b/test/exercises/exercises_detail_widget_test.dart @@ -53,7 +53,6 @@ void main() { expect(find.text('Bench'), findsOneWidget, reason: 'Equipment'); expect(find.text('Dumbbell'), findsOneWidget, reason: 'Equipment'); - debugDumpApp(); expect(find.text('Muscles'), findsNWidgets(2), reason: 'One header, one sub header'); expect(find.text('Flutterus maximus (NOT TRANSLATED)'), findsOneWidget, reason: 'Muscles'); expect(find.text('Biceps brachii (Biceps)'), findsOneWidget, reason: 'Muscles'); @@ -66,7 +65,7 @@ void main() { ); expect(find.text('Gluteus maximus'), findsOneWidget, reason: 'Secondary muscles'); expect(find.text('Description'), findsOneWidget, reason: 'Description header'); - expect(find.text('Lorem ipsum etc'), findsOneWidget, reason: 'Description'); + expect(find.text('add clever text'), findsOneWidget, reason: 'Description'); expect(find.text('Variations'), findsNothing); }); } diff --git a/test/exercises/model_exercisebase_test.dart b/test/exercises/model_exercisebase_test.dart index 2529ec83..ba0764c4 100644 --- a/test/exercises/model_exercisebase_test.dart +++ b/test/exercises/model_exercisebase_test.dart @@ -6,16 +6,16 @@ void main() { group('Model tests', () { test('test getExercise', () async { // arrange and act - final base = getTestExerciseBases()[0]; + final base = getTestExerciseBases()[1]; // assert - expect(base.getExercise('en').id, 2); - expect(base.getExercise('en-UK').id, 2); - expect(base.getExercise('de').id, 1); - expect(base.getExercise('de-AT').id, 1); + expect(base.getExercise('en').id, 5); + expect(base.getExercise('en-UK').id, 5); + expect(base.getExercise('de').id, 4); + expect(base.getExercise('de-AT').id, 4); expect(base.getExercise('fr').id, 3); expect(base.getExercise('fr-FR').id, 3); - expect(base.getExercise('pt').id, 2); // English again + expect(base.getExercise('pt').id, 5); // English again }); }); } diff --git a/test/gallery/gallery_screen_test.dart b/test/gallery/gallery_screen_test.dart index f75f4705..dfb08a16 100644 --- a/test/gallery/gallery_screen_test.dart +++ b/test/gallery/gallery_screen_test.dart @@ -18,6 +18,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; @@ -57,7 +58,8 @@ void main() { testWidgets('Test the widgets on the gallery screen', (WidgetTester tester) async { await mockNetworkImagesFor(() => tester.pumpWidget(createScreen())); - expect(find.byType(GestureDetector), findsNWidgets(4)); + expect(find.byType(SliverMasonryGrid), findsOneWidget); + expect(find.byType(GestureDetector, skipOffstage: false), findsNWidgets(4)); }); testWidgets('Test opening the form for an existing image', (WidgetTester tester) async { diff --git a/test/nutrition/nutritional_plan_screen_test.dart b/test/nutrition/nutritional_plan_screen_test.dart index 796f11af..407514cd 100644 --- a/test/nutrition/nutritional_plan_screen_test.dart +++ b/test/nutrition/nutritional_plan_screen_test.dart @@ -69,7 +69,7 @@ void main() { await tester.pumpAndSettle(); // PLan description - expect(find.text('lots and lots of mass'), findsOneWidget); + expect(find.text('Less fat, more protein'), findsOneWidget); // Ingredients expect(find.text('100g Water'), findsOneWidget); diff --git a/test/workout/gym_mode_screen_test.dart b/test/workout/gym_mode_screen_test.dart index 175c2b36..d06aa7b6 100644 --- a/test/workout/gym_mode_screen_test.dart +++ b/test/workout/gym_mode_screen_test.dart @@ -48,8 +48,7 @@ void main() { final bases = getTestExerciseBases(); when(mockExerciseProvider.findExerciseBaseById(1)).thenReturn(bases[0]); - when(mockExerciseProvider.findExerciseBaseById(2)).thenReturn(bases[1]); - when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(bases[2]); + when(mockExerciseProvider.findExerciseBaseById(6)).thenReturn(bases[5]); return ChangeNotifierProvider( create: (context) => WorkoutPlansProvider( @@ -92,7 +91,8 @@ void main() { // expect(find.byType(StartPage), findsOneWidget); expect(find.text('Your workout today'), findsOneWidget); - expect(find.text('test exercise 2'), findsOneWidget); + expect(find.text('Bench press'), findsOneWidget); + expect(find.text('Side raises'), findsOneWidget); expect(find.byIcon(Icons.close), findsOneWidget); expect(find.byIcon(Icons.menu), findsOneWidget); expect(find.byIcon(Icons.chevron_left), findsNothing); @@ -101,9 +101,9 @@ void main() { await tester.pumpAndSettle(); // - // Exercise overview page + // Bench press - exercise overview page // - expect(find.text('test exercise 2'), findsOneWidget); + expect(find.text('Bench press'), findsOneWidget); expect(find.byType(ExerciseOverview), findsOneWidget); expect(find.byIcon(Icons.close), findsOneWidget); expect(find.byIcon(Icons.menu), findsOneWidget); @@ -113,15 +113,15 @@ void main() { await tester.pumpAndSettle(); // - // Log + // Bench press - Log // - expect(find.text('test exercise 2'), findsOneWidget); + expect(find.text('Bench press'), findsOneWidget); expect(find.byType(LogPage), findsOneWidget); expect(find.byType(Form), findsOneWidget); expect(find.byType(ListTile), findsNWidgets(3), reason: 'Two logs and the switch tile'); expect(find.text('10 × 10 kg (1.5 RiR)'), findsOneWidget); expect(find.text('12 × 10 kg (2 RiR)'), findsOneWidget); - expect(find.text('Important to do exercises correctly'), findsOneWidget, reason: 'Set comment'); + expect(find.text('Make sure to warm up'), findsOneWidget, reason: 'Set comment'); expect(find.byIcon(Icons.close), findsOneWidget); expect(find.byIcon(Icons.menu), findsOneWidget); expect(find.byIcon(Icons.chevron_left), findsOneWidget); @@ -144,9 +144,9 @@ void main() { await tester.pumpAndSettle(); // - // Pause + // Bench press - pause // - expect(find.text('0:01'), findsOneWidget); + expect(find.text('Pause'), findsOneWidget); expect(find.byType(TimerWidget), findsOneWidget); expect(find.byIcon(Icons.close), findsOneWidget); expect(find.byIcon(Icons.menu), findsOneWidget); @@ -156,9 +156,9 @@ void main() { await tester.pumpAndSettle(); // - // Log + // Bench press - log // - expect(find.text('test exercise 2'), findsOneWidget); + expect(find.text('Bench press'), findsOneWidget); expect(find.byType(LogPage), findsOneWidget); expect(find.byType(Form), findsOneWidget); await tester.drag(find.byType(LogPage), const Offset(-500.0, 0.0)); @@ -167,7 +167,7 @@ void main() { // // Pause // - expect(find.text('0:01'), findsOneWidget); + expect(find.text('Pause'), findsOneWidget); expect(find.byType(TimerWidget), findsOneWidget); expect(find.byIcon(Icons.chevron_left), findsOneWidget); expect(find.byIcon(Icons.close), findsOneWidget); @@ -175,6 +175,42 @@ void main() { await tester.tap(find.byIcon(Icons.chevron_right)); await tester.pumpAndSettle(); + // + // Side raises - exercise overview page + // + expect(find.text('Side raises'), findsOneWidget); + expect(find.byType(ExerciseOverview), findsOneWidget); + await tester.tap(find.byIcon(Icons.chevron_right)); + await tester.pumpAndSettle(); + + // + // Side raises - log + // + expect(find.byType(LogPage), findsOneWidget); + await tester.tap(find.byIcon(Icons.chevron_right)); + await tester.pumpAndSettle(); + + // + // Side raises - timer + // + expect(find.byType(TimerWidget), findsOneWidget); + await tester.tap(find.byIcon(Icons.chevron_right)); + await tester.pumpAndSettle(); + + // + // Side raises - log + // + expect(find.byType(LogPage), findsOneWidget); + await tester.tap(find.byIcon(Icons.chevron_right)); + await tester.pumpAndSettle(); + + // + // Side raises - timer + // + expect(find.byType(TimerWidget), findsOneWidget); + await tester.tap(find.byIcon(Icons.chevron_right)); + await tester.pumpAndSettle(); + // // Session // diff --git a/test/workout/set_model_test.dart b/test/workout/set_model_test.dart index 9a7234a5..dfd4b0e8 100644 --- a/test/workout/set_model_test.dart +++ b/test/workout/set_model_test.dart @@ -27,7 +27,7 @@ void main() { final set = workout.days.first.sets.first; final exercise1 = set.exerciseBasesObj[0]; - expect(set.getSmartTextRepr(exercise1), '2 × 10 kg (2 RiR)'); + expect(set.getSmartTextRepr(exercise1), '6 × 80 kg (3 RiR)'); }); }); } diff --git a/test/workout/weight_unit_form_widget_test.dart b/test/workout/weight_unit_form_widget_test.dart index d956bbc1..8fbe987a 100644 --- a/test/workout/weight_unit_form_widget_test.dart +++ b/test/workout/weight_unit_form_widget_test.dart @@ -19,16 +19,19 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:wger/models/workouts/setting.dart'; import 'package:wger/models/workouts/weight_unit.dart'; +import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/workout_plans.dart'; import 'package:wger/screens/workout_plan_screen.dart'; import 'package:wger/widgets/workouts/forms.dart'; import './workout_form_test.mocks.dart'; +@GenerateMocks([BodyWeightProvider]) void main() { var mockWorkoutPlans = MockWorkoutPlansProvider(); diff --git a/test/workout/weight_unit_form_widget_test.mocks.dart b/test/workout/weight_unit_form_widget_test.mocks.dart new file mode 100644 index 00000000..b35c3408 --- /dev/null +++ b/test/workout/weight_unit_form_widget_test.mocks.dart @@ -0,0 +1,326 @@ +// Mocks generated by Mockito 5.3.2 from annotations +// in wger/test/workout/weight_unit_form_widget_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i6; +import 'dart:ui' as _i7; + +import 'package:http/http.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; +import 'package:wger/models/body_weight/weight_entry.dart' as _i4; +import 'package:wger/providers/auth.dart' as _i2; +import 'package:wger/providers/body_weight.dart' as _i5; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeAuthProvider_0 extends _i1.SmartFake implements _i2.AuthProvider { + _FakeAuthProvider_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeClient_1 extends _i1.SmartFake implements _i3.Client { + _FakeClient_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeWeightEntry_2 extends _i1.SmartFake implements _i4.WeightEntry { + _FakeWeightEntry_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeUri_3 extends _i1.SmartFake implements Uri { + _FakeUri_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeResponse_4 extends _i1.SmartFake implements _i3.Response { + _FakeResponse_4( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [BodyWeightProvider]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockBodyWeightProvider extends _i1.Mock implements _i5.BodyWeightProvider { + MockBodyWeightProvider() { + _i1.throwOnMissingStub(this); + } + + @override + List<_i4.WeightEntry> get items => (super.noSuchMethod( + Invocation.getter(#items), + returnValue: <_i4.WeightEntry>[], + ) as List<_i4.WeightEntry>); + @override + _i2.AuthProvider get auth => (super.noSuchMethod( + Invocation.getter(#auth), + returnValue: _FakeAuthProvider_0( + this, + Invocation.getter(#auth), + ), + ) as _i2.AuthProvider); + @override + set auth(_i2.AuthProvider? _auth) => super.noSuchMethod( + Invocation.setter( + #auth, + _auth, + ), + returnValueForMissingStub: null, + ); + @override + _i3.Client get client => (super.noSuchMethod( + Invocation.getter(#client), + returnValue: _FakeClient_1( + this, + Invocation.getter(#client), + ), + ) as _i3.Client); + @override + set client(_i3.Client? _client) => super.noSuchMethod( + Invocation.setter( + #client, + _client, + ), + returnValueForMissingStub: null, + ); + @override + bool get hasListeners => (super.noSuchMethod( + Invocation.getter(#hasListeners), + returnValue: false, + ) as bool); + @override + void clear() => super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValueForMissingStub: null, + ); + @override + _i4.WeightEntry findById(int? id) => (super.noSuchMethod( + Invocation.method( + #findById, + [id], + ), + returnValue: _FakeWeightEntry_2( + this, + Invocation.method( + #findById, + [id], + ), + ), + ) as _i4.WeightEntry); + @override + _i4.WeightEntry? findByDate(DateTime? date) => (super.noSuchMethod(Invocation.method( + #findByDate, + [date], + )) as _i4.WeightEntry?); + @override + _i6.Future> fetchAndSetEntries() => (super.noSuchMethod( + Invocation.method( + #fetchAndSetEntries, + [], + ), + returnValue: _i6.Future>.value(<_i4.WeightEntry>[]), + ) as _i6.Future>); + @override + _i6.Future<_i4.WeightEntry> addEntry(_i4.WeightEntry? entry) => (super.noSuchMethod( + Invocation.method( + #addEntry, + [entry], + ), + returnValue: _i6.Future<_i4.WeightEntry>.value(_FakeWeightEntry_2( + this, + Invocation.method( + #addEntry, + [entry], + ), + )), + ) as _i6.Future<_i4.WeightEntry>); + @override + _i6.Future editEntry(_i4.WeightEntry? entry) => (super.noSuchMethod( + Invocation.method( + #editEntry, + [entry], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override + _i6.Future deleteEntry(int? id) => (super.noSuchMethod( + Invocation.method( + #deleteEntry, + [id], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override + Map getDefaultHeaders({dynamic includeAuth = false}) => (super.noSuchMethod( + Invocation.method( + #getDefaultHeaders, + [], + {#includeAuth: includeAuth}, + ), + returnValue: {}, + ) as Map); + @override + Uri makeUrl( + String? path, { + int? id, + String? objectMethod, + Map? query, + }) => + (super.noSuchMethod( + Invocation.method( + #makeUrl, + [path], + { + #id: id, + #objectMethod: objectMethod, + #query: query, + }, + ), + returnValue: _FakeUri_3( + this, + Invocation.method( + #makeUrl, + [path], + { + #id: id, + #objectMethod: objectMethod, + #query: query, + }, + ), + ), + ) as Uri); + @override + _i6.Future> fetch(Uri? uri) => (super.noSuchMethod( + Invocation.method( + #fetch, + [uri], + ), + returnValue: _i6.Future>.value({}), + ) as _i6.Future>); + @override + _i6.Future> post( + Map? data, + Uri? uri, + ) => + (super.noSuchMethod( + Invocation.method( + #post, + [ + data, + uri, + ], + ), + returnValue: _i6.Future>.value({}), + ) as _i6.Future>); + @override + _i6.Future> patch( + Map? data, + Uri? uri, + ) => + (super.noSuchMethod( + Invocation.method( + #patch, + [ + data, + uri, + ], + ), + returnValue: _i6.Future>.value({}), + ) as _i6.Future>); + @override + _i6.Future<_i3.Response> deleteRequest( + String? url, + int? id, + ) => + (super.noSuchMethod( + Invocation.method( + #deleteRequest, + [ + url, + id, + ], + ), + returnValue: _i6.Future<_i3.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #deleteRequest, + [ + url, + id, + ], + ), + )), + ) as _i6.Future<_i3.Response>); + @override + void addListener(_i7.VoidCallback? listener) => super.noSuchMethod( + Invocation.method( + #addListener, + [listener], + ), + returnValueForMissingStub: null, + ); + @override + void removeListener(_i7.VoidCallback? listener) => super.noSuchMethod( + Invocation.method( + #removeListener, + [listener], + ), + returnValueForMissingStub: null, + ); + @override + void dispose() => super.noSuchMethod( + Invocation.method( + #dispose, + [], + ), + returnValueForMissingStub: null, + ); + @override + void notifyListeners() => super.noSuchMethod( + Invocation.method( + #notifyListeners, + [], + ), + returnValueForMissingStub: null, + ); +} diff --git a/test/workout/workout_form_test.mocks.dart b/test/workout/workout_form_test.mocks.dart index 7f967cd8..0cff6922 100644 --- a/test/workout/workout_form_test.mocks.dart +++ b/test/workout/workout_form_test.mocks.dart @@ -4,11 +4,12 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i13; -import 'dart:ui' as _i15; +import 'dart:ui' as _i16; import 'package:http/http.dart' as _i5; import 'package:mockito/mockito.dart' as _i1; -import 'package:wger/models/exercises/exercise.dart' as _i14; +import 'package:wger/models/exercises/base.dart' as _i14; +import 'package:wger/models/exercises/exercise.dart' as _i15; import 'package:wger/models/workouts/day.dart' as _i7; import 'package:wger/models/workouts/log.dart' as _i11; import 'package:wger/models/workouts/repetition_unit.dart' as _i3; @@ -354,14 +355,14 @@ class MockWorkoutPlansProvider extends _i1.Mock implements _i12.WorkoutPlansProv @override _i13.Future> fetchLogData( _i6.WorkoutPlan? workout, - _i14.Exercise? exercise, + _i14.ExerciseBase? base, ) => (super.noSuchMethod( Invocation.method( #fetchLogData, [ workout, - exercise, + base, ], ), returnValue: _i13.Future>.value({}), @@ -485,7 +486,7 @@ class MockWorkoutPlansProvider extends _i1.Mock implements _i12.WorkoutPlansProv @override _i13.Future fetchSmartText( _i8.Set? workoutSet, - _i14.Exercise? exercise, + _i15.Exercise? exercise, ) => (super.noSuchMethod( Invocation.method( @@ -667,7 +668,7 @@ class MockWorkoutPlansProvider extends _i1.Mock implements _i12.WorkoutPlansProv )), ) as _i13.Future<_i5.Response>); @override - void addListener(_i15.VoidCallback? listener) => super.noSuchMethod( + void addListener(_i16.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #addListener, [listener], @@ -675,7 +676,7 @@ class MockWorkoutPlansProvider extends _i1.Mock implements _i12.WorkoutPlansProv returnValueForMissingStub: null, ); @override - void removeListener(_i15.VoidCallback? listener) => super.noSuchMethod( + void removeListener(_i16.VoidCallback? listener) => super.noSuchMethod( Invocation.method( #removeListener, [listener], diff --git a/test/workout/workout_plan_screen_test.dart b/test/workout/workout_plan_screen_test.dart index 7f909d98..4fc31fc5 100644 --- a/test/workout/workout_plan_screen_test.dart +++ b/test/workout/workout_plan_screen_test.dart @@ -61,9 +61,9 @@ void main() { await tester.tap(find.byType(TextButton)); await tester.pumpAndSettle(); - expect(find.text('test workout 1'), findsOneWidget); - expect(find.text('test day 1'), findsOneWidget); - expect(find.text('test day 2'), findsOneWidget); + expect(find.text('3 day workout'), findsOneWidget); + expect(find.text('chest, shoulders'), findsOneWidget); + expect(find.text('legs'), findsOneWidget); expect(find.byType(Dismissible), findsNWidgets(2)); }); diff --git a/test_data/body_weight.dart b/test_data/body_weight.dart index 409a1abd..8cec705c 100644 --- a/test_data/body_weight.dart +++ b/test_data/body_weight.dart @@ -20,3 +20,7 @@ import 'package:wger/models/body_weight/weight_entry.dart'; final weightEntry1 = WeightEntry(id: 1, weight: 80, date: DateTime(2021, 01, 01)); final weightEntry2 = WeightEntry(id: 2, weight: 81, date: DateTime(2021, 01, 10)); + +List getWeightEntries() { + return [weightEntry1, weightEntry2]; +} diff --git a/test_data/exercises.dart b/test_data/exercises.dart index 88257463..7b891d39 100644 --- a/test_data/exercises.dart +++ b/test_data/exercises.dart @@ -35,12 +35,13 @@ const tCategory1 = ExerciseCategory(id: 1, name: 'Arms'); const tCategory2 = ExerciseCategory(id: 2, name: 'Legs'); const tCategory3 = ExerciseCategory(id: 3, name: 'Abs'); const tCategory4 = ExerciseCategory(id: 4, name: 'Shoulders'); +const tCategory5 = ExerciseCategory(id: 5, name: 'Calves'); const tEquipment1 = Equipment(id: 1, name: 'Bench'); const tEquipment2 = Equipment(id: 1, name: 'Dumbbell'); const tEquipment3 = Equipment(id: 2, name: 'Matress'); -final tBase1 = ExerciseBase( +final benchPress = ExerciseBase( id: 1, uuid: '364f196c-881b-4839-8bfc-9e8f651521b6', creationDate: DateTime(2021, 09, 01), @@ -51,7 +52,7 @@ final tBase1 = ExerciseBase( musclesSecondary: const [tMuscle3], ); -final tBase2 = ExerciseBase( +final crunches = ExerciseBase( id: 2, uuid: '82415754-fc4c-49ea-8ca7-1516dd36d5a0', creationDate: DateTime(2021, 08, 01), @@ -62,7 +63,7 @@ final tBase2 = ExerciseBase( musclesSecondary: const [tMuscle2], ); -final tBase3 = ExerciseBase( +final deadLift = ExerciseBase( id: 3, uuid: 'ca84e2c5-5608-4d6d-ba57-6d4b6b5e7acd', creationDate: DateTime(2021, 08, 01), @@ -73,7 +74,7 @@ final tBase3 = ExerciseBase( musclesSecondary: const [tMuscle2], ); -final tBase4 = ExerciseBase( +final curls = ExerciseBase( id: 4, uuid: '361f024c-fdf8-4146-b7d7-0c1b67c58141', creationDate: DateTime(2021, 08, 01), @@ -83,75 +84,127 @@ final tBase4 = ExerciseBase( muscles: const [tMuscle1], musclesSecondary: const [tMuscle2], ); +final squats = ExerciseBase( + id: 5, + uuid: '361f024c-fdf8-4146-b7d7-0c1b67c58141', + creationDate: DateTime(2021, 08, 01), + updateDate: DateTime(2021, 08, 01), + category: tCategory3, + equipment: const [tEquipment2], + muscles: const [tMuscle1], + musclesSecondary: const [tMuscle2], +); +final sideRaises = ExerciseBase( + id: 6, + uuid: '721ff972-c568-41e3-8cf5-cf1e5c5c801c', + creationDate: DateTime(2022, 11, 01), + updateDate: DateTime(2022, 11, 01), + category: tCategory4, + equipment: const [tEquipment2], + muscles: const [tMuscle1], + musclesSecondary: const [tMuscle2], +); -final tExercise1 = Exercise( +final benchPressDe = Exercise( id: 1, uuid: 'f4cc326b-e497-4bd7-a71d-0eb1db522743', creationDate: DateTime(2021, 1, 15), - name: 'test exercise 1', + name: 'Bankdrücken', description: 'add clever text', - baseId: tBase1.id, + baseId: benchPress.id, + language: tLanguage1, +); +final benchPressEn = Exercise( + id: 7, + uuid: 'f4cc326b-e497-4bd7-a71d-0eb1db522743', + creationDate: DateTime(2021, 1, 15), + name: 'Bench press', + description: 'add clever text', + baseId: benchPress.id, language: tLanguage1, ); -final tExercise2 = Exercise( +final deadLiftEn = Exercise( id: 2, uuid: 'b7f51a1a-0368-4dfc-a03c-d629a4089b4a', creationDate: DateTime(2021, 1, 15), - name: 'test exercise 2', + name: 'Dead Lift', description: 'Lorem ipsum etc', - baseId: tBase2.id, + baseId: crunches.id, language: tLanguage2, ); -final tExercise3 = Exercise( +final crunchesFr = Exercise( id: 3, uuid: 'd83f572d-add5-48dc-89cf-75f6770284f1', creationDate: DateTime(2021, 4, 1), - name: 'test exercise 3', + name: 'Crunches', description: 'The man in black fled across the desert, and the gunslinger followed', - baseId: tBase3.id, + baseId: deadLift.id, language: tLanguage3, ); -final tExercise4 = Exercise( +final crunchesDe = Exercise( id: 4, uuid: 'a3e96c1d-b35f-4b0e-9cf4-ca37666cf521', creationDate: DateTime(2021, 4, 1), - name: 'test exercise 4', + name: 'Crunches', description: 'The story so far: in the beginning, the universe was created', - baseId: tBase3.id, + baseId: deadLift.id, language: tLanguage1, ); -final tExercise5 = Exercise( +final crunchesEn = Exercise( id: 5, uuid: '8c49a816-2247-4116-94bb-b5c0ce09c609', creationDate: DateTime(2021, 4, 1), name: 'test exercise 5', description: 'I am an invisible man', - baseId: tBase3.id, + baseId: deadLift.id, language: tLanguage2, ); -final tExercise6 = Exercise( +final curlsEn = Exercise( id: 6, uuid: '259a637e-957f-4fe1-b61b-f56e3793ebcd', creationDate: DateTime(2021, 4, 1), - name: 'test exercise 6', + name: 'Curls', description: 'It was a bright cold day in April, and the clocks were striking thirteen', - baseId: tBase3.id, + baseId: curls.id, + language: tLanguage2, +); + +final squatsEn = Exercise( + id: 8, + uuid: '259a637e-957f-4fe1-b61b-f56e3793ebcd', + creationDate: DateTime(2021, 4, 1), + name: 'Squats', + description: 'It was a bright cold day in April, and the clocks were striking thirteen', + baseId: curls.id, + language: tLanguage2, +); + +final sideRaisesEn = Exercise( + id: 9, + uuid: '6bf89ad0-5a43-4e98-91d3-a8c6886c9712', + creationDate: DateTime(2022, 11, 1), + name: 'Side raises', + description: 'It was a bright cold day in April, and the clocks were striking thirteen', + baseId: curls.id, language: tLanguage2, ); List getTestExercises() { - return [tExercise1, tExercise2, tExercise3]; + return [benchPressDe, deadLiftEn, crunchesFr]; } List getTestExerciseBases() { - tBase1.exercises = [tExercise1, tExercise2, tExercise3]; - tBase2.exercises = [tExercise4, tExercise5]; - tBase3.exercises = [tExercise6]; + benchPress.exercises = [benchPressEn, benchPressDe]; + crunches.exercises = [crunchesEn, crunchesDe, crunchesFr]; + deadLift.exercises = [deadLiftEn]; + curls.exercises = [curlsEn]; + squats.exercises = [squatsEn]; + sideRaises.exercises = [sideRaisesEn]; - return [tBase1, tBase2, tBase3, tBase4]; + return [benchPress, crunches, deadLift, curls, squats, sideRaises]; } diff --git a/test_data/measurements.dart b/test_data/measurements.dart new file mode 100644 index 00000000..87c524eb --- /dev/null +++ b/test_data/measurements.dart @@ -0,0 +1,34 @@ +/* + * This file is part of wger Workout Manager . + * Copyright (C) 2020, 2021 wger Team + * + * wger Workout Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wger Workout Manager is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import 'package:wger/models/measurements/measurement_category.dart'; +import 'package:wger/models/measurements/measurement_entry.dart'; + +final e1 = MeasurementEntry(id: 1, category: 1, date: DateTime(2022, 9, 10), value: 30, notes: ''); +final e2 = MeasurementEntry(id: 2, category: 1, date: DateTime(2022, 10, 5), value: 25, notes: ''); +final e3 = MeasurementEntry(id: 3, category: 1, date: DateTime(2022, 10, 10), value: 17, notes: ''); +final e4 = MeasurementEntry(id: 4, category: 1, date: DateTime(2022, 11, 1), value: 17, notes: ''); +final e5 = MeasurementEntry(id: 5, category: 1, date: DateTime(2022, 11, 10), value: 20, notes: ''); +final e6 = MeasurementEntry(id: 6, category: 1, date: DateTime(2022, 11, 15), value: 23, notes: ''); + +List getMeasurementCategories() { + final entries = [e1, e2, e3, e4, e5, e6]; + final category = MeasurementCategory(id: 1, name: 'Body fat', unit: '%', entries: entries); + + return [category]; +} diff --git a/test_data/nutritional_plans.dart b/test_data/nutritional_plans.dart index 3a39a664..8df73438 100644 --- a/test_data/nutritional_plans.dart +++ b/test_data/nutritional_plans.dart @@ -103,7 +103,7 @@ NutritionalPlan getNutritionalPlan() { final NutritionalPlan plan = NutritionalPlan( id: 1, - description: 'lots and lots of mass', + description: 'Less fat, more protein', creationDate: DateTime(2021, 5, 23), ); plan.meals = [meal1, meal2]; diff --git a/test_data/workouts.dart b/test_data/workouts.dart index a7a59fd6..229e3a47 100644 --- a/test_data/workouts.dart +++ b/test_data/workouts.dart @@ -35,21 +35,6 @@ const RepetitionUnit repetitionUnit2 = RepetitionUnit(id: 2, name: 'Hours'); WorkoutPlan getWorkout() { final testBases = getTestExerciseBases(); - final setting1 = Setting( - setId: 1, - order: 1, - exerciseBaseId: 1, - repetitionUnitId: 1, - reps: 2, - weightUnitId: 1, - comment: 'ddd', - rir: '2', - ); - setting1.repetitionUnit = repetitionUnit1; - setting1.weightUnit = weightUnit1; - setting1.exerciseBase = testBases[0]; - setting1.weight = 10; - final log1 = Log.empty() ..id = 1 ..weight = 10 @@ -83,36 +68,104 @@ WorkoutPlan getWorkout() { log3.weightUnit = weightUnit1; log3.repetitionUnit = repetitionUnit1; - final set1 = Set.withData( + final settingBenchPress = Setting( + setId: 1, + order: 1, + exerciseBaseId: 1, + repetitionUnitId: 1, + reps: 6, + weightUnitId: 1, + comment: 'ddd', + rir: '3', + ); + settingBenchPress.repetitionUnit = repetitionUnit1; + settingBenchPress.weightUnit = weightUnit1; + settingBenchPress.exerciseBase = testBases[0]; + settingBenchPress.weight = 80; + + final setBenchPress = Set.withData( id: 1, day: 1, sets: 3, order: 1, - comment: 'Important to do exercises correctly', + comment: 'Make sure to warm up', ); - set1.addExerciseBase(testBases[0]); - set1.settings.add(setting1); - set1.settingsComputed = [setting1, setting1]; + setBenchPress.addExerciseBase(testBases[0]); + setBenchPress.settings.add(settingBenchPress); + setBenchPress.settingsComputed = [settingBenchPress, settingBenchPress]; - final day1 = Day() + final settingSquat = Setting( + setId: 2, + order: 1, + exerciseBaseId: 8, + repetitionUnitId: 1, + reps: 8, + weightUnitId: 1, + comment: 'ddd', + rir: '2', + ); + settingSquat.repetitionUnit = repetitionUnit1; + settingSquat.weightUnit = weightUnit1; + settingSquat.exerciseBase = testBases[4]; + settingSquat.weight = 120; + + final setSquat = Set.withData( + id: 2, + day: 1, + sets: 3, + order: 1, + ); + setSquat.addExerciseBase(testBases[4]); + setSquat.settings.add(settingSquat); + setSquat.settingsComputed = [settingSquat, settingSquat]; + + final settingSideRaises = Setting( + setId: 2, + order: 1, + exerciseBaseId: 8, + repetitionUnitId: 1, + reps: 12, + weightUnitId: 1, + comment: 'ddd', + rir: '', + ); + settingSideRaises.repetitionUnit = repetitionUnit1; + settingSideRaises.weightUnit = weightUnit1; + settingSideRaises.exerciseBase = testBases[5]; + settingSideRaises.weight = 6; + + final setSideRaises = Set.withData( + id: 3, + day: 1, + sets: 3, + order: 1, + ); + setSideRaises.addExerciseBase(testBases[5]); + setSideRaises.settings.add(settingSideRaises); + setSideRaises.settingsComputed = [settingSideRaises, settingSideRaises]; + + final dayChestShoulders = Day() ..id = 1 ..workoutId = 1 - ..description = 'test day 1' + ..description = 'chest, shoulders' ..daysOfWeek = [1, 2]; - day1.sets.add(set1); + dayChestShoulders.sets.add(setBenchPress); + dayChestShoulders.sets.add(setSideRaises); - final day2 = Day() + final dayLegs = Day() ..id = 2 ..workoutId = 1 - ..description = 'test day 2' + ..description = 'legs' ..daysOfWeek = [4]; + dayLegs.sets.add(setSquat); final workout = WorkoutPlan( - id: 1, - creationDate: DateTime(2021, 01, 01), - name: 'test workout 1', - days: [day1, day2], - logs: [log1, log2, log3]); + id: 1, + creationDate: DateTime(2021, 01, 01), + name: '3 day workout', + days: [dayChestShoulders, dayLegs], + logs: [log1, log2, log3], + ); return workout; }