diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml index de6a948b..86c1da99 100644 --- a/.github/workflows/android-release.yml +++ b/.github/workflows/android-release.yml @@ -1,8 +1,8 @@ name: Google Play release on: push: - branches: - - 'release/*' + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' jobs: deploy_android: @@ -14,45 +14,78 @@ jobs: - name: Setup Java uses: actions/setup-java@v1 with: - java-version: 12.x + java-version: 11.x - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' - - - name: Decrypt config files - run: cd ./android/fastlane/envfiles && chmod +x ./decrypt_secrets.sh && ./decrypt_secrets.sh - env: - DECRYPTKEY_PLAYSTORE: ${{ secrets.DECRYPTKEY_PLAYSTORE }} - DECRYPTKEY_PLAYSTORE_SIGNING_KEY: ${{ secrets.DECRYPTKEY_PLAYSTORE_SIGNING_KEY }} - DECRYPTKEY_PROPERTIES: ${{ secrets.DECRYPTKEY_PROPERTIES }} + ruby-version: '3' - name: Setup Flutter uses: subosito/flutter-action@v1 with: channel: 'stable' - flutter-version: '2.2.x' + flutter-version: '2.5.x' - - run: dart --version - - run: flutter --version + - name: Decrypt config files + run: | + cd ./fastlane/android/envfiles + chmod +x ./decrypt_secrets.sh + ./decrypt_secrets.sh + env: + DECRYPTKEY_PLAYSTORE: ${{ secrets.DECRYPTKEY_PLAYSTORE }} + DECRYPTKEY_PLAYSTORE_SIGNING_KEY: ${{ secrets.DECRYPTKEY_PLAYSTORE_SIGNING_KEY }} + DECRYPTKEY_PROPERTIES: ${{ secrets.DECRYPTKEY_PROPERTIES }} + + - name: Flutter info + run: | + dart --version + flutter --version - name: Install Flutter dependencies run: flutter pub get + - name: Extract version information + id: get_version + run: | + echo ::set-output name=VERSION_V::$(echo $GITHUB_REF | cut -d / -f 3) + echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3 | cut -c 2-) + echo ::set-output name=BUILD::$(flutter pub run cider version | cut -d '+' -f 2) + + # Note: the original tag that triggered the workflow is in the form vX.Y.Z + # but the pubspec.yaml is committed in the commit after that one. + # Since we need the tag to point to the correct commit for other workflows + # such as f-droid we need a way to correct it. Only moving the tag + # would not work, as it would trigger this workflow again. So as + # a workaround, we use the v-tag to trigger this workflow, add a new + # one without the v and push it. - name: Bump version - uses: maierj/fastlane-action@v2.0.0 - with: - lane: setVersion - subdirectory: android + run: | + flutter pub run cider version ${{ steps.get_version.outputs.VERSION }}+${{ steps.get_version.outputs.BUILD }} + flutter pub run cider bump build + + git config user.name Github-actions + git config user.email github-actions@github.com + git add . + git commit -m "Bump version to $( flutter pub run cider version )" + git tag ${{ steps.get_version.outputs.VERSION }} + git push origin HEAD:master --tags + git push origin --delete ${{ steps.get_version.outputs.VERSION_V }} - name: Build AAB run: flutter build appbundle --release env: WGER_API_KEY: ${{ secrets.WGER_API_KEY }} - - name: Run Fastlane - uses: maierj/fastlane-action@v2.0.0 + - name: Upload build to Play Store + uses: maierj/fastlane-action@v2.1.0 with: lane: production subdirectory: android + + - name: Make Github release + uses: softprops/action-gh-release@v1 + with: + files: build/app/outputs/bundle/release/app-release.aab + tag_name: ${{ steps.get_version.outputs.VERSION }} + body_path: CHANGELOG.md \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c840518..9ac22461 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,8 +2,12 @@ name: Continous Integration on: push: branches: [ master ] + paths: + - '**.dart' pull_request: branches: [ master ] + paths: + - '**.dart' jobs: test: runs-on: ubuntu-20.04 @@ -14,7 +18,7 @@ jobs: uses: subosito/flutter-action@v1 with: channel: 'stable' - flutter-version: '2.2.x' + flutter-version: '2.5.x' - run: dart --version - run: flutter --version diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 0b31d6da..d8052c82 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -4,6 +4,8 @@ on: push: branches: - "master" + paths: + - '**.dart' jobs: diff --git a/.gitignore b/.gitignore index 8317ac5e..eb18a5b7 100644 --- a/.gitignore +++ b/.gitignore @@ -40,8 +40,10 @@ app.*.symbols # Obfuscation related app.*.map.json -# Exceptions to above rules. +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages -/android/fastlane/envfiles/playstore.json -/android/fastlane/envfiles/wger.properties -/android/fastlane/envfiles/keys.jks +/fastlane/metadata/android/envfiles/playstore.json +/fastlane/metadata/android/envfiles/wger.properties +/fastlane/metadata/android/envfiles/keys.jks +/fastlane/metadata/android/envfiles/key.properties diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..f1351e44 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,25 @@ +🚀 Features: +* Allow users to give meals a description #89 +* Allow users to delete workout log entries #97 +* Allow users to log individual ingredients/products #114 +* New loading animation during first run #99 +* Added reference from log to meal #105 + + +🐛 Bug Fixes: +* Improve usability for workout logs #91 +* Preselect correct time in session form #93 +* Fixed infinite loader bug during auth #96 +* Fix error not showing up in auth screen #102 +* Fix for chart legend bug #112 +* Fix for RiR slider #113 + + +🧰 Maintenance: +* Better linting #87 #98 +* Improve automatic build system for publication on play store +* Notify the user when saving entries in gym mode #92 +* Consistenly display nutritional values #94 +* Add minimum required server version #29 +* Make order field of sets required #109 + diff --git a/CHANGELOG.template.md b/CHANGELOG.template.md new file mode 100644 index 00000000..f29c2972 --- /dev/null +++ b/CHANGELOG.template.md @@ -0,0 +1,10 @@ +🚀 Features: +* + + +🐛 Bug Fixes: +* + + +🧰 Maintenance: +* \ No newline at end of file diff --git a/README.md b/README.md index 5711fedb..f0d2ff5f 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Alternatively, you can use one of our test servers, just ask us for access. Install Flutter, all its dependencies and create a new virtual device: . -The app currently uses flutter 2.2 +The app currently uses flutter 2.5 ### 3 Create a new file ``wger.properties`` in ``android/fastlane/envfiles``: diff --git a/analysis_options.yaml b/analysis_options.yaml index 92ea0b11..6640b461 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -65,7 +65,7 @@ linter: empty_statements: true exhaustive_cases: true file_names: true - flutter_style_todos: true + flutter_style_todos: false hash_and_equals: true implementation_imports: true iterable_contains_unrelated_type: true diff --git a/android/.gitignore b/android/.gitignore index 60658c9a..bc2100d8 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -5,7 +5,3 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -fastlane/envfiles/key.properties diff --git a/android/app/build.gradle b/android/app/build.gradle index 58146be7..8633bbe8 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -27,14 +27,14 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" // Keys for the android play store def keystoreProperties = new Properties() -def keystorePropertiesFile = rootProject.file('fastlane/envfiles/key.properties') +def keystorePropertiesFile = rootProject.file('../fastlane/metadata/android/envfiles/key.properties') if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) } // Key for wger.de REST API def wgerProperties = new Properties() -def localMapsPropertiesFile = rootProject.file('fastlane/envfiles/wger.properties') +def localMapsPropertiesFile = rootProject.file('../fastlane/metadata/android/envfiles/wger.properties') if (localMapsPropertiesFile.exists()) { project.logger.info('Load maps properties from local file') localMapsPropertiesFile.withReader('UTF-8') { reader -> @@ -55,7 +55,7 @@ if(wgerApiKey == null){ } android { - compileSdkVersion 29 + compileSdkVersion 31 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -69,7 +69,7 @@ android { // Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "de.wger.flutter" minSdkVersion 21 - targetSdkVersion 30 + targetSdkVersion 31 versionCode flutterVersionCode.toInteger() versionName flutterVersionName manifestPlaceholders = [WGER_API_KEY: wgerApiKey] diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 9a8d34ed..3438b858 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -26,6 +26,7 @@ android:icon="@mipmap/ic_launcher"> + find the source code on https://github.com/wger-project +-> ask your questions or just say hello on our discord Server https://discord.gg/rPWFv6W \ No newline at end of file diff --git a/android/fastlane/metadata/android/es/short_description.txt b/fastlane/metadata/android/es-ES/short_description.txt similarity index 100% rename from android/fastlane/metadata/android/es/short_description.txt rename to fastlane/metadata/android/es-ES/short_description.txt diff --git a/android/fastlane/metadata/android/uk/title.txt b/fastlane/metadata/android/es-ES/title.txt similarity index 100% rename from android/fastlane/metadata/android/uk/title.txt rename to fastlane/metadata/android/es-ES/title.txt diff --git a/android/fastlane/metadata/android/fr-FR/full_description.txt b/fastlane/metadata/android/fr-FR/full_description.txt similarity index 100% rename from android/fastlane/metadata/android/fr-FR/full_description.txt rename to fastlane/metadata/android/fr-FR/full_description.txt diff --git a/android/fastlane/metadata/android/fr-FR/short_description.txt b/fastlane/metadata/android/fr-FR/short_description.txt similarity index 100% rename from android/fastlane/metadata/android/fr-FR/short_description.txt rename to fastlane/metadata/android/fr-FR/short_description.txt diff --git a/android/fastlane/metadata/android/fr-FR/title.txt b/fastlane/metadata/android/fr-FR/title.txt similarity index 100% rename from android/fastlane/metadata/android/fr-FR/title.txt rename to fastlane/metadata/android/fr-FR/title.txt diff --git a/android/fastlane/metadata/android/hr/full_description.txt b/fastlane/metadata/android/hr/full_description.txt similarity index 100% rename from android/fastlane/metadata/android/hr/full_description.txt rename to fastlane/metadata/android/hr/full_description.txt diff --git a/android/fastlane/metadata/android/hr/short_description.txt b/fastlane/metadata/android/hr/short_description.txt similarity index 100% rename from android/fastlane/metadata/android/hr/short_description.txt rename to fastlane/metadata/android/hr/short_description.txt diff --git a/fastlane/metadata/android/hr/title.txt b/fastlane/metadata/android/hr/title.txt new file mode 100644 index 00000000..ea0df956 --- /dev/null +++ b/fastlane/metadata/android/hr/title.txt @@ -0,0 +1 @@ +wger Workout Manager \ No newline at end of file diff --git a/android/fastlane/metadata/android/it-IT/full_description.txt b/fastlane/metadata/android/it-IT/full_description.txt similarity index 100% rename from android/fastlane/metadata/android/it-IT/full_description.txt rename to fastlane/metadata/android/it-IT/full_description.txt diff --git a/android/fastlane/metadata/android/it-IT/short_description.txt b/fastlane/metadata/android/it-IT/short_description.txt similarity index 100% rename from android/fastlane/metadata/android/it-IT/short_description.txt rename to fastlane/metadata/android/it-IT/short_description.txt diff --git a/android/fastlane/metadata/android/it-IT/title.txt b/fastlane/metadata/android/it-IT/title.txt similarity index 100% rename from android/fastlane/metadata/android/it-IT/title.txt rename to fastlane/metadata/android/it-IT/title.txt diff --git a/android/fastlane/metadata/android/nb-NO/full_description.txt b/fastlane/metadata/android/nb-NO/full_description.txt similarity index 100% rename from android/fastlane/metadata/android/nb-NO/full_description.txt rename to fastlane/metadata/android/nb-NO/full_description.txt diff --git a/android/fastlane/metadata/android/nb-NO/short_description.txt b/fastlane/metadata/android/nb-NO/short_description.txt similarity index 100% rename from android/fastlane/metadata/android/nb-NO/short_description.txt rename to fastlane/metadata/android/nb-NO/short_description.txt diff --git a/android/fastlane/metadata/android/nb-NO/title.txt b/fastlane/metadata/android/nb-NO/title.txt similarity index 100% rename from android/fastlane/metadata/android/nb-NO/title.txt rename to fastlane/metadata/android/nb-NO/title.txt diff --git a/fastlane/metadata/android/tr/full_description.txt b/fastlane/metadata/android/tr/full_description.txt new file mode 100644 index 00000000..1b22733e --- /dev/null +++ b/fastlane/metadata/android/tr/full_description.txt @@ -0,0 +1,39 @@ +Fitness tutkunlarından fitness severlere - Egzersiz Yöneticiniz WGER ile sağlığınızı organize edin! + +1 numaralı fitness uygulamanızı zaten buldunuz mu ve kendi spor rutinlerinizi oluşturmayı seviyor musunuz? Ne tür bir sportif canavar olursanız olun - hepimizin ortak bir yanı var: Sağlık verilerimizi takip etmeyi seviyoruz <3 + +Bu nedenle, fitness yolculuğunuzu kullanışlı küçük egzersiz kayıt defterinizle hala yönettiğiniz için sizi yargılamıyoruz, ancak 2021'e hoş geldiniz! + +Sizin için hayatınızı kolaylaştırmak için en alakalı özelliklere göre boyutlandırılmış %100 ücretsiz bir dijital sağlık ve fitness takip uygulaması geliştirdik. Başlayın, antrenmana devam edin ve ilerlemenizi kutlayın! + +wger bir Açık Kaynak projesidir ve her şey: +* Vucüdun +* Antrenmanlarınız +* Senin ilerlemen +* Verileriniz + +Vucüdun: +En sevdiğiniz ikramların içeriğini Google'da aramanıza gerek yok - 78000'den fazla ürün arasından günlük öğünlerinizi seçin ve besin değerlerini görün. Beslenme planına yemek ekleyin ve takvimde diyetinizin bir özetini tutun. + +Antrenmanlarınız: +Vücudunuz için en iyisini siz bilirsiniz. 200 farklı egzersizden artan çeşitlilikten kendi egzersiz programlarınızı oluşturun. Ardından, ağırlıklarınızı tek dokunuşla kaydederken egzersiz boyunca size rehberlik etmesi için Spor Salonu Modunu kullanın. + +Senin ilerlemen: +Hedeflerinizi asla gözden kaçırmayın. Kilonuzu takip edin ve istatistiklerinizi saklayın. + +Verileriniz: +wger, kişiselleştirilmiş fitness günlüğünüzdür - ancak verilerinizin sahibi sizsiniz. Erişmek ve onunla harika şeyler yapmak için REST API'yi kullanın. + +Lütfen dikkat: Bu ücretsiz uygulama ek fonlara dayalı değildir ve sizden para bağışlamanızı istemiyoruz. Dahası, sürekli büyüyen bir topluluk projesidir. Bu yüzden her zaman yeni özelliklere hazır olun! + +#OpenSource – bu ne anlama geliyor? + +Açık Kaynak, bu uygulamanın ve konuştuğu sunucunun tüm kaynak kodunun ücretsiz ve herkes tarafından kullanılabilir olduğu anlamına gelir: +* Kendi sunucunuzda veya yerel spor salonunuz için wger çalıştırmak ister misiniz? Devam etmek! +* Bir özelliği özlüyor ve uygulamak istiyor musunuz? Şimdi başla! +* Hiçbir şeyin hiçbir yere gönderilmediğini kontrol etmek ister misiniz? Yapabilirsiniz! + +Topluluğumuza katılın ve dünyanın her yerinden spor meraklılarının ve BT meraklılarının bir parçası olun. İhtiyaçlarımıza göre özelleştirilmiş uygulamayı ayarlamak ve optimize etmek için çalışmaya devam ediyoruz. Katkılarınızı seviyoruz, bu yüzden istediğiniz zaman atlamaktan ve dilekleriniz ve fikirlerinizle katkıda bulunmaktan çekinmeyin! + +-> https://github.com/wger-project adresinde kaynak kodunu bulun +-> sorularınızı sorun veya sadece discord sunucumuzda merhaba deyin https://discord.gg/rPWFv6W diff --git a/fastlane/metadata/android/tr/short_description.txt b/fastlane/metadata/android/tr/short_description.txt new file mode 100644 index 00000000..2e719d78 --- /dev/null +++ b/fastlane/metadata/android/tr/short_description.txt @@ -0,0 +1 @@ +Fitness/egzersiz, beslenme ve kilo takibi diff --git a/android/fastlane/metadata/android/uk/full_description.txt b/fastlane/metadata/android/uk/full_description.txt similarity index 100% rename from android/fastlane/metadata/android/uk/full_description.txt rename to fastlane/metadata/android/uk/full_description.txt diff --git a/android/fastlane/metadata/android/uk/short_description.txt b/fastlane/metadata/android/uk/short_description.txt similarity index 100% rename from android/fastlane/metadata/android/uk/short_description.txt rename to fastlane/metadata/android/uk/short_description.txt diff --git a/fastlane/metadata/android/uk/title.txt b/fastlane/metadata/android/uk/title.txt new file mode 100644 index 00000000..ea0df956 --- /dev/null +++ b/fastlane/metadata/android/uk/title.txt @@ -0,0 +1 @@ +wger Workout Manager \ No newline at end of file diff --git a/fastlane/metadata/android/zh-CN/full_description.txt b/fastlane/metadata/android/zh-CN/full_description.txt new file mode 100644 index 00000000..ba92c243 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/full_description.txt @@ -0,0 +1,39 @@ +每一个健身爱好者 - 与您的健身教练 WGER 一起,让你更健康! + +你是否已经找到了排名第一的健身应用程序,并且喜欢创建自己的运动习惯? 无论你是哪种运动野兽——我们都有一个共同点:我们喜欢跟踪我们的健康数据 + +因此,我们不会因为你仍然使用小笔记本来管理你的健身旅程而评判你,但欢迎来到 2021 年! + +我们为你开发了 100% 免费的数字健康和健身追踪器应用程序,压缩到最相关的功能,让你的生活更轻松。开始吧,继续训练并庆祝你的进步! + +wger 是一个开源项目,关于: +* 你的身体 +* 你的锻炼 +* 你的进步 +* 你的数据 + +你的身体: +无需在谷歌上搜索你最喜欢的食物的成分——从 78000 多种产品中选择你的日常膳食并查看营养价值。将膳食添加到营养计划中,并在日历中概述你的饮食。 + +你的锻炼: +你知道什么对你的身体最好。从 200 种不同的练习中选择越来越多的练习来创建你自己的锻炼。然后,使用健身房模式指导你完成训练,同时一键记录你的体重。 + +你的进步: +永远不要忘记你的目标。跟踪你的体重并保留你的统计数据。 + +你的数据: +wger 是你的个性化健身日记——但你拥有自己的数据。使用 REST API 来访问它并用它做惊人的事情。 + +请注意:这个免费的应用程序不是基于额外的资金,我们不要求你捐款。不仅如此,它还是一个不断发展的社区项目。因此,请随时为新功能做好准备! + +#OpenSource – 这是什么意思? + +开源意味着这个应用程序的整个源代码和它与之通信的服务器都是免费的,任何人都可以使用: +* 你想在自己的服务器上为你还是为你当地的健身房运行 wger?都可以! +* 你是否错过了某个功能并想要实现它?现在开始! +* 你想检查任何地方都没有发送任何东西吗?你可以! + +加入我们的社区,成为来自世界各地的体育爱好者和 IT 极客的一份子。我们一直致力于调整和优化根据我们的需求定制的应用程序。我们喜欢你的意见,因此请随时加入并贡献你的愿望和想法! + +-> 在 https://github.com/wger-project 上找到源代码 +-> 在我们的 Discord 服务器上提问或打个招呼 https://discord.gg/rPWFv6W diff --git a/fastlane/metadata/android/zh-CN/short_description.txt b/fastlane/metadata/android/zh-CN/short_description.txt new file mode 100644 index 00000000..46c8b60f --- /dev/null +++ b/fastlane/metadata/android/zh-CN/short_description.txt @@ -0,0 +1 @@ +健身/锻炼、营养和体重追踪器 diff --git a/android/fastlane/report.xml b/fastlane/report.xml similarity index 100% rename from android/fastlane/report.xml rename to fastlane/report.xml diff --git a/lib/helpers/consts.dart b/lib/helpers/consts.dart index a37ab849..c0e4ad56 100644 --- a/lib/helpers/consts.dart +++ b/lib/helpers/consts.dart @@ -26,6 +26,10 @@ const double ICON_SIZE_SMALL = 20; /// Default wger server during login const DEFAULT_SERVER = 'https://wger.de'; +/// Keys used in the android manifest +const MANIFEST_KEY_API = 'wger.api_key'; +const MANIFEST_KEY_CHECK_UPDATE = 'wger.check_min_app_version'; + /// Default weight unit is "kg" const DEFAULT_WEIGHT_UNIT = 1; @@ -70,6 +74,3 @@ const ENERGY_CARBOHYDRATES = 4; /// kcal per gram of fat (approx) const ENERGY_FAT = 9; - -/// Flag to check for updates to the new version. -const ENABLED_UPDATE = false; diff --git a/lib/helpers/gym_mode.dart b/lib/helpers/gym_mode.dart index dd15611a..ffad3e26 100644 --- a/lib/helpers/gym_mode.dart +++ b/lib/helpers/gym_mode.dart @@ -19,7 +19,6 @@ /// Calculates the number of plates needed to reach a specific weight List plateCalculator(num totalWeight, num barWeight, List plates) { final List ans = []; - final platesCount = plates.length; // Weight is less than the bar if (totalWeight < barWeight) { diff --git a/lib/helpers/misc.dart b/lib/helpers/misc.dart index 01261914..05e5d693 100644 --- a/lib/helpers/misc.dart +++ b/lib/helpers/misc.dart @@ -96,6 +96,6 @@ void launchURL(String url, BuildContext context) async { await canLaunch(url) ? await launch(url) : ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("Could not open $url.")), + SnackBar(content: Text('Could not open $url.')), ); } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index e38f9204..0b3d7c30 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -531,5 +531,11 @@ "recentlyUsedIngredients": "Kürzlich hinzugefügte Zutaten", "@recentlyUsedIngredients": { "description": "A message when a user adds a new ingredient to a meal." - } + }, + "searchIngredient": "Zutat suchen", + "@searchIngredient": { + "description": "Label on ingredient search form" + }, + "logIngredient": "Im Nährwerttagebuch speichern", + "@logIngredient": {} } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 77c192e5..be62be29 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -242,6 +242,12 @@ "@logMeal": {}, "addIngredient": "Add ingredient", "@addIngredient": {}, + "logIngredient": "Save to nutrition diary", + "@logIngredient": {}, + "searchIngredient": "Search ingredient", + "@searchIngredient": { + "description": "Label on ingredient search form" + }, "nutritionalPlan": "Nutritional plan", "@nutritionalPlan": {}, "nutritionalDiary": "Nutritional diary", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 2dc2191e..647a0f75 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -526,5 +526,11 @@ "recentlyUsedIngredients": "Ingrédients récemment ajoutés", "@recentlyUsedIngredients": { "description": "A message when a user adds a new ingredient to a meal." - } + }, + "searchIngredient": "Rechercher un ingrédient", + "@searchIngredient": { + "description": "Label on ingredient search form" + }, + "logIngredient": "Sauvegarder dans le journal nutritionnel", + "@logIngredient": {} } diff --git a/lib/l10n/app_hr.arb b/lib/l10n/app_hr.arb index b1f50e7b..2a802be0 100644 --- a/lib/l10n/app_hr.arb +++ b/lib/l10n/app_hr.arb @@ -514,5 +514,11 @@ "recentlyUsedIngredients": "Nedavno dodani sastojci", "@recentlyUsedIngredients": { "description": "A message when a user adds a new ingredient to a meal." + }, + "logIngredient": "Spremi u dnevnik prehrane", + "@logIngredient": {}, + "searchIngredient": "Traži sastojak", + "@searchIngredient": { + "description": "Label on ingredient search form" } } diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 630e4769..41aea826 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -164,5 +164,199 @@ "placeholders": { "nr": {} } - } + }, + "sameRepetitions": "Eğer tüm setler için aynı ağırlıklarla aynı setleri yapıyorsanız, sadece bir satır doldurabilirsiniz. Örneğin, 4 set için sadece 10 girin, bu otomatik olarak \"4 x 10\"a dönüşüyor.", + "@sameRepetitions": {}, + "selectExercises": "Eğer bir süper set yapmak istiyorsanız, birkaç egzersiz için arama yapabilirsiniz, birlikte gruplanacaklardır", + "@selectExercises": {}, + "logHelpEntries": "Tek bir günde, aynı sayıda tekrara sahip ancak farklı ağırlıklara sahip birden fazla giriş varsa, diyagramda yalnızca daha yüksek ağırlığa sahip giriş gösterilir.", + "@logHelpEntries": {}, + "addSet": "Set ekle", + "@addSet": { + "description": "Label for the button that adds a set (to a workout day)" + }, + "date": "Tarih", + "@date": { + "description": "The date of a workout log or body weight entry" + }, + "time": "Zaman", + "@time": { + "description": "The time of a meal or workout" + }, + "logHelpEntriesUnits": "Yalnızca ağırlık birimi (kg veya lb) ve tekrarları olan girişlerin çizelgelendirildiğini, zaman veya arızaya kadar olan diğer kombinasyonların burada göz ardı edildiğini unutmayın.", + "@logHelpEntriesUnits": {}, + "nutritionalPlans": "Beslenme planları", + "@nutritionalPlans": {}, + "energyShort": "E", + "@energyShort": { + "description": "The first letter or short name of the word 'Energy', used in overviews" + }, + "total": "Toplam", + "@total": { + "description": "Label used for total sums of e.g. calories or similar" + }, + "kJ": "kilo joule", + "@kJ": { + "description": "Energy in a meal in kilo joules, kJ" + }, + "anErrorOccurred": "Bir hata oluştu!", + "@anErrorOccurred": {}, + "plateCalculator": "Tabaklar", + "@plateCalculator": { + "description": "Label used for the plate calculator in the gym mode" + }, + "logIngredient": "Beslenme günlüğüne kaydet", + "@logIngredient": {}, + "comment": "Yorum", + "@comment": { + "description": "Comment, additional information" + }, + "notes": "Notlar", + "@notes": { + "description": "Personal notes, e.g. for a workout session" + }, + "workoutSession": "Egzersiz Seansı", + "@workoutSession": { + "description": "A (logged) workout session" + }, + "newDay": "Yeni gün", + "@newDay": {}, + "newSet": "Yeni set", + "@newSet": { + "description": "Header when adding a new set to a workout day" + }, + "gymMode": "Spor salonu modu", + "@gymMode": { + "description": "Label when starting the gym mode" + }, + "plateCalculatorNotDivisible": "Varolan tabaklar ile istenilen ağırlığa ulaşmak mümkün değil", + "@plateCalculatorNotDivisible": { + "description": "Error message when the current weight is not reachable with plates (e.g. 33.1 kg)" + }, + "pause": "Duraklat", + "@pause": { + "description": "Noun, not an imperative! Label used for the pause when using the gym mode" + }, + "jumpTo": "Buraya git", + "@jumpTo": { + "description": "Imperative. Label used in popup allowing the user to jump to a specific exercise while in the gym mode" + }, + "todaysWorkout": "Günlük antrenmanınız", + "@todaysWorkout": {}, + "description": "Açıklama", + "@description": {}, + "name": "İsim", + "@name": { + "description": "Name for a workout or nutritional plan" + }, + "ingredient": "Bileşen", + "@ingredient": {}, + "save": "Kaydet", + "@save": {}, + "addMeal": "Yemek ekle", + "@addMeal": {}, + "mealLogged": "Günlüğe kaydedilen yemek", + "@mealLogged": {}, + "logMeal": "Bu yemeği kaydet", + "@logMeal": {}, + "addIngredient": "Malzeme ekle", + "@addIngredient": {}, + "measurements": "Ölçümler", + "@measurements": { + "description": "Categories for the measurements such as biceps size, body fat, etc." + }, + "measurement": "Ölçüm", + "@measurement": {}, + "searchIngredient": "İçerik ara", + "@searchIngredient": { + "description": "Label on ingredient search form" + }, + "nutritionalPlan": "Beslenme planı", + "@nutritionalPlan": {}, + "nutritionalDiary": "Beslenme Günlüğü", + "@nutritionalDiary": {}, + "noNutritionalPlans": "Beslenme planınız yok", + "@noNutritionalPlans": { + "description": "Message shown when the user has no nutritional plans" + }, + "weight": "Ağırlık", + "@weight": { + "description": "The weight of a workout log or body weight entry" + }, + "measurementCategoriesHelpText": "\"Pazı\" veya \"vücut yağı\" gibi ölçüm kategorisi", + "@measurementCategoriesHelpText": {}, + "measurementEntriesHelpText": "'cm' veya '%' gibi kategoriyi ölçmek için kullanılan birim", + "@measurementEntriesHelpText": {}, + "value": "Değer", + "@value": { + "description": "The value of a measurement entry" + }, + "start": "Başlangıç", + "@start": { + "description": "Label on button to start the gym mode (i.e., an imperative)" + }, + "timeStart": "Başlangıç zamanı", + "@timeStart": { + "description": "The starting time of a workout" + }, + "timeEnd": "Bitiş zamanı", + "@timeEnd": { + "description": "The end time of a workout" + }, + "timeStartAhead": "Başlangıç zamanı, bitiş zamanından önce olamaz", + "@timeStartAhead": {}, + "energy": "Enerji", + "@energy": { + "description": "Energy in a meal, ingredient etc. e.g. in kJ" + }, + "kcal": "kilo kalori", + "@kcal": { + "description": "Energy in a meal in kilocalories, kcal" + }, + "macronutrients": "Makrobesinler", + "@macronutrients": {}, + "planned": "Planlı", + "@planned": { + "description": "Header for the column of 'planned' nutritional values, i.e. what should be eaten" + }, + "logged": "Kaydedildi", + "@logged": { + "description": "Header for the column of 'logged' nutritional values, i.e. what was eaten" + }, + "difference": "Fark", + "@difference": {}, + "percentEnergy": "Enerji Yüzdesi", + "@percentEnergy": {}, + "gPerBodyKg": "vücut kg başına düşen g", + "@gPerBodyKg": { + "description": "Label used for total sums of e.g. calories or similar in grams per Kg of body weight" + }, + "g": "gram", + "@g": { + "description": "Abbreviation for gram" + }, + "protein": "Protein", + "@protein": {}, + "proteinShort": "P", + "@proteinShort": { + "description": "The first letter or short name of the word 'Protein', used in overviews" + }, + "carbohydrates": "Karbonhidratlar", + "@carbohydrates": {}, + "carbohydratesShort": "carb", + "@carbohydratesShort": { + "description": "The first letter or short name of the word 'Carbohydrates', used in overviews" + }, + "sugars": "Şekerler", + "@sugars": {}, + "fat": "Yağ", + "@fat": {}, + "fatShort": "fat", + "@fatShort": { + "description": "The first letter or short name of the word 'Fat', used in overviews" + }, + "saturatedFat": "Doymuş yağ", + "@saturatedFat": {}, + "fibres": "Lif", + "@fibres": {} } diff --git a/lib/main.dart b/lib/main.dart index c58abe57..479f8098 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -105,7 +105,7 @@ class MyApp extends StatelessWidget { theme: wgerTheme, home: auth.isAuth ? FutureBuilder( - future: auth.neededApplicationUpdate(), + future: auth.applicationUpdateRequired(), builder: (ctx, snapshot) => snapshot.connectionState == ConnectionState.done && snapshot.data == true ? UpdateAppScreen() diff --git a/lib/models/body_weight/weight_entry.g.dart b/lib/models/body_weight/weight_entry.g.dart index 98ab3eda..d1152d20 100644 --- a/lib/models/body_weight/weight_entry.g.dart +++ b/lib/models/body_weight/weight_entry.g.dart @@ -7,7 +7,10 @@ part of 'weight_entry.dart'; // ************************************************************************** WeightEntry _$WeightEntryFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'weight', 'date']); + $checkKeys( + json, + requiredKeys: const ['id', 'weight', 'date'], + ); return WeightEntry( id: json['id'] as int?, weight: stringToNum(json['weight'] as String?), diff --git a/lib/models/exercises/category.g.dart b/lib/models/exercises/category.g.dart index 5083051f..915120d1 100644 --- a/lib/models/exercises/category.g.dart +++ b/lib/models/exercises/category.g.dart @@ -7,7 +7,10 @@ part of 'category.dart'; // ************************************************************************** ExerciseCategory _$ExerciseCategoryFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'name']); + $checkKeys( + json, + requiredKeys: const ['id', 'name'], + ); return ExerciseCategory( id: json['id'] as int, name: json['name'] as String, diff --git a/lib/models/exercises/comment.g.dart b/lib/models/exercises/comment.g.dart index 6195a276..179ef89b 100644 --- a/lib/models/exercises/comment.g.dart +++ b/lib/models/exercises/comment.g.dart @@ -7,7 +7,10 @@ part of 'comment.dart'; // ************************************************************************** Comment _$CommentFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'comment']); + $checkKeys( + json, + requiredKeys: const ['id', 'comment'], + ); return Comment( id: json['id'] as int, comment: json['comment'] as String, diff --git a/lib/models/exercises/equipment.g.dart b/lib/models/exercises/equipment.g.dart index 252f0397..3948e1bb 100644 --- a/lib/models/exercises/equipment.g.dart +++ b/lib/models/exercises/equipment.g.dart @@ -7,7 +7,10 @@ part of 'equipment.dart'; // ************************************************************************** Equipment _$EquipmentFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'name']); + $checkKeys( + json, + requiredKeys: const ['id', 'name'], + ); return Equipment( id: json['id'] as int, name: json['name'] as String, diff --git a/lib/models/exercises/exercise.g.dart b/lib/models/exercises/exercise.g.dart index 4c449343..2b0bf68e 100644 --- a/lib/models/exercises/exercise.g.dart +++ b/lib/models/exercises/exercise.g.dart @@ -7,19 +7,22 @@ part of 'exercise.dart'; // ************************************************************************** Exercise _$ExerciseFromJson(Map json) { - $checkKeys(json, requiredKeys: const [ - 'id', - 'uuid', - 'creation_date', - 'name', - 'description', - 'category', - 'muscles', - 'muscles_secondary', - 'equipment', - 'images', - 'comments' - ]); + $checkKeys( + json, + requiredKeys: const [ + 'id', + 'uuid', + 'creation_date', + 'name', + 'description', + 'category', + 'muscles', + 'muscles_secondary', + 'equipment', + 'images', + 'comments' + ], + ); return Exercise( id: json['id'] as int, uuid: json['uuid'] as String, diff --git a/lib/models/exercises/image.g.dart b/lib/models/exercises/image.g.dart index c55b4029..6ef7c62e 100644 --- a/lib/models/exercises/image.g.dart +++ b/lib/models/exercises/image.g.dart @@ -7,7 +7,10 @@ part of 'image.dart'; // ************************************************************************** ExerciseImage _$ExerciseImageFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'uuid', 'exercise_base', 'image']); + $checkKeys( + json, + requiredKeys: const ['id', 'uuid', 'exercise_base', 'image'], + ); return ExerciseImage( id: json['id'] as int, uuid: json['uuid'] as String, diff --git a/lib/models/exercises/muscle.g.dart b/lib/models/exercises/muscle.g.dart index 41820a7f..89bcb1ab 100644 --- a/lib/models/exercises/muscle.g.dart +++ b/lib/models/exercises/muscle.g.dart @@ -7,7 +7,10 @@ part of 'muscle.dart'; // ************************************************************************** Muscle _$MuscleFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'name', 'is_front']); + $checkKeys( + json, + requiredKeys: const ['id', 'name', 'is_front'], + ); return Muscle( id: json['id'] as int, name: json['name'] as String, diff --git a/lib/models/gallery/image.g.dart b/lib/models/gallery/image.g.dart index 98ad831b..d87cc4e4 100644 --- a/lib/models/gallery/image.g.dart +++ b/lib/models/gallery/image.g.dart @@ -7,7 +7,10 @@ part of 'image.dart'; // ************************************************************************** Image _$ImageFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'date', 'image']); + $checkKeys( + json, + requiredKeys: const ['id', 'date', 'image'], + ); return Image( id: json['id'] as int?, date: DateTime.parse(json['date'] as String), diff --git a/lib/models/measurements/measurement_category.g.dart b/lib/models/measurements/measurement_category.g.dart index 8c5b6538..eb887b2e 100644 --- a/lib/models/measurements/measurement_category.g.dart +++ b/lib/models/measurements/measurement_category.g.dart @@ -7,7 +7,10 @@ part of 'measurement_category.dart'; // ************************************************************************** MeasurementCategory _$MeasurementCategoryFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'name', 'unit']); + $checkKeys( + json, + requiredKeys: const ['id', 'name', 'unit'], + ); return MeasurementCategory( id: json['id'] as int?, name: json['name'] as String, diff --git a/lib/models/measurements/measurement_entry.g.dart b/lib/models/measurements/measurement_entry.g.dart index 76964759..7f6e346a 100644 --- a/lib/models/measurements/measurement_entry.g.dart +++ b/lib/models/measurements/measurement_entry.g.dart @@ -7,7 +7,10 @@ part of 'measurement_entry.dart'; // ************************************************************************** MeasurementEntry _$MeasurementEntryFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'category', 'date', 'value', 'notes']); + $checkKeys( + json, + requiredKeys: const ['id', 'category', 'date', 'value', 'notes'], + ); return MeasurementEntry( id: json['id'] as int?, category: json['category'] as int, diff --git a/lib/models/nutrition/ingredient.g.dart b/lib/models/nutrition/ingredient.g.dart index 6ffb0a9c..05ef48d7 100644 --- a/lib/models/nutrition/ingredient.g.dart +++ b/lib/models/nutrition/ingredient.g.dart @@ -7,19 +7,22 @@ part of 'ingredient.dart'; // ************************************************************************** Ingredient _$IngredientFromJson(Map json) { - $checkKeys(json, requiredKeys: const [ - 'id', - 'name', - 'creation_date', - 'energy', - 'carbohydrates', - 'carbohydrates_sugar', - 'protein', - 'fat', - 'fat_saturated', - 'fibres', - 'sodium' - ]); + $checkKeys( + json, + requiredKeys: const [ + 'id', + 'name', + 'creation_date', + 'energy', + 'carbohydrates', + 'carbohydrates_sugar', + 'protein', + 'fat', + 'fat_saturated', + 'fibres', + 'sodium' + ], + ); return Ingredient( id: json['id'] as int, name: json['name'] as String, diff --git a/lib/models/nutrition/ingredient_weight_unit.g.dart b/lib/models/nutrition/ingredient_weight_unit.g.dart index 600d0ed4..f147a2ee 100644 --- a/lib/models/nutrition/ingredient_weight_unit.g.dart +++ b/lib/models/nutrition/ingredient_weight_unit.g.dart @@ -7,7 +7,10 @@ part of 'ingredient_weight_unit.dart'; // ************************************************************************** IngredientWeightUnit _$IngredientWeightUnitFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'weight_unit', 'ingredient', 'grams', 'amount']); + $checkKeys( + json, + requiredKeys: const ['id', 'weight_unit', 'ingredient', 'grams', 'amount'], + ); return IngredientWeightUnit( id: json['id'] as int, weightUnit: WeightUnit.fromJson(json['weight_unit'] as Map), diff --git a/lib/models/nutrition/log.g.dart b/lib/models/nutrition/log.g.dart index 72c3f639..61690155 100644 --- a/lib/models/nutrition/log.g.dart +++ b/lib/models/nutrition/log.g.dart @@ -7,8 +7,10 @@ part of 'log.dart'; // ************************************************************************** Log _$LogFromJson(Map json) { - $checkKeys(json, - requiredKeys: const ['id', 'plan', 'datetime', 'ingredient', 'weight_unit', 'amount']); + $checkKeys( + json, + requiredKeys: const ['id', 'plan', 'datetime', 'ingredient', 'weight_unit', 'amount'], + ); return Log( id: json['id'] as int?, mealId: json['meal'] as int?, diff --git a/lib/models/nutrition/meal.g.dart b/lib/models/nutrition/meal.g.dart index 3d079787..296d637e 100644 --- a/lib/models/nutrition/meal.g.dart +++ b/lib/models/nutrition/meal.g.dart @@ -6,13 +6,11 @@ part of 'meal.dart'; // JsonSerializableGenerator // ************************************************************************** -Meal _$MealFromJson(Map json) { - return Meal( - id: json['id'] as int?, - time: stringToTime(json['time'] as String?), - name: json['name'] as String?, - )..planId = json['plan'] as int; -} +Meal _$MealFromJson(Map json) => Meal( + id: json['id'] as int?, + time: stringToTime(json['time'] as String?), + name: json['name'] as String?, + )..planId = json['plan'] as int; Map _$MealToJson(Meal instance) => { 'id': instance.id, diff --git a/lib/models/nutrition/meal_item.g.dart b/lib/models/nutrition/meal_item.g.dart index e0af0526..514788cc 100644 --- a/lib/models/nutrition/meal_item.g.dart +++ b/lib/models/nutrition/meal_item.g.dart @@ -7,7 +7,10 @@ part of 'meal_item.dart'; // ************************************************************************** MealItem _$MealItemFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'amount']); + $checkKeys( + json, + requiredKeys: const ['id', 'amount'], + ); return MealItem( id: json['id'] as int?, mealId: json['meal'] as int?, diff --git a/lib/models/nutrition/nutritional_plan.g.dart b/lib/models/nutrition/nutritional_plan.g.dart index 024e87db..661a9f47 100644 --- a/lib/models/nutrition/nutritional_plan.g.dart +++ b/lib/models/nutrition/nutritional_plan.g.dart @@ -7,7 +7,10 @@ part of 'nutritional_plan.dart'; // ************************************************************************** NutritionalPlan _$NutritionalPlanFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'description', 'creation_date']); + $checkKeys( + json, + requiredKeys: const ['id', 'description', 'creation_date'], + ); return NutritionalPlan( id: json['id'] as int?, description: json['description'] as String, diff --git a/lib/models/nutrition/weight_unit.g.dart b/lib/models/nutrition/weight_unit.g.dart index b8a01b2b..6f2b9607 100644 --- a/lib/models/nutrition/weight_unit.g.dart +++ b/lib/models/nutrition/weight_unit.g.dart @@ -7,7 +7,10 @@ part of 'weight_unit.dart'; // ************************************************************************** WeightUnit _$WeightUnitFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'name']); + $checkKeys( + json, + requiredKeys: const ['id', 'name'], + ); return WeightUnit( id: json['id'] as int, name: json['name'] as String, diff --git a/lib/models/workouts/day.g.dart b/lib/models/workouts/day.g.dart index 6ab6e972..0f1b6736 100644 --- a/lib/models/workouts/day.g.dart +++ b/lib/models/workouts/day.g.dart @@ -7,7 +7,10 @@ part of 'day.dart'; // ************************************************************************** Day _$DayFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'training', 'description', 'day']); + $checkKeys( + json, + requiredKeys: const ['id', 'training', 'description', 'day'], + ); return Day() ..id = json['id'] as int? ..workoutId = json['training'] as int diff --git a/lib/models/workouts/log.g.dart b/lib/models/workouts/log.g.dart index c9717af3..cb2815e3 100644 --- a/lib/models/workouts/log.g.dart +++ b/lib/models/workouts/log.g.dart @@ -7,16 +7,19 @@ part of 'log.dart'; // ************************************************************************** Log _$LogFromJson(Map json) { - $checkKeys(json, requiredKeys: const [ - 'id', - 'exercise', - 'workout', - 'reps', - 'repetition_unit', - 'weight', - 'weight_unit', - 'date' - ]); + $checkKeys( + json, + requiredKeys: const [ + 'id', + 'exercise', + 'workout', + 'reps', + 'repetition_unit', + 'weight', + 'weight_unit', + 'date' + ], + ); return Log( id: json['id'] as int?, exerciseId: json['exercise'] as int, diff --git a/lib/models/workouts/repetition_unit.g.dart b/lib/models/workouts/repetition_unit.g.dart index 40829256..33e6a815 100644 --- a/lib/models/workouts/repetition_unit.g.dart +++ b/lib/models/workouts/repetition_unit.g.dart @@ -7,7 +7,10 @@ part of 'repetition_unit.dart'; // ************************************************************************** RepetitionUnit _$RepetitionUnitFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'name']); + $checkKeys( + json, + requiredKeys: const ['id', 'name'], + ); return RepetitionUnit( id: json['id'] as int, name: json['name'] as String, diff --git a/lib/models/workouts/session.g.dart b/lib/models/workouts/session.g.dart index b00ec0c2..79f4fee4 100644 --- a/lib/models/workouts/session.g.dart +++ b/lib/models/workouts/session.g.dart @@ -7,8 +7,10 @@ part of 'session.dart'; // ************************************************************************** WorkoutSession _$WorkoutSessionFromJson(Map json) { - $checkKeys(json, - requiredKeys: const ['id', 'workout', 'date', 'impression', 'time_start', 'time_end']); + $checkKeys( + json, + requiredKeys: const ['id', 'workout', 'date', 'impression', 'time_start', 'time_end'], + ); return WorkoutSession() ..id = json['id'] as int? ..workoutId = json['workout'] as int diff --git a/lib/models/workouts/set.g.dart b/lib/models/workouts/set.g.dart index 9c6f83e2..2548fc12 100644 --- a/lib/models/workouts/set.g.dart +++ b/lib/models/workouts/set.g.dart @@ -7,7 +7,10 @@ part of 'set.dart'; // ************************************************************************** Set _$SetFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'sets', 'order', 'comment']); + $checkKeys( + json, + requiredKeys: const ['id', 'sets', 'order', 'comment'], + ); return Set( day: json['exerciseday'] as int, sets: json['sets'] as int, diff --git a/lib/models/workouts/setting.g.dart b/lib/models/workouts/setting.g.dart index d99751fa..05715589 100644 --- a/lib/models/workouts/setting.g.dart +++ b/lib/models/workouts/setting.g.dart @@ -7,18 +7,21 @@ part of 'setting.dart'; // ************************************************************************** Setting _$SettingFromJson(Map json) { - $checkKeys(json, requiredKeys: const [ - 'id', - 'set', - 'order', - 'exercise', - 'repetition_unit', - 'reps', - 'weight', - 'weight_unit', - 'comment', - 'rir' - ]); + $checkKeys( + json, + requiredKeys: const [ + 'id', + 'set', + 'order', + 'exercise', + 'repetition_unit', + 'reps', + 'weight', + 'weight_unit', + 'comment', + 'rir' + ], + ); return Setting( id: json['id'] as int?, setId: json['set'] as int, diff --git a/lib/models/workouts/weight_unit.g.dart b/lib/models/workouts/weight_unit.g.dart index b8a01b2b..6f2b9607 100644 --- a/lib/models/workouts/weight_unit.g.dart +++ b/lib/models/workouts/weight_unit.g.dart @@ -7,7 +7,10 @@ part of 'weight_unit.dart'; // ************************************************************************** WeightUnit _$WeightUnitFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'name']); + $checkKeys( + json, + requiredKeys: const ['id', 'name'], + ); return WeightUnit( id: json['id'] as int, name: json['name'] as String, diff --git a/lib/models/workouts/workout_plan.g.dart b/lib/models/workouts/workout_plan.g.dart index 0a1dfb0a..ac1d6fa9 100644 --- a/lib/models/workouts/workout_plan.g.dart +++ b/lib/models/workouts/workout_plan.g.dart @@ -7,7 +7,10 @@ part of 'workout_plan.dart'; // ************************************************************************** WorkoutPlan _$WorkoutPlanFromJson(Map json) { - $checkKeys(json, requiredKeys: const ['id', 'creation_date', 'name', 'description']); + $checkKeys( + json, + requiredKeys: const ['id', 'creation_date', 'name', 'description'], + ); return WorkoutPlan( id: json['id'] as int?, creationDate: DateTime.parse(json['creation_date'] as String), diff --git a/lib/providers/auth.dart b/lib/providers/auth.dart index 45c12cf0..e1f1f6db 100644 --- a/lib/providers/auth.dart +++ b/lib/providers/auth.dart @@ -39,34 +39,38 @@ class AuthProvider with ChangeNotifier { String? serverUrl; String? serverVersion; PackageInfo? applicationVersion; + Map metadata = {}; + + static const MIN_APP_VERSION_URL = 'min-app-version'; + static const SERVER_VERSION_URL = 'version'; + static const REGISTRATION_URL = 'register'; + static const LOGIN_URL = 'login'; + + late http.Client client; + + AuthProvider([http.Client? client, bool? checkMetadata]) { + this.client = client ?? http.Client(); + + // TODO: this is a workaround since AndroidMetadata doesn't work while running tests + if (checkMetadata ?? true) { + try { + AndroidMetadata.metaDataAsMap.then((value) => metadata = value!); + } on PlatformException { + throw Exception('An error occurred reading the metadata from AndroidManifest'); + } catch (error) {} + } + } /// flag to indicate that the application has successfully loaded all initial data bool dataInit = false; - // DateTime _expiryDate; - // String _userId; - // Timer _authTimer; - bool get isAuth { return token != null; } - String? get token2 { - // if (_expiryDate != null && - // _expiryDate.isAfter(DateTime.now()) && - // _token != null) { - return token; - // } - // return null; - } - - // String get userId { - // return _userId; - // } - /// Server application version Future setServerVersion() async { - final response = await http.get(makeUri(serverUrl!, 'version')); + final response = await client.get(makeUri(serverUrl!, SERVER_VERSION_URL)); final responseData = json.decode(response.body); serverVersion = responseData; } @@ -78,15 +82,19 @@ class AuthProvider with ChangeNotifier { } /// Checking if there is a new version of the application. - Future neededApplicationUpdate() async { - if (!ENABLED_UPDATE) { + Future applicationUpdateRequired([String? version]) async { + if (metadata.containsKey('wger.check_min_app_version') || + metadata['wger.check_min_app_version'] == 'false') { return false; } - final response = await http.get(makeUri(serverUrl!, 'min-app-version')); - final applicationLatestVersion = json.decode(response.body); - final currentVersion = Version.parse(applicationVersion!.version); - final latestAppVersion = Version.parse(applicationLatestVersion); - return latestAppVersion > currentVersion; + + 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(response.body); + return requiredAppVersion >= currentVersion; } /// Registers a new user @@ -95,27 +103,18 @@ class AuthProvider with ChangeNotifier { required String password, required String email, required String serverUrl}) async { - final uri = Uri.parse('$serverUrl/api/v2/register/'); - Map? metadata = {}; - - // Read the api key from the manifest file - try { - metadata = await AndroidMetadata.metaDataAsMap; - } on PlatformException { - throw Exception('An error occurred reading the API key'); - } - // Register try { final Map data = {'username': username, 'password': password}; if (email != '') { data['email'] = email; } - final response = await http.post( - uri, + final response = await client.post( + makeUri(serverUrl, REGISTRATION_URL), headers: { HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8', - HttpHeaders.authorizationHeader: "Token ${metadata!['wger.api_key']}" + HttpHeaders.authorizationHeader: 'Token ${metadata[MANIFEST_KEY_API]}', + HttpHeaders.userAgentHeader: getAppNameHeader(), }, body: json.encode(data), ); @@ -133,14 +132,14 @@ class AuthProvider with ChangeNotifier { /// Authenticates a user Future login(String username, String password, String serverUrl) async { - final uri = Uri.parse('$serverUrl/api/v2/login/'); await logout(shouldNotify: false); try { - final response = await http.post( - uri, + final response = await client.post( + makeUri(serverUrl, LOGIN_URL), headers: { HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8', + HttpHeaders.userAgentHeader: getAppNameHeader(), }, body: json.encode({'username': username, 'password': password}), ); @@ -154,13 +153,6 @@ class AuthProvider with ChangeNotifier { this.serverUrl = serverUrl; token = responseData['token']; - // _userId = responseData['localId']; - // _expiryDate = DateTime.now().add( - // Duration( - // seconds: int.parse(responseData['expiresIn']), - // ), - // ); - notifyListeners(); // store login data in shared preferences @@ -168,7 +160,6 @@ class AuthProvider with ChangeNotifier { final userData = json.encode({ 'token': token, 'serverUrl': this.serverUrl, - // 'expiryDate': _expiryDate.toIso8601String(), }); final serverData = json.encode({ 'serverUrl': this.serverUrl, @@ -201,16 +192,9 @@ class AuthProvider with ChangeNotifier { return false; } final extractedUserData = json.decode(prefs.getString('userData')!); - // final expiryDate = DateTime.parse(extractedUserData['expiryDate']); - - // if (expiryDate.isBefore(DateTime.now())) { - // return false; - // } token = extractedUserData['token']; serverUrl = extractedUserData['serverUrl']; - // _userId = extractedUserData['userId']; - // _expiryDate = expiryDate; log('autologin successful'); setApplicationVersion(); @@ -225,12 +209,6 @@ class AuthProvider with ChangeNotifier { token = null; serverUrl = null; dataInit = false; - // _userId = null; - // _expiryDate = null; - // if (_authTimer != null) { - // _authTimer.cancel(); - // _authTimer = null; - // } if (shouldNotify) { notifyListeners(); @@ -240,24 +218,16 @@ class AuthProvider with ChangeNotifier { prefs.remove('userData'); } - // void _autoLogout() { - // if (_authTimer != null) { - // _authTimer.cancel(); - // } - // final timeToExpiry = _expiryDate.difference(DateTime.now()).inSeconds; - // _authTimer = Timer(Duration(seconds: timeToExpiry), logout); - // } - /// Returns the application name and version /// /// This is used in the headers when talking to the API String getAppNameHeader() { String out = ''; if (applicationVersion != null) { - out = '${applicationVersion!.version} ' + out = '/${applicationVersion!.version} ' '(${applicationVersion!.packageName}; ' 'build: ${applicationVersion!.buildNumber})'; } - return 'wger App/$out'; + return 'wger App$out'; } } diff --git a/lib/providers/exercises.dart b/lib/providers/exercises.dart index 4cdd33c7..080196dc 100644 --- a/lib/providers/exercises.dart +++ b/lib/providers/exercises.dart @@ -19,7 +19,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; @@ -65,8 +64,7 @@ class ExercisesProvider extends WgerBaseProvider with ChangeNotifier { } Future fetchAndSetCategories() async { - final response = await client.get(makeUrl(categoriesUrlPath)); - final categories = json.decode(response.body) as Map; + final categories = await fetch(makeUrl(categoriesUrlPath)); try { for (final category in categories['results']) { _categories.add(ExerciseCategory.fromJson(category)); @@ -77,8 +75,7 @@ class ExercisesProvider extends WgerBaseProvider with ChangeNotifier { } Future fetchAndSetMuscles() async { - final response = await client.get(makeUrl(musclesUrlPath)); - final muscles = json.decode(response.body) as Map; + final muscles = await fetch(makeUrl(musclesUrlPath)); try { for (final muscle in muscles['results']) { _muscles.add(Muscle.fromJson(muscle)); @@ -89,8 +86,7 @@ class ExercisesProvider extends WgerBaseProvider with ChangeNotifier { } Future fetchAndSetEquipment() async { - final response = await client.get(makeUrl(equipmentUrlPath)); - final equipments = json.decode(response.body) as Map; + final equipments = await fetch(makeUrl(equipmentUrlPath)); try { for (final equipment in equipments['results']) { _equipment.add(Equipment.fromJson(equipment)); @@ -142,16 +138,7 @@ class ExercisesProvider extends WgerBaseProvider with ChangeNotifier { await fetchAndSetCategories(); await fetchAndSetMuscles(); await fetchAndSetEquipment(); - - final response = await client.get( - makeUrl( - exerciseInfoUrlPath, - query: {'limit': '1000'}, - ), - headers: { - HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8', - }); - final exercisesData = json.decode(utf8.decode(response.bodyBytes)) as Map; + final exercisesData = await fetch(makeUrl(exerciseInfoUrlPath, query: {'limit': '1000'})); try { // Load exercises diff --git a/lib/providers/nutrition.dart b/lib/providers/nutrition.dart index c7052c73..5fcc9d62 100644 --- a/lib/providers/nutrition.dart +++ b/lib/providers/nutrition.dart @@ -330,7 +330,7 @@ class NutritionPlansProvider extends WgerBaseProvider with ChangeNotifier { Future logMealToDiary(Meal meal) async { for (final item in meal.mealItems) { final plan = findById(meal.planId); - final Log log = Log.fromMealItem(item, plan.id!, meal.id!); + final Log log = Log.fromMealItem(item, plan.id!, meal.id); final data = await post(log.toJson(), makeUrl(_nutritionDiaryPath)); log.id = data['id']; @@ -339,6 +339,18 @@ class NutritionPlansProvider extends WgerBaseProvider with ChangeNotifier { notifyListeners(); } + /// Log custom ingredient to nutrition diary + Future logIngredentToDiary(MealItem mealItem, int planId, [DateTime? dateTime]) async { + final plan = findById(planId); + mealItem.ingredientObj = await fetchIngredient(mealItem.ingredientId); + final Log log = Log.fromMealItem(mealItem, plan.id!, null, dateTime); + + final data = await post(log.toJson(), makeUrl(_nutritionDiaryPath)); + log.id = data['id']; + plan.logs.add(log); + notifyListeners(); + } + /// Deletes a log entry Future deleteLog(int logId, int planId) async { await deleteRequest(_nutritionDiaryPath, logId); diff --git a/lib/screens/auth_screen.dart b/lib/screens/auth_screen.dart index 39c7d5d3..6a80be1b 100644 --- a/lib/screens/auth_screen.dart +++ b/lib/screens/auth_screen.dart @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -import 'package:android_metadata/android_metadata.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -119,11 +118,10 @@ class _AuthCardState extends State { // // If not, the user will not be able to register via the app try { - AndroidMetadata.metaDataAsMap.then((data) { - if (!data!.containsKey('wger.api_key') || data['wger.api_key'] == '') { - _canRegister = false; - } - }); + final metadata = Provider.of(context, listen: false).metadata; + if (metadata.containsKey(MANIFEST_KEY_API) || metadata[MANIFEST_KEY_API] == '') { + _canRegister = false; + } } on PlatformException { _canRegister = false; } diff --git a/lib/screens/home_tabs_screen.dart b/lib/screens/home_tabs_screen.dart index e3c6f1b1..6621e4f9 100644 --- a/lib/screens/home_tabs_screen.dart +++ b/lib/screens/home_tabs_screen.dart @@ -129,12 +129,12 @@ class _HomeTabsScreenState extends State with SingleTickerProvid child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Center( + const Center( child: SizedBox( height: 70, child: RiveAnimation.asset( 'assets/animations/wger_logo.riv', - animations: const ['idle_loop2'], + animations: ['idle_loop2'], ), ), ), diff --git a/lib/screens/nutritional_plan_screen.dart b/lib/screens/nutritional_plan_screen.dart index 6baeefa3..fa45e08c 100644 --- a/lib/screens/nutritional_plan_screen.dart +++ b/lib/screens/nutritional_plan_screen.dart @@ -44,7 +44,20 @@ class NutritionalPlanScreen extends StatelessWidget { return Scaffold( //appBar: getAppBar(nutritionalPlan), - //drawer: AppDrawer(), + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.history_edu), + onPressed: () { + Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context).logIngredient, + IngredientLogForm(_nutritionalPlan), + hasListView: true, + ), + ); + }, + ), body: CustomScrollView( slivers: [ SliverAppBar( diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart index 3ee49f51..19a9ae72 100644 --- a/lib/theme/theme.dart +++ b/lib/theme/theme.dart @@ -58,8 +58,8 @@ final ThemeData wgerTheme = ThemeData( // Show icons in the system's bar in light colors appBarTheme: const AppBarTheme( - brightness: Brightness.dark, systemOverlayStyle: SystemUiOverlayStyle.dark, + color: wgerPrimaryColor, ), /* diff --git a/lib/widgets/app_drawer.dart b/lib/widgets/app_drawer.dart deleted file mode 100644 index 6c53d093..00000000 --- a/lib/widgets/app_drawer.dart +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:provider/provider.dart'; -import 'package:wger/providers/auth.dart'; -import 'package:wger/providers/body_weight.dart'; -import 'package:wger/providers/gallery.dart'; -import 'package:wger/providers/nutrition.dart'; -import 'package:wger/providers/workout_plans.dart'; -import 'package:wger/widgets/core/about.dart'; - -class AppDrawer extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Drawer( - child: Column( - children: [ - AppBar( - title: const Text('wger'), - automaticallyImplyLeading: false, - ), - ListTile( - //dense: true, - leading: const Icon(Icons.exit_to_app), - title: Text(AppLocalizations.of(context).logout), - onTap: () { - Provider.of(context, listen: false).logout(); - Provider.of(context, listen: false).clear(); - Provider.of(context, listen: false).clear(); - Provider.of(context, listen: false).clear(); - Provider.of(context, listen: false).clear(); - Navigator.of(context).pop(); - Navigator.of(context).pushReplacementNamed('/'); - }, - ), - WgerAboutListTile() - ], - ), - ); - } -} diff --git a/lib/widgets/dashboard/widgets.dart b/lib/widgets/dashboard/widgets.dart index 8b779376..6048f0a9 100644 --- a/lib/widgets/dashboard/widgets.dart +++ b/lib/widgets/dashboard/widgets.dart @@ -199,14 +199,29 @@ class _DashboardNutritionWidgetState extends State { ), if (_hasContent) Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton( - child: Text(AppLocalizations.of(context).goToDetailPage), - onPressed: () { - Navigator.of(context) - .pushNamed(NutritionalPlanScreen.routeName, arguments: _plan); - }), + child: Text(AppLocalizations.of(context).logIngredient), + onPressed: () { + Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context).logIngredient, + IngredientLogForm(_plan!), + hasListView: true, + ), + ); + }, + ), + TextButton( + child: Text(AppLocalizations.of(context).goToDetailPage), + onPressed: () { + Navigator.of(context) + .pushNamed(NutritionalPlanScreen.routeName, arguments: _plan); + }, + ), ], ), ], diff --git a/lib/widgets/nutrition/forms.dart b/lib/widgets/nutrition/forms.dart index 3a0815e6..70e0725c 100644 --- a/lib/widgets/nutrition/forms.dart +++ b/lib/widgets/nutrition/forms.dart @@ -18,7 +18,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:provider/provider.dart'; import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/helpers/consts.dart'; @@ -29,6 +28,7 @@ import 'package:wger/models/nutrition/meal_item.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/providers/nutrition.dart'; import 'package:wger/screens/nutritional_plan_screen.dart'; +import 'package:wger/widgets/nutrition/widgets.dart'; class MealForm extends StatelessWidget { late final Meal _meal; @@ -115,18 +115,18 @@ class MealForm extends StatelessWidget { class MealItemForm extends StatelessWidget { final Meal _meal; late final MealItem _mealItem; - final List _listMealItems; + final _form = GlobalKey(); + final _ingredientIdController = TextEditingController(); + final _ingredientController = TextEditingController(); + final _amountController = TextEditingController(); + MealItemForm(this._meal, this._listMealItems, [mealItem]) { _mealItem = mealItem ?? MealItem.empty(); _mealItem.mealId = _meal.id!; } - final _form = GlobalKey(); - final _ingredientController = TextEditingController(); - final _amountController = TextEditingController(); - @override Widget build(BuildContext context) { final String unit = AppLocalizations.of(context).g; @@ -136,37 +136,7 @@ class MealItemForm extends StatelessWidget { key: _form, child: Column( children: [ - TypeAheadFormField( - textFieldConfiguration: TextFieldConfiguration( - controller: _ingredientController, - decoration: InputDecoration(labelText: AppLocalizations.of(context).ingredient), - ), - suggestionsCallback: (pattern) async { - return Provider.of(context, listen: false).searchIngredient( - pattern, - Localizations.localeOf(context).languageCode, - ); - }, - itemBuilder: (context, dynamic suggestion) { - return ListTile( - title: Text(suggestion['value']), - subtitle: Text(suggestion['data']['id'].toString()), - ); - }, - transitionBuilder: (context, suggestionsBox, controller) { - return suggestionsBox; - }, - onSuggestionSelected: (dynamic suggestion) { - _mealItem.ingredientId = suggestion['data']['id']; - _ingredientController.text = suggestion['value']; - }, - validator: (value) { - if (value!.isEmpty) { - return AppLocalizations.of(context).selectIngredient; - } - return null; - }, - ), + IngredientTypeahead(_ingredientIdController, _ingredientController), TextFormField( decoration: InputDecoration(labelText: AppLocalizations.of(context).weight), controller: _amountController, @@ -191,6 +161,7 @@ class MealItemForm extends StatelessWidget { return; } _form.currentState!.save(); + _mealItem.ingredientId = int.parse(_ingredientIdController.text); try { Provider.of(context, listen: false) @@ -217,6 +188,8 @@ class MealItemForm extends StatelessWidget { child: ListTile( onTap: () { _ingredientController.text = _listMealItems[index].ingredientObj.name; + _ingredientIdController.text = + _listMealItems[index].ingredientObj.id.toString(); _amountController.text = _listMealItems[index].amount.toStringAsFixed(0); _mealItem.ingredientId = _listMealItems[index].ingredientId; _mealItem.amount = _listMealItems[index].amount; @@ -236,6 +209,130 @@ class MealItemForm extends StatelessWidget { } } +class IngredientLogForm extends StatelessWidget { + late MealItem _mealItem; + final NutritionalPlan _plan; + + final _form = GlobalKey(); + final _ingredientController = TextEditingController(); + final _ingredientIdController = TextEditingController(); + final _amountController = TextEditingController(); + final _dateController = TextEditingController(); + + IngredientLogForm(this._plan) { + _mealItem = MealItem.empty(); + _dateController.text = toDate(DateTime.now())!; + } + + @override + Widget build(BuildContext context) { + final diaryEntries = _plan.logs; + final String unit = AppLocalizations.of(context).g; + + return Container( + margin: const EdgeInsets.all(20), + child: Form( + key: _form, + child: Column( + children: [ + IngredientTypeahead(_ingredientIdController, _ingredientController), + TextFormField( + decoration: InputDecoration(labelText: AppLocalizations.of(context).weight), + controller: _amountController, + keyboardType: TextInputType.number, + onFieldSubmitted: (_) {}, + onSaved: (newValue) { + _mealItem.amount = double.parse(newValue!); + }, + validator: (value) { + try { + double.parse(value!); + } catch (error) { + return AppLocalizations.of(context).enterValidNumber; + } + return null; + }, + ), + TextFormField( + readOnly: true, // Stop keyboard from appearing + decoration: InputDecoration( + labelText: AppLocalizations.of(context).date, + suffixIcon: const Icon(Icons.calendar_today_outlined), + ), + enableInteractiveSelection: false, + controller: _dateController, + onTap: () async { + // Show Date Picker Here + final pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(DateTime.now().year - 10), + lastDate: DateTime.now(), + ); + + if (pickedDate != null) { + _dateController.text = toDate(pickedDate)!; + } + }, + onSaved: (newValue) { + _dateController.text = newValue!; + }, + ), + ElevatedButton( + child: Text(AppLocalizations.of(context).save), + onPressed: () async { + if (!_form.currentState!.validate()) { + return; + } + _form.currentState!.save(); + _mealItem.ingredientId = int.parse(_ingredientIdController.text); + + try { + Provider.of(context, listen: false).logIngredentToDiary( + _mealItem, _plan.id!, DateTime.parse(_dateController.text)); + } on WgerHttpException catch (error) { + showHttpExceptionErrorDialog(error, context); + } catch (error) { + showErrorDialog(error, context); + } + Navigator.of(context).pop(); + }, + ), + if (diaryEntries.isNotEmpty) const SizedBox(height: 10.0), + Container( + child: Text(AppLocalizations.of(context).recentlyUsedIngredients), + padding: const EdgeInsets.all(10.0), + ), + Expanded( + child: ListView.builder( + itemCount: diaryEntries.length, + shrinkWrap: true, + itemBuilder: (context, index) { + return Card( + child: ListTile( + onTap: () { + _ingredientController.text = diaryEntries[index].ingredientObj.name; + _ingredientIdController.text = + diaryEntries[index].ingredientObj.id.toString(); + _amountController.text = diaryEntries[index].amount.toStringAsFixed(0); + _mealItem.ingredientId = diaryEntries[index].ingredientId; + _mealItem.amount = diaryEntries[index].amount; + }, + title: Text(_plan.logs[index].ingredientObj.name), + subtitle: Text('${diaryEntries[index].amount.toStringAsFixed(0)}$unit'), + trailing: const Icon(Icons.copy), + ), + ); + }, + ), + ) + ], + ), + ), + ); + } +} + class PlanForm extends StatelessWidget { final _form = GlobalKey(); final _descriptionController = TextEditingController(); diff --git a/lib/widgets/nutrition/widgets.dart b/lib/widgets/nutrition/widgets.dart new file mode 100644 index 00000000..6438ce30 --- /dev/null +++ b/lib/widgets/nutrition/widgets.dart @@ -0,0 +1,74 @@ +/* + * 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:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/nutrition.dart'; + +class IngredientTypeahead extends StatefulWidget { + final TextEditingController _ingredientController; + final TextEditingController _ingredientIdController; + + const IngredientTypeahead(this._ingredientIdController, this._ingredientController); + + @override + _IngredientTypeaheadState createState() => _IngredientTypeaheadState(); +} + +class _IngredientTypeaheadState extends State { + @override + Widget build(BuildContext context) { + return TypeAheadFormField( + textFieldConfiguration: TextFieldConfiguration( + controller: widget._ingredientController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).searchIngredient, + suffixIcon: const Icon(Icons.search), + ), + ), + suggestionsCallback: (pattern) async { + return Provider.of(context, listen: false).searchIngredient( + pattern, + Localizations.localeOf(context).languageCode, + ); + }, + itemBuilder: (context, dynamic suggestion) { + return ListTile( + title: Text(suggestion['value']), + subtitle: Text(suggestion['data']['id'].toString()), + ); + }, + transitionBuilder: (context, suggestionsBox, controller) { + return suggestionsBox; + }, + onSuggestionSelected: (dynamic suggestion) { + widget._ingredientIdController.text = suggestion['data']['id'].toString(); + widget._ingredientController.text = suggestion['value']; + }, + validator: (value) { + if (value!.isEmpty) { + return AppLocalizations.of(context).selectIngredient; + } + return null; + }, + ); + } +} diff --git a/lib/widgets/workouts/log.dart b/lib/widgets/workouts/log.dart index cb245adb..15f7e809 100644 --- a/lib/widgets/workouts/log.dart +++ b/lib/widgets/workouts/log.dart @@ -98,7 +98,7 @@ class _DayLogWidgetState extends State { children: [ Text(log.singleLogRepTextNoNl), IconButton( - icon: Icon(Icons.delete), + icon: const Icon(Icons.delete), onPressed: () async { showDeleteDialog( context, exercise.name, log, exercise, widget._exerciseData); diff --git a/pubspec.lock b/pubspec.lock index d957b2c6..6fe7ae66 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "22.0.0" + version: "30.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "1.7.1" + version: "2.7.0" android_metadata: dependency: "direct main" description: @@ -42,7 +42,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.6.1" + version: "2.8.1" boolean_selector: dependency: transitive description: @@ -56,7 +56,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" build_config: dependency: transitive description: @@ -70,28 +70,28 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.5" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.5" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "7.1.0" + version: "7.2.2" built_collection: dependency: transitive description: @@ -112,7 +112,7 @@ packages: name: camera url: "https://pub.dartlang.org" source: hosted - version: "0.9.2+2" + version: "0.9.4+5" camera_platform_interface: dependency: transitive description: @@ -120,6 +120,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + camera_web: + dependency: transitive + description: + name: camera_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1+1" + change: + dependency: transitive + description: + name: change + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" characters: dependency: transitive description: @@ -133,21 +147,21 @@ packages: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.1" charts_common: dependency: transitive description: name: charts_common url: "https://pub.dartlang.org" source: hosted - version: "0.11.0" + version: "0.12.0" charts_flutter: dependency: "direct main" description: name: charts_flutter url: "https://pub.dartlang.org" source: hosted - version: "0.11.0" + version: "0.12.0" checked_yaml: dependency: transitive description: @@ -161,7 +175,7 @@ packages: name: chewie url: "https://pub.dartlang.org" source: hosted - version: "1.2.2" + version: "1.1.0" chewie_audio: dependency: transitive description: @@ -169,6 +183,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + cider: + dependency: "direct dev" + description: + name: cider + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" cli_util: dependency: transitive description: @@ -231,14 +252,14 @@ packages: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.2.0" equatable: dependency: "direct main" description: @@ -279,13 +300,20 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_barcode_scanner: + dependency: "direct main" + description: + name: flutter_barcode_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" flutter_calendar_carousel: dependency: "direct main" description: name: flutter_calendar_carousel url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.1.0" flutter_html: dependency: "direct main" description: @@ -346,21 +374,21 @@ packages: name: flutter_math_fork url: "https://pub.dartlang.org" source: hosted - version: "0.3.3+1" + version: "0.5.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.5" flutter_svg: dependency: transitive description: name: flutter_svg url: "https://pub.dartlang.org" source: hosted - version: "0.22.0" + version: "0.23.0+1" flutter_test: dependency: "direct dev" description: flutter @@ -372,7 +400,7 @@ packages: name: flutter_typeahead url: "https://pub.dartlang.org" source: hosted - version: "3.2.1" + version: "3.2.3" flutter_web_plugins: dependency: transitive description: flutter @@ -398,7 +426,7 @@ packages: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" graphs: dependency: transitive description: @@ -419,7 +447,7 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.3" + version: "0.13.4" http_multi_server: dependency: transitive description: @@ -447,7 +475,7 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.8.4+1" + version: "0.8.4+4" image_picker_for_web: dependency: transitive description: @@ -489,14 +517,21 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.0.1" + version: "4.3.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "4.1.4" + version: "6.0.1" + klizma: + dependency: transitive + description: + name: klizma + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" lints: dependency: transitive description: @@ -511,6 +546,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.2" + markdown: + dependency: transitive + description: + name: markdown + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.1" + marker: + dependency: transitive + description: + name: marker + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.2" matcher: dependency: transitive description: @@ -524,7 +573,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.7.0" mime: dependency: transitive description: @@ -538,7 +587,7 @@ packages: name: mockito url: "https://pub.dartlang.org" source: hosted - version: "5.0.15" + version: "5.0.16" nested: dependency: transitive description: @@ -601,7 +650,7 @@ packages: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.2" path_provider_platform_interface: dependency: transitive description: @@ -615,7 +664,7 @@ packages: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" pedantic: dependency: transitive description: @@ -629,7 +678,7 @@ packages: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.4.0" platform: dependency: transitive description: @@ -657,14 +706,14 @@ packages: name: process url: "https://pub.dartlang.org" source: hosted - version: "4.2.3" + version: "4.2.4" provider: dependency: "direct main" description: name: provider url: "https://pub.dartlang.org" source: hosted - version: "5.0.0" + version: "6.0.1" pub_semver: dependency: transitive description: @@ -678,7 +727,7 @@ packages: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" quiver: dependency: transitive description: @@ -686,27 +735,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1+1" + rfc_6901: + dependency: transitive + description: + name: rfc_6901 + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" rive: dependency: "direct main" description: name: rive url: "https://pub.dartlang.org" source: hosted - version: "0.7.28" + version: "0.7.33" shared_preferences: dependency: "direct main" description: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.0.7" + version: "2.0.9" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.9" + shared_preferences_ios: + dependency: transitive + description: + name: shared_preferences_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.8" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.3" shared_preferences_macos: dependency: transitive description: @@ -734,7 +804,7 @@ packages: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.3" shelf: dependency: transitive description: @@ -767,7 +837,14 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.1.1" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" source_span: dependency: transitive description: @@ -823,7 +900,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.4.2" timing: dependency: transitive description: @@ -851,7 +928,7 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.0.10" + version: "6.0.15" url_launcher_linux: dependency: transitive description: @@ -901,13 +978,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + version_manipulation: + dependency: transitive + description: + name: version_manipulation + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" video_player: dependency: transitive description: name: video_player url: "https://pub.dartlang.org" source: hosted - version: "2.2.3" + version: "2.2.7" video_player_platform_interface: dependency: transitive description: @@ -963,7 +1047,7 @@ packages: name: watcher url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" web_socket_channel: dependency: transitive description: @@ -977,14 +1061,35 @@ packages: name: webview_flutter url: "https://pub.dartlang.org" source: hosted - version: "2.0.13" + version: "2.3.1" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.1" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.2.10" + version: "2.3.0" xdg_directories: dependency: transitive description: @@ -998,7 +1103,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "5.1.2" + version: "5.3.1" yaml: dependency: transitive description: @@ -1007,5 +1112,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.13.0 <3.0.0" - flutter: ">=2.2.0" + dart: ">=2.14.0 <3.0.0" + flutter: ">=2.5.0" diff --git a/pubspec.yaml b/pubspec.yaml index b97a1891..5551bdb7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # github action, the current versions are ignored. # - the version number is taken from the git branch release/x.y.z # - the build number is computed by reading the last one from the play store and increased by one -version: 0.2.0+11 +version: 1.4.0+24 environment: sdk: '>=2.12.0 <3.0.0' @@ -33,9 +33,10 @@ dependencies: android_metadata: ^0.2.1 camera: ^0.9.2+2 - charts_flutter: ^0.11.0 + charts_flutter: ^0.12.0 collection: ^1.15.0-nullsafety.4 cupertino_icons: ^1.0.0 + equatable: ^2.0.3 flutter_calendar_carousel: ^2.0.3 flutter_html: ^2.1.2 flutter_typeahead: ^3.2.0 @@ -43,15 +44,14 @@ dependencies: http: ^0.13.3 image_picker: ^0.8.4+1 intl: ^0.17.0 - json_annotation: ^4.0.1 + json_annotation: ^4.3.0 version: ^2.0.0 package_info: ^2.0.2 - provider: ^5.0.0 - rive: 0.7.28 + provider: ^6.0.1 + rive: ^0.7.33 shared_preferences: ^2.0.7 table_calendar: ^3.0.2 url_launcher: ^6.0.10 - equatable: ^2.0.3 dev_dependencies: flutter_test: @@ -60,10 +60,11 @@ dev_dependencies: # sdk: flutter build_runner: ^2.1.2 flutter_launcher_icons: ^0.9.1 - json_serializable: ^4.1.4 + json_serializable: ^6.0.1 mockito: ^5.0.15 network_image_mock: ^2.0.1 flutter_lints: ^1.0.4 + cider: ^0.1.0 flutter_icons: android: true diff --git a/test/auth/auth_provider_test.dart b/test/auth/auth_provider_test.dart new file mode 100644 index 00000000..8dc53fd9 --- /dev/null +++ b/test/auth/auth_provider_test.dart @@ -0,0 +1,62 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart'; +import 'package:mockito/mockito.dart'; +import 'package:wger/providers/auth.dart'; + +import '../other/base_provider_test.mocks.dart'; + +void main() { + late AuthProvider authProvider; + late MockClient mockClient; + + final Uri tVersionUri = Uri( + scheme: 'http', + host: 'localhost', + path: 'api/v2/min-app-version/', + ); + + setUp(() { + mockClient = MockClient(); + authProvider = AuthProvider(mockClient, false); + authProvider.serverUrl = 'http://localhost'; + }); + + group('min application version check', () { + 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'); + + // assert + expect(updateNeeded, false); + }); + + 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'); + + // assert + expect(updateNeeded, true); + }); + + 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'); + + // assert + expect(updateNeeded, true); + }); + + 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'); + + // assert + expect(updateNeeded, true); //!!! + }); + }); +} diff --git a/test/auth_screen_test.dart b/test/auth/auth_screen_test.dart similarity index 100% rename from test/auth_screen_test.dart rename to test/auth/auth_screen_test.dart diff --git a/test/gallery_form_test.dart b/test/gallery/gallery_form_test.dart similarity index 97% rename from test/gallery_form_test.dart rename to test/gallery/gallery_form_test.dart index 690e2cea..259c2a7d 100644 --- a/test/gallery_form_test.dart +++ b/test/gallery/gallery_form_test.dart @@ -27,8 +27,8 @@ import 'package:wger/models/gallery/image.dart' as gallery; import 'package:wger/providers/gallery.dart'; import 'package:wger/widgets/gallery/forms.dart'; -import '../test_data/gallery.dart'; -import 'gallery_screen_test.mocks.dart'; +import './gallery_screen_test.mocks.dart'; +import '../../test_data/gallery.dart'; void main() { late gallery.Image image; diff --git a/test/gallery_screen_test.dart b/test/gallery/gallery_screen_test.dart similarity index 97% rename from test/gallery_screen_test.dart rename to test/gallery/gallery_screen_test.dart index 8507048e..f75f4705 100644 --- a/test/gallery_screen_test.dart +++ b/test/gallery/gallery_screen_test.dart @@ -27,8 +27,8 @@ import 'package:wger/providers/gallery.dart'; import 'package:wger/screens/form_screen.dart'; import 'package:wger/widgets/gallery/overview.dart'; -import '../test_data/gallery.dart'; -import 'gallery_screen_test.mocks.dart'; +import './gallery_screen_test.mocks.dart'; +import '../../test_data/gallery.dart'; @GenerateMocks([GalleryProvider]) void main() { diff --git a/test/gallery_screen_test.mocks.dart b/test/gallery/gallery_screen_test.mocks.dart similarity index 97% rename from test/gallery_screen_test.mocks.dart rename to test/gallery/gallery_screen_test.mocks.dart index b7864a90..8f5d6f1d 100644 --- a/test/gallery_screen_test.mocks.dart +++ b/test/gallery/gallery_screen_test.mocks.dart @@ -1,5 +1,5 @@ -// Mocks generated by Mockito 5.0.15 from annotations -// in wger/test/gallery_screen_test.dart. +// Mocks generated by Mockito 5.0.16 from annotations +// in wger/test/gallery/gallery_screen_test.dart. // Do not manually edit this file. import 'dart:async' as _i6; @@ -19,6 +19,7 @@ import 'package:wger/providers/gallery.dart' as _i4; // 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 class _FakeAuthProvider_0 extends _i1.Fake implements _i2.AuthProvider {} diff --git a/test/measurements/measurement_categories_screen_test.mocks.dart b/test/measurements/measurement_categories_screen_test.mocks.dart index bc5f90a5..89093d71 100644 --- a/test/measurements/measurement_categories_screen_test.mocks.dart +++ b/test/measurements/measurement_categories_screen_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.0.15 from annotations +// Mocks generated by Mockito 5.0.16 from annotations // in wger/test/measurements/measurement_categories_screen_test.dart. // Do not manually edit this file. @@ -18,6 +18,7 @@ import 'package:wger/providers/measurement.dart' as _i4; // 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 class _FakeWgerBaseProvider_0 extends _i1.Fake implements _i2.WgerBaseProvider {} diff --git a/test/measurements/measurement_provider_test.mocks.dart b/test/measurements/measurement_provider_test.mocks.dart index 3d0ae4e9..45ea064b 100644 --- a/test/measurements/measurement_provider_test.mocks.dart +++ b/test/measurements/measurement_provider_test.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.0.15 from annotations +// Mocks generated by Mockito 5.0.16 from annotations // in wger/test/measurements/measurement_provider_test.dart. // Do not manually edit this file. @@ -16,6 +16,7 @@ import 'package:wger/providers/base_provider.dart' as _i4; // 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 class _FakeAuthProvider_0 extends _i1.Fake implements _i2.AuthProvider {} diff --git a/test/nutritional_diary_test.dart b/test/nutrition/nutritional_diary_test.dart similarity index 98% rename from test/nutritional_diary_test.dart rename to test/nutrition/nutritional_diary_test.dart index 55cb637c..d65029a7 100644 --- a/test/nutritional_diary_test.dart +++ b/test/nutrition/nutritional_diary_test.dart @@ -22,7 +22,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:wger/widgets/nutrition/charts.dart'; import 'package:wger/widgets/nutrition/nutritional_diary_detail.dart'; -import '../test_data/nutritional_plans.dart'; +import '../../test_data/nutritional_plans.dart'; void main() { Widget getWidget({locale = 'en'}) { diff --git a/test/nutritional_meal_form_test.dart b/test/nutrition/nutritional_meal_form_test.dart similarity index 97% rename from test/nutritional_meal_form_test.dart rename to test/nutrition/nutritional_meal_form_test.dart index 0075503d..d3a34666 100644 --- a/test/nutritional_meal_form_test.dart +++ b/test/nutrition/nutritional_meal_form_test.dart @@ -29,8 +29,8 @@ import 'package:wger/providers/nutrition.dart'; import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/widgets/nutrition/forms.dart'; -import '../test_data/nutritional_plans.dart'; -import 'nutritional_plan_form_test.mocks.dart'; +import './nutritional_plan_form_test.mocks.dart'; +import '../../test_data/nutritional_plans.dart'; void main() { var mockNutrition = MockNutritionPlansProvider(); diff --git a/test/nutritional_plan_form_test.dart b/test/nutrition/nutritional_plan_form_test.dart similarity index 98% rename from test/nutritional_plan_form_test.dart rename to test/nutrition/nutritional_plan_form_test.dart index 6cb45705..059f1637 100644 --- a/test/nutritional_plan_form_test.dart +++ b/test/nutrition/nutritional_plan_form_test.dart @@ -28,7 +28,7 @@ import 'package:wger/providers/nutrition.dart'; import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/widgets/nutrition/forms.dart'; -import 'nutritional_plan_form_test.mocks.dart'; +import './nutritional_plan_form_test.mocks.dart'; @GenerateMocks([NutritionPlansProvider]) void main() { diff --git a/test/nutritional_plan_form_test.mocks.dart b/test/nutrition/nutritional_plan_form_test.mocks.dart similarity index 95% rename from test/nutritional_plan_form_test.mocks.dart rename to test/nutrition/nutritional_plan_form_test.mocks.dart index a878141a..ab76647c 100644 --- a/test/nutritional_plan_form_test.mocks.dart +++ b/test/nutrition/nutritional_plan_form_test.mocks.dart @@ -1,5 +1,5 @@ -// Mocks generated by Mockito 5.0.15 from annotations -// in wger/test/nutritional_plan_form_test.dart. +// Mocks generated by Mockito 5.0.16 from annotations +// in wger/test/nutrition/nutritional_plan_form_test.dart. // Do not manually edit this file. import 'dart:async' as _i9; @@ -21,6 +21,7 @@ import 'package:wger/providers/nutrition.dart' as _i8; // 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 class _FakeAuthProvider_0 extends _i1.Fake implements _i2.AuthProvider {} @@ -152,6 +153,11 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP returnValue: Future.value(), returnValueForMissingStub: Future.value()) as _i9.Future); @override + _i9.Future logIngredentToDiary(_i6.MealItem? mealItem, int? planId, [DateTime? dateTime]) => + (super.noSuchMethod(Invocation.method(#logIngredentToDiary, [mealItem, planId, dateTime]), + returnValue: Future.value(), + returnValueForMissingStub: Future.value()) as _i9.Future); + @override _i9.Future deleteLog(int? logId, int? planId) => (super.noSuchMethod(Invocation.method(#deleteLog, [logId, planId]), returnValue: Future.value(), diff --git a/test/nutritional_plan_model_test.dart b/test/nutrition/nutritional_plan_model_test.dart similarity index 97% rename from test/nutritional_plan_model_test.dart rename to test/nutrition/nutritional_plan_model_test.dart index e2e12746..8eb86cc5 100644 --- a/test/nutritional_plan_model_test.dart +++ b/test/nutrition/nutritional_plan_model_test.dart @@ -20,7 +20,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_values.dart'; -import '../test_data/nutritional_plans.dart'; +import '../../test_data/nutritional_plans.dart'; void main() { late NutritionalPlan plan; diff --git a/test/nutritional_plan_screen_test.dart b/test/nutrition/nutritional_plan_screen_test.dart similarity index 96% rename from test/nutritional_plan_screen_test.dart rename to test/nutrition/nutritional_plan_screen_test.dart index 98bb314e..796f11af 100644 --- a/test/nutritional_plan_screen_test.dart +++ b/test/nutrition/nutritional_plan_screen_test.dart @@ -25,9 +25,9 @@ import 'package:wger/providers/nutrition.dart'; import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/widgets/nutrition/charts.dart'; -import '../test_data/nutritional_plans.dart'; -import 'base_provider_test.mocks.dart'; -import 'utils.dart'; +import '../../test_data/nutritional_plans.dart'; +import '../other/base_provider_test.mocks.dart'; +import '../utils.dart'; void main() { Widget createNutritionalPlan({locale = 'en'}) { diff --git a/test/nutritional_plans_screen_test.dart b/test/nutrition/nutritional_plans_screen_test.dart similarity index 98% rename from test/nutritional_plans_screen_test.dart rename to test/nutrition/nutritional_plans_screen_test.dart index abd62d50..0b0bbb24 100644 --- a/test/nutritional_plans_screen_test.dart +++ b/test/nutrition/nutritional_plans_screen_test.dart @@ -28,8 +28,8 @@ import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/nutritional_plans_screen.dart'; import 'package:wger/widgets/nutrition/forms.dart'; -import 'base_provider_test.mocks.dart'; -import 'utils.dart'; +import '../other/base_provider_test.mocks.dart'; +import '../utils.dart'; void main() { Widget createHomeScreen({locale = 'en'}) { diff --git a/test/nutritional_values_class_test.dart b/test/nutrition/nutritional_values_class_test.dart similarity index 100% rename from test/nutritional_values_class_test.dart rename to test/nutrition/nutritional_values_class_test.dart diff --git a/test/base_provider_test.dart b/test/other/base_provider_test.dart similarity index 98% rename from test/base_provider_test.dart rename to test/other/base_provider_test.dart index bfec04ae..2f6cbdf1 100644 --- a/test/base_provider_test.dart +++ b/test/other/base_provider_test.dart @@ -21,7 +21,7 @@ import 'package:http/http.dart' as http; import 'package:mockito/annotations.dart'; import 'package:wger/providers/base_provider.dart'; -import 'utils.dart'; +import '../utils.dart'; @GenerateMocks([http.Client]) void main() { diff --git a/test/base_provider_test.mocks.dart b/test/other/base_provider_test.mocks.dart similarity index 96% rename from test/base_provider_test.mocks.dart rename to test/other/base_provider_test.mocks.dart index c64ebdcf..c052da81 100644 --- a/test/base_provider_test.mocks.dart +++ b/test/other/base_provider_test.mocks.dart @@ -1,5 +1,5 @@ -// Mocks generated by Mockito 5.0.15 from annotations -// in wger/test/base_provider_test.dart. +// Mocks generated by Mockito 5.0.16 from annotations +// in wger/test/other/base_provider_test.dart. // Do not manually edit this file. import 'dart:async' as _i5; @@ -19,6 +19,7 @@ import 'package:mockito/mockito.dart' as _i1; // 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 class _FakeResponse_0 extends _i1.Fake implements _i2.Response {} diff --git a/test/extensions_test.dart b/test/other/extensions_test.dart similarity index 100% rename from test/extensions_test.dart rename to test/other/extensions_test.dart diff --git a/test/utils.dart b/test/utils.dart index 7a612cef..67c8b97d 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -20,9 +20,10 @@ import 'package:wger/providers/auth.dart'; import 'package:wger/providers/exercises.dart'; import '../test_data/exercises.dart'; +import 'other/base_provider_test.mocks.dart'; // Test Auth provider -final AuthProvider testAuthProvider = AuthProvider() +final AuthProvider testAuthProvider = AuthProvider(MockClient(), false) ..token = 'FooBar' ..serverUrl = 'https://localhost'; diff --git a/test/weight_model_test.dart b/test/weight/weight_model_test.dart similarity index 100% rename from test/weight_model_test.dart rename to test/weight/weight_model_test.dart diff --git a/test/weight_provider_test.dart b/test/weight/weight_provider_test.dart similarity index 98% rename from test/weight_provider_test.dart rename to test/weight/weight_provider_test.dart index 7f9c1106..f120b15a 100644 --- a/test/weight_provider_test.dart +++ b/test/weight/weight_provider_test.dart @@ -22,8 +22,8 @@ import 'package:mockito/mockito.dart'; import 'package:wger/models/body_weight/weight_entry.dart'; import 'package:wger/providers/body_weight.dart'; -import 'base_provider_test.mocks.dart'; -import 'utils.dart'; +import '../other/base_provider_test.mocks.dart'; +import '../utils.dart'; void main() { group('test body weight provider', () { diff --git a/test/weight_screen_test.dart b/test/weight/weight_screen_test.dart similarity index 97% rename from test/weight_screen_test.dart rename to test/weight/weight_screen_test.dart index d551227a..d0db6acd 100644 --- a/test/weight_screen_test.dart +++ b/test/weight/weight_screen_test.dart @@ -28,9 +28,9 @@ import 'package:wger/screens/weight_screen.dart'; import 'package:wger/widgets/core/charts.dart'; import 'package:wger/widgets/weight/forms.dart'; -import '../test_data/body_weight.dart'; -import 'base_provider_test.mocks.dart'; -import 'utils.dart'; +import '../../test_data/body_weight.dart'; +import '../other/base_provider_test.mocks.dart'; +import '../utils.dart'; void main() { Widget createHomeScreen({locale = 'en'}) { diff --git a/test/gym_mode_screen_test.dart b/test/workout/gym_mode_screen_test.dart similarity index 98% rename from test/gym_mode_screen_test.dart rename to test/workout/gym_mode_screen_test.dart index 685f501b..95e5a3dc 100644 --- a/test/gym_mode_screen_test.dart +++ b/test/workout/gym_mode_screen_test.dart @@ -27,9 +27,9 @@ import 'package:wger/screens/workout_plan_screen.dart'; import 'package:wger/widgets/workouts/forms.dart'; import 'package:wger/widgets/workouts/gym_mode.dart'; -import '../test_data/workouts.dart'; -import 'base_provider_test.mocks.dart'; -import 'utils.dart'; +import '../../test_data/workouts.dart'; +import '../other/base_provider_test.mocks.dart'; +import '../utils.dart'; void main() { Widget createHomeScreen({locale = 'en'}) { diff --git a/test/plate_calculator_test.dart b/test/workout/plate_calculator_test.dart similarity index 100% rename from test/plate_calculator_test.dart rename to test/workout/plate_calculator_test.dart diff --git a/test/set_model_test.dart b/test/workout/set_model_test.dart similarity index 96% rename from test/set_model_test.dart rename to test/workout/set_model_test.dart index 60f1bdae..c92a9137 100644 --- a/test/set_model_test.dart +++ b/test/workout/set_model_test.dart @@ -18,7 +18,7 @@ import 'package:flutter_test/flutter_test.dart'; -import '../test_data/workouts.dart'; +import '../../test_data/workouts.dart'; void main() { group('Test the getSmartTextRepr method for a set', () { diff --git a/test/setting_model_test.dart b/test/workout/setting_model_test.dart similarity index 100% rename from test/setting_model_test.dart rename to test/workout/setting_model_test.dart diff --git a/test/workout_day_form_test.dart b/test/workout/workout_day_form_test.dart similarity index 97% rename from test/workout_day_form_test.dart rename to test/workout/workout_day_form_test.dart index a06cab56..3da79efa 100644 --- a/test/workout_day_form_test.dart +++ b/test/workout/workout_day_form_test.dart @@ -27,8 +27,8 @@ import 'package:wger/models/workouts/workout_plan.dart'; import 'package:wger/providers/workout_plans.dart'; import 'package:wger/widgets/workouts/forms.dart'; -import '../test_data/workouts.dart'; -import 'workout_form_test.mocks.dart'; +import './workout_form_test.mocks.dart'; +import '../../test_data/workouts.dart'; void main() { var mockWorkoutPlans = MockWorkoutPlansProvider(); diff --git a/test/workout_form_test.dart b/test/workout/workout_form_test.dart similarity index 99% rename from test/workout_form_test.dart rename to test/workout/workout_form_test.dart index fae44db8..44f72b28 100644 --- a/test/workout_form_test.dart +++ b/test/workout/workout_form_test.dart @@ -28,7 +28,7 @@ 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'; +import './workout_form_test.mocks.dart'; @GenerateMocks([WorkoutPlansProvider]) void main() { diff --git a/test/workout_form_test.mocks.dart b/test/workout/workout_form_test.mocks.dart similarity index 98% rename from test/workout_form_test.mocks.dart rename to test/workout/workout_form_test.mocks.dart index 9bfd1d08..00b22094 100644 --- a/test/workout_form_test.mocks.dart +++ b/test/workout/workout_form_test.mocks.dart @@ -1,5 +1,5 @@ -// Mocks generated by Mockito 5.0.15 from annotations -// in wger/test/workout_form_test.dart. +// Mocks generated by Mockito 5.0.16 from annotations +// in wger/test/workout/workout_form_test.dart. // Do not manually edit this file. import 'dart:async' as _i13; @@ -26,6 +26,7 @@ import 'package:wger/providers/workout_plans.dart' as _i12; // 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 class _FakeWeightUnit_0 extends _i1.Fake implements _i2.WeightUnit {} diff --git a/test/workout_log_model_test.dart b/test/workout/workout_log_model_test.dart similarity index 100% rename from test/workout_log_model_test.dart rename to test/workout/workout_log_model_test.dart diff --git a/test/workout_plan_model_test.dart b/test/workout/workout_plan_model_test.dart similarity index 94% rename from test/workout_plan_model_test.dart rename to test/workout/workout_plan_model_test.dart index b0250774..574820d4 100644 --- a/test/workout_plan_model_test.dart +++ b/test/workout/workout_plan_model_test.dart @@ -18,8 +18,8 @@ import 'package:flutter_test/flutter_test.dart'; -import '../test_data/exercises.dart'; -import '../test_data/workouts.dart'; +import '../../test_data/exercises.dart'; +import '../../test_data/workouts.dart'; void main() { group('model tests', () { diff --git a/test/workout_plan_screen_test.dart b/test/workout/workout_plan_screen_test.dart similarity index 96% rename from test/workout_plan_screen_test.dart rename to test/workout/workout_plan_screen_test.dart index a2d98e63..7f909d98 100644 --- a/test/workout_plan_screen_test.dart +++ b/test/workout/workout_plan_screen_test.dart @@ -23,9 +23,9 @@ import 'package:provider/provider.dart'; import 'package:wger/providers/workout_plans.dart'; import 'package:wger/screens/workout_plan_screen.dart'; -import '../test_data/workouts.dart'; -import 'base_provider_test.mocks.dart'; -import 'utils.dart'; +import '../../test_data/workouts.dart'; +import '../other/base_provider_test.mocks.dart'; +import '../utils.dart'; void main() { Widget createHomeScreen({locale = 'en'}) { diff --git a/test/workout_plans_screen_test.dart b/test/workout/workout_plans_screen_test.dart similarity index 98% rename from test/workout_plans_screen_test.dart rename to test/workout/workout_plans_screen_test.dart index fe387318..eddc25bc 100644 --- a/test/workout_plans_screen_test.dart +++ b/test/workout/workout_plans_screen_test.dart @@ -29,8 +29,8 @@ import 'package:wger/screens/workout_plans_screen.dart'; import 'package:wger/widgets/nutrition/forms.dart'; import 'package:wger/widgets/workouts/forms.dart'; -import 'base_provider_test.mocks.dart'; -import 'utils.dart'; +import '../other/base_provider_test.mocks.dart'; +import '../utils.dart'; void main() { Widget createHomeScreen({locale = 'en'}) { diff --git a/test/workout_set_form_test.dart b/test/workout/workout_set_form_test.dart similarity index 95% rename from test/workout_set_form_test.dart rename to test/workout/workout_set_form_test.dart index cbab5c10..67d605a7 100644 --- a/test/workout_set_form_test.dart +++ b/test/workout/workout_set_form_test.dart @@ -32,11 +32,11 @@ import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/workout_plans.dart'; import 'package:wger/widgets/workouts/forms.dart'; -import '../test_data/workouts.dart'; -import 'base_provider_test.mocks.dart'; -import 'utils.dart'; -import 'workout_form_test.mocks.dart'; -import 'workout_set_form_test.mocks.dart'; +import './workout_form_test.mocks.dart'; +import './workout_set_form_test.mocks.dart'; +import '../../test_data/workouts.dart'; +import '../other/base_provider_test.mocks.dart'; +import '../utils.dart'; @GenerateMocks([ExercisesProvider]) void main() { diff --git a/test/workout_set_form_test.mocks.dart b/test/workout/workout_set_form_test.mocks.dart similarity index 97% rename from test/workout_set_form_test.mocks.dart rename to test/workout/workout_set_form_test.mocks.dart index b6cef929..87955720 100644 --- a/test/workout_set_form_test.mocks.dart +++ b/test/workout/workout_set_form_test.mocks.dart @@ -1,5 +1,5 @@ -// Mocks generated by Mockito 5.0.15 from annotations -// in wger/test/workout_set_form_test.dart. +// Mocks generated by Mockito 5.0.16 from annotations +// in wger/test/workout/workout_set_form_test.dart. // Do not manually edit this file. import 'dart:async' as _i6; @@ -18,6 +18,7 @@ import 'package:wger/providers/exercises.dart' as _i5; // 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 class _FakeAuthProvider_0 extends _i1.Fake implements _i2.AuthProvider {}