diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml index 1aac6143..e21c683c 100644 --- a/.github/workflows/android-release.yml +++ b/.github/workflows/android-release.yml @@ -14,7 +14,7 @@ jobs: - name: Setup Java uses: actions/setup-java@v1 with: - java-version: 11.x + java-version: 17.x - name: Setup Ruby uses: ruby/setup-ruby@v1 @@ -25,7 +25,7 @@ jobs: uses: subosito/flutter-action@v1 with: channel: 'stable' - flutter-version: '3.0.x' + flutter-version: '3.7.x' - name: Decrypt config files run: | @@ -46,11 +46,10 @@ jobs: 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) + echo "VERSION_V=$(echo $GITHUB_REF | cut -d / -f 3)" >> $GITHUB_ENV + echo "VERSION=$(echo $GITHUB_REF | cut -d / -f 3 | cut -c 2-)" >> $GITHUB_ENV + echo "BUILD=$(flutter pub run cider version | cut -d '+' -f 2)" >> $GITHUB_ENV # 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. @@ -61,16 +60,16 @@ jobs: # one without the v and push it. - name: Bump version run: | - flutter pub run cider version ${{ steps.get_version.outputs.VERSION }}+${{ steps.get_version.outputs.BUILD }} + flutter pub run cider version ${{ env.VERSION }}+${{ env.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 tag ${{ env.VERSION }} git push origin HEAD:master --tags - git push origin --delete ${{ steps.get_version.outputs.VERSION_V }} + git push origin --delete ${{ env.VERSION_V }} - name: Build AAB run: flutter build appbundle --release @@ -78,7 +77,7 @@ jobs: WGER_API_KEY: ${{ secrets.WGER_API_KEY }} - name: Upload build to Play Store - uses: maierj/fastlane-action@v2.1.0 + uses: maierj/fastlane-action@v2.2.1 with: lane: production @@ -86,5 +85,5 @@ jobs: uses: softprops/action-gh-release@v1 with: files: build/app/outputs/bundle/release/app-release.aab - tag_name: ${{ steps.get_version.outputs.VERSION }} + tag_name: ${{ env.VERSION }} body_path: CHANGELOG.md \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e7e2894..b7766949 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,17 @@ name: Continous Integration on: push: - branches: [ master ] paths: - '**.dart' - 'pubspec.yaml' pull_request: - branches: [ master ] + branches: [ pull_request, master ] paths: - '**.dart' - 'pubspec.yaml' jobs: test: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 @@ -20,7 +19,7 @@ jobs: uses: subosito/flutter-action@v1 with: channel: 'stable' - flutter-version: '3.0.x' + flutter-version: '3.7.x' - run: dart --version - run: flutter --version diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml deleted file mode 100644 index 7e827d5a..00000000 --- a/.github/workflows/dependabot.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Dependabot Pub - -on: workflow_dispatch - -jobs: - pub: - name: Dependabot Pub - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: dart-lang/setup-dart@v1 - - name: Update - uses: IchordeDionysos/dependabot-pub-runner@main - with: - path: / \ No newline at end of file diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 4cba8fe1..fd987948 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -7,7 +7,7 @@ on: paths: - '**.dart' - + jobs: linting: runs-on: ubuntu-latest @@ -15,19 +15,19 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - + - name: Setup Flutter uses: subosito/flutter-action@v1 with: channel: 'stable' - flutter-version: '3.0.x' + flutter-version: '3.7.x' - name: Get dependencies run: flutter pub get - - name: Check for formatting issues (run "flutter format . ") - run: flutter format --line-length=100 . - + - name: Check for formatting issues (run "dart format . ") + run: dart format --line-length=100 . + - name: Push a commit with the changed files continue-on-error: true run: | diff --git a/.gitignore b/.gitignore index 08fb3709..728c5893 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. -#.vscode/ +.vscode/ # Flutter/Dart/Pub related **/doc/api/ @@ -47,3 +47,7 @@ app.*.map.json /fastlane/metadata/envfiles/wger.properties /fastlane/metadata/envfiles/keys.jks /fastlane/metadata/envfiles/key.properties + +# Others +/vendor/bundle/ruby/ +/coverage/ diff --git a/.vscode/settings.json b/.vscode/settings.json index 074f5899..a6032c70 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "dart.lineLength": 100 + "dart.lineLength": 100, + "diffEditor.ignoreTrimWhitespace": true, } \ No newline at end of file diff --git a/AUTHORS.md b/AUTHORS.md index ea77dc6e..bc73c98b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -13,6 +13,11 @@ - Marko Milosevic - - Karthik Reddy (Axel) - - Ogundoyin Toluwani - +- Nenza Nurfirmansyah - +- Florian Schmitz - +- Adam Bujdoš - +- Aman Negi - +- Sandi Milohanic - ## Translators @@ -51,3 +56,11 @@ - Japanese - Kosei TANAKA (97) + +- Bahasa Indonesia + + - Nenza Nurfirmansyah (73) + +- Croatian + + - Sandi Milohaic diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..2ccf2ecb --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" + +gem "fastlane" +plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') +eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..293dc4bf --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,222 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.5) + rexml + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + artifactory (3.0.15) + atomos (0.1.3) + aws-eventstream (1.2.0) + aws-partitions (1.671.0) + aws-sdk-core (3.168.3) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.60.0) + aws-sdk-core (~> 3, >= 3.165.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.117.2) + aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.2) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + declarative (0.0.20) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.8.1) + emoji_regex (3.2.3) + excon (0.94.0) + faraday (1.10.2) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.6) + fastlane (2.211.0) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + fastlane-plugin-versioning (0.5.1) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.31.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-core (0.9.1) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.16.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-playcustomapp_v1 (0.12.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) + google-cloud-core (1.6.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.3.0) + google-cloud-storage (1.44.0) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.3.0) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.6.2) + json (2.6.3) + jwt (2.5.0) + memoist (0.16.2) + mini_magick (4.11.0) + mini_mime (1.1.2) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.1) + optparse (0.1.1) + os (1.1.4) + plist (3.6.0) + public_suffix (5.0.0) + rake (13.0.6) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.5) + rouge (2.0.7) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + security (0.1.3) + signet (0.17.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.22.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + arm64-darwin-21 + arm64-darwin-22 + x86_64-linux + +DEPENDENCIES + fastlane + fastlane-plugin-versioning + +BUNDLED WITH + 2.2.32 diff --git a/README.md b/README.md index 820a29d6..02d42047 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ If you want to contribute, hop on the Discord server and say hi! ## Development ### 1 -Install the wger server, the easiest way is to start the development docker-compose: - +Install the [wger server](https://github.com/wger-project/wger), the easiest way +is to start the development docker-compose: Alternatively, you can use one of our test servers, just ask us for access. @@ -35,10 +35,10 @@ Alternatively, you can use one of our test servers, just ask us for access. Install Flutter, and all its dependencies, and create a new virtual device: . -The app currently uses flutter 3.0 +The app currently uses flutter 3.3 ### 3 -Create a new file ``wger.properties`` in ``android/fastlane/envfiles``: +Create a new file ``wger.properties`` in ``fastlane/metadata/envfiles/``: ```properties WGER_API_KEY=123456 @@ -52,9 +52,6 @@ on your local instance and then run ``python3 manage.py add-user-rest the userna You can later list all the registered users with: ``python3 manage.py list-users-api`` -[Get it on F-Droid](https://f-droid.org/packages/de.wger.flutter) ### 4 Start the application with ``flutter run`` or use your IDE diff --git a/android/app/build.gradle b/android/app/build.gradle index 547dcded..3c03548c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -44,18 +44,28 @@ if (localMapsPropertiesFile.exists()) { project.logger.info('Load maps properties from environment') try { wgerProperties['WGER_API_KEY'] = System.getenv('WGER_API_KEY') - } catch(NullPointerException e) { + } catch (NullPointerException e) { project.logger.warn('Failed to load WGER_API_KEY from environment.', e) } } def wgerApiKey = wgerProperties.getProperty('WGER_API_KEY') -if(wgerApiKey == null){ +if (wgerApiKey == null) { wgerApiKey = "" - project.logger.error('Wger Api Key not configured. Set it in `app/wger.properties` or in the environment variable `WGER_API_KEY`') + project.logger.error('Wger Api Key not configured. Set it in `/fastlane/metadata/android/envfiles/wger.properties` or in the environment variable `WGER_API_KEY`') } android { - compileSdkVersion 31 + compileSdkVersion 33 + ndkVersion "25.1.8937393" + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -69,7 +79,7 @@ android { // Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "de.wger.flutter" minSdkVersion 21 - targetSdkVersion 31 + targetSdkVersion 33 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 001b3a6c..d6807bee 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -16,7 +16,12 @@ - + diff --git a/android/app/src/main/res/xml/network_security_config.xml b/android/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 00000000..8d843f3b --- /dev/null +++ b/android/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index c5231564..58a8c74b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.7.10' repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.3' + classpath 'com.android.tools.build:gradle:7.2.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -14,7 +14,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/android/fastlane/envfiles/wger.properties b/android/fastlane/envfiles/wger.properties deleted file mode 100644 index c367445e..00000000 --- a/android/fastlane/envfiles/wger.properties +++ /dev/null @@ -1,3 +0,0 @@ -```properties -WGER_API_KEY=77a270641bb5654c517e91f277bf06623c141318 -``` \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 90f271df..6b665338 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/assets/images/muscles/front.svg b/assets/images/muscles/front.svg index 5024d282..a14eb968 100644 --- a/assets/images/muscles/front.svg +++ b/assets/images/muscles/front.svg @@ -1,99 +1 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/fastlane/metadata/android/README.md b/fastlane/metadata/android/README.md index 4b436265..4e894f9d 100644 --- a/fastlane/metadata/android/README.md +++ b/fastlane/metadata/android/README.md @@ -10,8 +10,9 @@ If we use a new version, update the version used by ## 2. Dry-run release before uploading -* Increase build nr in pubspec.yaml +* Increase build nr in pubspec.yaml (revert after the dry-run was successful) * `flutter build appbundle --release` +* `bundle install` * `bundle exec fastlane android test_configuration` (needs the different keys available) It might be necessary to repeat these steps if upload_to_play_store returns any errors diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/ca/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..e0652ee1 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/ca/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..421f3431 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/ca/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..cfdad6c8 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/ca/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..bb36f261 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/ca/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..eda1cb07 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/ca/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/ca/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..67db6435 Binary files /dev/null and b/fastlane/metadata/android/ca/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..9d20ac05 Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..17672906 Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..c51b23da Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..daf5d8df Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..1dd4bc00 Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/de-DE/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/de-DE/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..c6af5484 Binary files /dev/null and b/fastlane/metadata/android/de-DE/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..22a930ca Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - workout plan.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - workout plan.png deleted file mode 100644 index d6f10a7b..00000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/01 - workout plan.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..e91dcf75 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout log.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout log.png deleted file mode 100644 index 7e7ebb40..00000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/02 - workout log.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/03 - gym mode.png index 6d5e26dc..ec165111 100644 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/03 - gym mode.png and b/fastlane/metadata/android/en-US/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..37edf1b2 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - nutritional plan.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - nutritional plan.png deleted file mode 100644 index adbb9f6b..00000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/04 - nutritional plan.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..3ed9a28a Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - weight.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - weight.png deleted file mode 100644 index d60c5c8d..00000000 Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/05 - weight.png and /dev/null differ diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..56b42156 Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..a18feeab Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..55ec07f7 Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..1125e76d Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..47ff7cfe Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..c284035b Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/es-ES/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/es-ES/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..5ba0ec82 Binary files /dev/null and b/fastlane/metadata/android/es-ES/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..51c3021c Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..efe5ae25 Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..1a839619 Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..a345757d Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..d20d6bc3 Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/fr-FR/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..e47c5563 Binary files /dev/null and b/fastlane/metadata/android/fr-FR/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..04001acc Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..8c907375 Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..5bfbb38e Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..48c655fe Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..53e986ec Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/hi-IN/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..1253513b Binary files /dev/null and b/fastlane/metadata/android/hi-IN/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/hr/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..f2dfd1d5 Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/hr/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..c127530d Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/hr/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..8023e095 Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/hr/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..83f265af Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/hr/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..1f7c16db Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/hr/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/hr/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..1c9d0eda Binary files /dev/null and b/fastlane/metadata/android/hr/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..2fea9c71 Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..b1cb3ff6 Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..351b2b9a Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..0a1bd8ba Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..6e57f2f6 Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/it-IT/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/it-IT/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..b15e0887 Binary files /dev/null and b/fastlane/metadata/android/it-IT/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..2f8bf4c5 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..e15f788e Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..ec165111 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..37edf1b2 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..b5c61559 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/nb-NO/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..b04c8127 Binary files /dev/null and b/fastlane/metadata/android/nb-NO/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/pl/full_description.txt b/fastlane/metadata/android/pl-PL/full_description.txt similarity index 100% rename from fastlane/metadata/android/pl/full_description.txt rename to fastlane/metadata/android/pl-PL/full_description.txt diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..f3f4e516 Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..bee98fa2 Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..c041291e Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..4af5a2c9 Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..06acea4d Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/pl-PL/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..b4c5c0e6 Binary files /dev/null and b/fastlane/metadata/android/pl-PL/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/pl/short_description.txt b/fastlane/metadata/android/pl-PL/short_description.txt similarity index 100% rename from fastlane/metadata/android/pl/short_description.txt rename to fastlane/metadata/android/pl-PL/short_description.txt diff --git a/fastlane/metadata/android/pl-PL/title.txt b/fastlane/metadata/android/pl-PL/title.txt new file mode 100644 index 00000000..d35e4087 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/title.txt @@ -0,0 +1 @@ +wger Workout Manager diff --git a/fastlane/metadata/android/pt/full_description.txt b/fastlane/metadata/android/pt-BR/full_description.txt similarity index 100% rename from fastlane/metadata/android/pt/full_description.txt rename to fastlane/metadata/android/pt-BR/full_description.txt diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..3ccf2223 Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..4db82b13 Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..1accd772 Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..597dedd4 Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..f94b4aac Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/pt-BR/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..fd5e4d97 Binary files /dev/null and b/fastlane/metadata/android/pt-BR/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/pt/short_description.txt b/fastlane/metadata/android/pt-BR/short_description.txt similarity index 100% rename from fastlane/metadata/android/pt/short_description.txt rename to fastlane/metadata/android/pt-BR/short_description.txt diff --git a/fastlane/metadata/android/pt-BR/title.txt b/fastlane/metadata/android/pt-BR/title.txt new file mode 100644 index 00000000..ea0df956 --- /dev/null +++ b/fastlane/metadata/android/pt-BR/title.txt @@ -0,0 +1 @@ +wger Workout Manager \ No newline at end of file diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..aeba637c Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..c492e5d6 Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..71790b47 Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..5aab8b04 Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..acf27004 Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/ru-RU/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..145f417d Binary files /dev/null and b/fastlane/metadata/android/ru-RU/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..f38600ee Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..8539f92e Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..6807102b Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..b813b098 Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..a2b9d7c5 Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/tr-TR/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..a9d4df79 Binary files /dev/null and b/fastlane/metadata/android/tr-TR/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/uk/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..5adfe3b7 Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/uk/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..5fca1b2e Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/uk/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..3b266f9c Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/uk/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..ca59421f Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/uk/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..c0715759 Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/uk/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/uk/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..74610f20 Binary files /dev/null and b/fastlane/metadata/android/uk/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/01 - dashboard.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/01 - dashboard.png new file mode 100644 index 00000000..070dcbb1 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/01 - dashboard.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/02 - workout detail.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/02 - workout detail.png new file mode 100644 index 00000000..d1cb7447 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/02 - workout detail.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/03 - gym mode.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/03 - gym mode.png new file mode 100644 index 00000000..a7ed6366 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/03 - gym mode.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - measurements.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - measurements.png new file mode 100644 index 00000000..1138a387 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/04 - measurements.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - nutritional plan.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - nutritional plan.png new file mode 100644 index 00000000..673889d5 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/05 - nutritional plan.png differ diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/06 - weight.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/06 - weight.png new file mode 100644 index 00000000..60c18543 Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/06 - weight.png differ diff --git a/fastlane/report.xml b/fastlane/report.xml index 430c0d54..c1eafc1e 100644 --- a/fastlane/report.xml +++ b/fastlane/report.xml @@ -5,12 +5,12 @@ - + - + diff --git a/integration_test/1_dashboard.dart b/integration_test/1_dashboard.dart new file mode 100644 index 00000000..7abfcf45 --- /dev/null +++ b/integration_test/1_dashboard.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/body_weight.dart'; +import 'package:wger/providers/measurement.dart'; +import 'package:wger/providers/nutrition.dart'; +import 'package:wger/providers/workout_plans.dart'; +import 'package:wger/screens/dashboard.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/measurements/measurement_categories_screen_test.mocks.dart'; +import '../test/nutrition/nutritional_plan_form_test.mocks.dart'; +import '../test/workout/weight_unit_form_widget_test.mocks.dart'; +import '../test/workout/workout_form_test.mocks.dart'; +import '../test_data/body_weight.dart'; +import '../test_data/measurements.dart'; +import '../test_data/nutritional_plans.dart'; +import '../test_data/workouts.dart'; + +Widget createDashboardScreen({locale = 'en'}) { + final mockWorkoutProvider = MockWorkoutPlansProvider(); + when(mockWorkoutProvider.activePlan).thenReturn(getWorkout()); + + final Map logs = { + 'results': [ + { + 'id': 1, + 'workout': 1, + 'date': '2022-12-01', + 'impression': '3', + 'time_start': '17:00', + 'time_end': '19:00' + } + ] + }; + when(mockWorkoutProvider.fetchSessionData()).thenAnswer((a) => Future.value(logs)); + + final mockNutritionProvider = MockNutritionPlansProvider(); + when(mockNutritionProvider.currentPlan).thenAnswer((realInvocation) => getNutritionalPlan()); + when(mockNutritionProvider.items).thenReturn([getNutritionalPlan()]); + + final mockWeightProvider = MockBodyWeightProvider(); + when(mockWeightProvider.items).thenReturn(getWeightEntries()); + + final mockMeasurementProvider = MockMeasurementProvider(); + when(mockMeasurementProvider.categories).thenReturn(getMeasurementCategories()); + + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => mockWorkoutProvider, + ), + ChangeNotifierProvider( + create: (context) => mockNutritionProvider, + ), + ChangeNotifierProvider( + create: (context) => mockWeightProvider, + ), + ChangeNotifierProvider( + create: (context) => mockMeasurementProvider, + ), + ], + child: MaterialApp( + locale: Locale(locale), + debugShowCheckedModeBanner: false, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: wgerTheme, + home: DashboardScreen(), + ), + ); +} diff --git a/integration_test/2_workout.dart b/integration_test/2_workout.dart new file mode 100644 index 00000000..b36d5265 --- /dev/null +++ b/integration_test/2_workout.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/workout_plans.dart'; +import 'package:wger/screens/workout_plan_screen.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/workout/workout_form_test.mocks.dart'; +import '../test_data/workouts.dart'; + +Widget createWorkoutDetailScreen({locale = 'en'}) { + final key = GlobalKey(); + + final mockWorkoutProvider = MockWorkoutPlansProvider(); + final workout = getWorkout(); + when(mockWorkoutProvider.activePlan).thenReturn(workout); + when(mockWorkoutProvider.fetchAndSetWorkoutPlanFull(1)).thenAnswer((_) => Future.value(workout)); + + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => mockWorkoutProvider, + ), + ], + child: MaterialApp( + locale: Locale(locale), + debugShowCheckedModeBanner: false, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: wgerTheme, + navigatorKey: key, + home: TextButton( + onPressed: () => key.currentState!.push( + MaterialPageRoute( + settings: RouteSettings(arguments: getWorkout()), + builder: (_) => WorkoutPlanScreen(), + ), + ), + child: const SizedBox(), + ), + ), + ); +} diff --git a/integration_test/3_gym_mode.dart b/integration_test/3_gym_mode.dart new file mode 100644 index 00000000..7727352e --- /dev/null +++ b/integration_test/3_gym_mode.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/exercises.dart'; +import 'package:wger/providers/workout_plans.dart'; +import 'package:wger/screens/gym_mode.dart'; +import 'package:wger/screens/workout_plan_screen.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/other/base_provider_test.mocks.dart'; +import '../test/utils.dart'; +import '../test/workout/gym_mode_screen_test.mocks.dart'; +import '../test_data/exercises.dart'; +import '../test_data/workouts.dart'; + +Widget createGymModeScreen({locale = 'en'}) { + final key = GlobalKey(); + final client = MockClient(); + final bases = getTestExerciseBases(); + final workout = getWorkout(); + + final mockExerciseProvider = MockExercisesProvider(); + + when(mockExerciseProvider.findExerciseBaseById(1)).thenReturn(bases[0]); // bench press + when(mockExerciseProvider.findExerciseBaseById(6)).thenReturn(bases[5]); // side raises + //when(mockExerciseProvider.findExerciseBaseById(2)).thenReturn(bases[1]); // crunches + //when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(bases[2]); // dead lift + + return ChangeNotifierProvider( + create: (context) => WorkoutPlansProvider( + testAuthProvider, + mockExerciseProvider, + [workout], + client, + ), + child: ChangeNotifierProvider( + create: (context) => mockExerciseProvider, + child: MaterialApp( + locale: Locale(locale), + debugShowCheckedModeBanner: false, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + navigatorKey: key, + theme: wgerTheme, + home: TextButton( + onPressed: () => key.currentState!.push( + MaterialPageRoute( + settings: RouteSettings(arguments: workout.days.first), + builder: (_) => GymModeScreen(), + ), + ), + child: const SizedBox(), + ), + routes: { + WorkoutPlanScreen.routeName: (ctx) => WorkoutPlanScreen(), + }, + ), + ), + ); +} diff --git a/integration_test/4_measurements.dart b/integration_test/4_measurements.dart new file mode 100644 index 00000000..c745d6c3 --- /dev/null +++ b/integration_test/4_measurements.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/providers/measurement.dart'; +import 'package:wger/screens/measurement_categories_screen.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/measurements/measurement_categories_screen_test.mocks.dart'; +import '../test_data/measurements.dart'; + +Widget createMeasurementScreen({locale = 'en'}) { + final mockMeasurementProvider = MockMeasurementProvider(); + when(mockMeasurementProvider.categories).thenReturn(getMeasurementCategories()); + + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => mockMeasurementProvider, + ), + ], + child: MaterialApp( + locale: Locale(locale), + debugShowCheckedModeBanner: false, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: wgerTheme, + home: MeasurementCategoriesScreen(), + ), + ); +} diff --git a/integration_test/5_nutritional_plan.dart b/integration_test/5_nutritional_plan.dart new file mode 100644 index 00000000..cfbf6610 --- /dev/null +++ b/integration_test/5_nutritional_plan.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/models/nutrition/ingredient.dart'; +import 'package:wger/models/nutrition/log.dart'; +import 'package:wger/models/nutrition/meal.dart'; +import 'package:wger/models/nutrition/meal_item.dart'; +import 'package:wger/models/nutrition/nutritional_plan.dart'; +import 'package:wger/providers/body_weight.dart'; +import 'package:wger/providers/nutrition.dart'; +import 'package:wger/screens/nutritional_plan_screen.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/other/base_provider_test.mocks.dart'; +import '../test/utils.dart'; + +Widget createNutritionalPlanScreen({locale = 'en'}) { + final key = GlobalKey(); + final client = MockClient(); + + final muesli = Ingredient( + id: 1, + code: '123456787', + name: 'Müsli', + creationDate: DateTime(2021, 5, 1), + energy: 500, + carbohydrates: 10, + carbohydratesSugar: 2, + protein: 5, + fat: 20, + fatSaturated: 7, + fibres: 12, + sodium: 0.5, + ); + final milk = Ingredient( + id: 1, + code: '123456787', + name: 'Milk', + creationDate: DateTime(2021, 5, 1), + energy: 500, + carbohydrates: 10, + carbohydratesSugar: 2, + protein: 5, + fat: 20, + fatSaturated: 7, + fibres: 12, + sodium: 0.5, + ); + final apple = Ingredient( + id: 1, + code: '123456787', + name: 'Apple', + creationDate: DateTime(2021, 5, 1), + energy: 500, + carbohydrates: 10, + carbohydratesSugar: 2, + protein: 5, + fat: 20, + fatSaturated: 7, + fibres: 12, + sodium: 0.5, + ); + + final mealItem1 = MealItem(ingredientId: 1, amount: 100, ingredient: muesli); + final mealItem2 = MealItem(ingredientId: 2, amount: 75, ingredient: milk); + final mealItem3 = MealItem(ingredientId: 3, amount: 100, ingredient: apple); + + final meal1 = Meal( + id: 1, + plan: 1, + time: const TimeOfDay(hour: 8, minute: 30), + name: 'Breakfast', + mealItems: [mealItem1, mealItem2], + ); + + final meal2 = Meal( + id: 2, + plan: 1, + time: const TimeOfDay(hour: 11, minute: 0), + name: 'Snack 1', + mealItems: [mealItem3], + ); + + final NutritionalPlan plan = NutritionalPlan( + id: 1, + description: 'Mini diet', + creationDate: DateTime(2021, 5, 23), + meals: [meal1, meal2], + ); + + // Add logs + plan.logs.add(Log.fromMealItem(mealItem1, 1, 1, DateTime(2021, 6, 1))); + plan.logs.add(Log.fromMealItem(mealItem2, 1, 1, DateTime(2021, 6, 1))); + plan.logs.add(Log.fromMealItem(mealItem3, 1, 1, DateTime(2021, 6, 10))); + + return MultiProvider( + providers: [ + ChangeNotifierProvider( + create: (context) => NutritionPlansProvider(testAuthProvider, [], client), + ), + ChangeNotifierProvider( + create: (context) => BodyWeightProvider(mockBaseProvider), + ), + ], + child: MaterialApp( + locale: Locale(locale), + debugShowCheckedModeBanner: false, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: wgerTheme, + navigatorKey: key, + home: TextButton( + onPressed: () => key.currentState!.push( + MaterialPageRoute( + settings: RouteSettings(arguments: plan), + builder: (_) => NutritionalPlanScreen(), + ), + ), + child: const SizedBox(), + ), + ), + ); +} diff --git a/integration_test/6_weight.dart b/integration_test/6_weight.dart new file mode 100644 index 00000000..041c3cb8 --- /dev/null +++ b/integration_test/6_weight.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:provider/provider.dart'; +import 'package:wger/models/body_weight/weight_entry.dart'; +import 'package:wger/providers/body_weight.dart'; +import 'package:wger/screens/form_screen.dart'; +import 'package:wger/screens/weight_screen.dart'; +import 'package:wger/theme/theme.dart'; + +import '../test/utils.dart'; + +Widget createWeightScreen({locale = 'en'}) { + final provider = BodyWeightProvider(mockBaseProvider); + provider.items = [ + WeightEntry(id: 1, weight: 86, date: DateTime(2021, 01, 01)), + WeightEntry(id: 2, weight: 81, date: DateTime(2021, 01, 10)), + WeightEntry(id: 3, weight: 82, date: DateTime(2021, 01, 20)), + WeightEntry(id: 4, weight: 83, date: DateTime(2021, 01, 30)), + WeightEntry(id: 5, weight: 86, date: DateTime(2021, 02, 20)), + WeightEntry(id: 6, weight: 90, date: DateTime(2021, 02, 28)), + WeightEntry(id: 7, weight: 91, date: DateTime(2021, 03, 20)), + WeightEntry(id: 8, weight: 91.1, date: DateTime(2021, 03, 30)), + WeightEntry(id: 9, weight: 90, date: DateTime(2021, 05, 1)), + WeightEntry(id: 10, weight: 91, date: DateTime(2021, 6, 5)), + WeightEntry(id: 11, weight: 89, date: DateTime(2021, 6, 20)), + WeightEntry(id: 12, weight: 88, date: DateTime(2021, 7, 15)), + WeightEntry(id: 13, weight: 86, date: DateTime(2021, 7, 20)), + WeightEntry(id: 14, weight: 83, date: DateTime(2021, 7, 30)), + WeightEntry(id: 15, weight: 80, date: DateTime(2021, 8, 10)) + ]; + + return ChangeNotifierProvider( + create: (context) => provider, + child: MaterialApp( + locale: Locale(locale), + debugShowCheckedModeBanner: false, + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: wgerTheme, + home: WeightScreen(), + routes: { + FormScreen.routeName: (ctx) => FormScreen(), + }, + ), + ); +} diff --git a/integration_test/README.md b/integration_test/README.md new file mode 100644 index 00000000..98bf8828 --- /dev/null +++ b/integration_test/README.md @@ -0,0 +1,10 @@ +Start emulator and run + +`flutter drive --driver=test_driver/screenshot_driver.dart --target=integration_test/app_test.dart` + +This will generate some screenshots and save them to the Play Store metadata folder + + +See +* +* diff --git a/integration_test/app_test.dart b/integration_test/app_test.dart new file mode 100644 index 00000000..f6b04b1d --- /dev/null +++ b/integration_test/app_test.dart @@ -0,0 +1,96 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import '1_dashboard.dart'; +import '2_workout.dart'; +import '3_gym_mode.dart'; +import '4_measurements.dart'; +import '5_nutritional_plan.dart'; +import '6_weight.dart'; + +Future takeScreenshot(tester, binding, String language, String name) async { + if (Platform.isAndroid) { + await binding.convertFlutterSurfaceToImage(); + await tester.pumpAndSettle(); + } + final filename = 'fastlane/metadata/android/$language/images/phoneScreenshots/$name.png'; + await binding.takeScreenshot(filename); +} + +// Available languages in weblate for the android metadata (not necessarily +// those for which the application is translated) +const languages = [ + //'de-DE', + + // Note: it seems if too many languages are processed at once, some processes + // disappear and no images are written. Doing this in smaller steps works fine + + 'ca', + 'de-DE', + 'en-US', + 'es-ES', + 'fr-FR', + + /* + 'hi-IN', + 'hr', + 'it-IT', + 'pt-BR', + 'nb-NO', + */ + 'pl-PL', + 'ru-RU', + 'tr-TR', + 'uk', + 'zh-CN' +]; + +void main() { + final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + group('Generate screenshots', () { + for (final language in languages) { + final languageCode = language.split('-')[0]; + + testWidgets('dashboard screen - $language', (WidgetTester tester) async { + await tester.pumpWidget(createDashboardScreen(locale: languageCode)); + await takeScreenshot(tester, binding, language, '01 - dashboard'); + }); + + testWidgets('workout detail screen - $language', (WidgetTester tester) async { + await tester.pumpWidget(createWorkoutDetailScreen(locale: languageCode)); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + await takeScreenshot(tester, binding, language, '02 - workout detail'); + }); + + testWidgets('gym mode screen - $language', (WidgetTester tester) async { + await tester.pumpWidget(createGymModeScreen(locale: languageCode)); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + await takeScreenshot(tester, binding, language, '03 - gym mode'); + }); + + testWidgets('measurement screen - $language', (WidgetTester tester) async { + await tester.pumpWidget(createMeasurementScreen(locale: languageCode)); + await takeScreenshot(tester, binding, language, '04 - measurements'); + }); + + testWidgets('nutritional plan detail - $language', (WidgetTester tester) async { + await tester.pumpWidget(createNutritionalPlanScreen(locale: languageCode)); + await tester.tap(find.byType(TextButton)); + await tester.pumpAndSettle(); + await takeScreenshot(tester, binding, language, '05 - nutritional plan'); + }); + + testWidgets('body weight screen - $language', (WidgetTester tester) async { + await tester.pumpWidget(createWeightScreen(locale: languageCode)); + await tester.pumpAndSettle(); + await takeScreenshot(tester, binding, language, '06 - weight'); + }); + } + }); +} diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index cbd6d940..b8ebd6ec 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -41,5 +41,7 @@ UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone + diff --git a/lib/helpers/consts.dart b/lib/helpers/consts.dart index 1164b99b..4dcfb723 100644 --- a/lib/helpers/consts.dart +++ b/lib/helpers/consts.dart @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import 'package:flutter/animation.dart'; +import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; /// Size for the "smaller" icons, e.g. when they belong to less important items @@ -45,9 +45,10 @@ const DAYS_TO_CACHE = 20; /// Name of the submit button in forms const SUBMIT_BUTTON_KEY_NAME = 'submit-button'; -/// Local Preferences key for exercises +/// Local Preferences keys const PREFS_EXERCISES = 'exerciseData'; const PREFS_EXERCISE_CACHE_VERSION = 'cacheVersion'; +const PREFS_INGREDIENTS = 'ingredientData'; const DEFAULT_ANIMATION_DURATION = Duration(milliseconds: 200); const DEFAULT_ANIMATION_CURVE = Curves.bounceIn; @@ -75,3 +76,26 @@ const ENERGY_CARBOHYDRATES = 4; /// kcal per gram of fat (approx) const ENERGY_FAT = 9; + +/// Language ID for English (fallback) +const LANGUAGE_SHORT_ENGLISH = 'en'; + +/// IDs of the different image art styles +/// +/// Values taken from exercises/models/image.py +enum EXERCISE_IMAGE_ART_STYLE { + _, // 0 is not used + LINE_ART, + THREE_D, + LOW_POLY, + PHOTO, + OTHER, +} + +/// Colors used for muscles +const COLOR_MAIN_MUSCLES = Colors.red; +const COLOR_SECONDARY_MUSCLES = Colors.orange; + +// Min account age to contribute exercises. Needs to be kept in sync with +// the value on the backend +const MIN_ACCOUNT_AGE = 14; diff --git a/lib/helpers/exercises/forms.dart b/lib/helpers/exercises/forms.dart new file mode 100644 index 00000000..25d92bde --- /dev/null +++ b/lib/helpers/exercises/forms.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +/// The amount of characters an exercise description needs to have +const MIN_CHARS_DESCRIPTION = 40; + +/// The amount of characters an exercise name needs to have +const MIN_CHARS_NAME = 5; +const MAX_CHARS_NAME = 40; + +String? validateName(String? name, BuildContext context) { + if (name!.isEmpty) { + return AppLocalizations.of(context).enterValue; + } + + if (name.length < MIN_CHARS_NAME || name.length > MAX_CHARS_NAME) { + return AppLocalizations.of(context).enterCharacters(MIN_CHARS_NAME, MAX_CHARS_NAME); + } + + return null; +} + +String? validateDescription(String? name, BuildContext context) { + if (name!.isEmpty) { + return AppLocalizations.of(context).enterValue; + } + + if (name.length < MIN_CHARS_DESCRIPTION) { + return AppLocalizations.of(context).enterMinCharacters(MIN_CHARS_DESCRIPTION); + } + + return null; +} diff --git a/lib/helpers/i18n.dart b/lib/helpers/i18n.dart new file mode 100644 index 00000000..9820f740 --- /dev/null +++ b/lib/helpers/i18n.dart @@ -0,0 +1,109 @@ +/// This code is autogenerated in the backend repo in extract-i18n.py do not edit! + +/// Translate dynamic strings that are returned from the server +/// These strings such as categories or equipment are returned by the server +/// in English and need to be translated here in the application (there are +/// probably better ways to do this, but that's the way it is right now). + +import 'package:flutter/widgets.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +String getTranslation(String value, BuildContext context) { + switch (value) { + case 'Abs': + return AppLocalizations.of(context).abs; + + case 'Arms': + return AppLocalizations.of(context).arms; + + case 'Back': + return AppLocalizations.of(context).back; + + case 'Barbell': + return AppLocalizations.of(context).barbell; + + case 'Bench': + return AppLocalizations.of(context).bench; + + case 'Biceps': + return AppLocalizations.of(context).biceps; + + case 'Calves': + return AppLocalizations.of(context).calves; + + case 'Cardio': + return AppLocalizations.of(context).cardio; + + case 'Chest': + return AppLocalizations.of(context).chest; + + case 'Dumbbell': + return AppLocalizations.of(context).dumbbell; + + case 'Glutes': + return AppLocalizations.of(context).glutes; + + case 'Gym mat': + return AppLocalizations.of(context).gym_mat; + + case 'Hamstrings': + return AppLocalizations.of(context).hamstrings; + + case 'Incline bench': + return AppLocalizations.of(context).incline_bench; + + case 'Kettlebell': + return AppLocalizations.of(context).kettlebell; + + case 'Kilometers': + return AppLocalizations.of(context).kilometers; + + case 'Lats': + return AppLocalizations.of(context).lats; + + case 'Legs': + return AppLocalizations.of(context).legs; + + case 'Lower back': + return AppLocalizations.of(context).lower_back; + + case 'Miles': + return AppLocalizations.of(context).miles; + + case 'Minutes': + return AppLocalizations.of(context).minutes; + + case 'Pull-up bar': + return AppLocalizations.of(context).pull_up_bar; + + case 'Quads': + return AppLocalizations.of(context).quads; + + case 'Repetitions': + return AppLocalizations.of(context).repetitions; + + case 'SZ-Bar': + return AppLocalizations.of(context).sz_bar; + + case 'Seconds': + return AppLocalizations.of(context).seconds; + + case 'Shoulders': + return AppLocalizations.of(context).shoulders; + + case 'Swiss Ball': + return AppLocalizations.of(context).swiss_ball; + + case 'Triceps': + return AppLocalizations.of(context).triceps; + + case 'Until Failure': + return AppLocalizations.of(context).until_failure; + + case 'none (bodyweight exercise)': + return AppLocalizations.of(context).none__bodyweight_exercise_; + + default: + throw FormatException('Could not translate the server string $value'); + } +} diff --git a/lib/helpers/misc.dart b/lib/helpers/misc.dart index 05e5d693..62272b06 100644 --- a/lib/helpers/misc.dart +++ b/lib/helpers/misc.dart @@ -93,8 +93,8 @@ extension TimeOfDayExtension on TimeOfDay { } void launchURL(String url, BuildContext context) async { - await canLaunch(url) - ? await launch(url) + await canLaunchUrl(Uri.parse(url)) + ? await launchUrl(Uri.parse(url)) : ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Could not open $url.')), ); diff --git a/lib/helpers/ui.dart b/lib/helpers/ui.dart index 5219c000..626e42e6 100644 --- a/lib/helpers/ui.dart +++ b/lib/helpers/ui.dart @@ -22,7 +22,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:provider/provider.dart'; import 'package:wger/exceptions/http_exception.dart'; -import 'package:wger/models/exercises/exercise.dart'; +import 'package:wger/models/exercises/base.dart'; +import 'package:wger/models/exercises/translation.dart'; import 'package:wger/models/workouts/log.dart'; import 'package:wger/providers/workout_plans.dart'; @@ -56,7 +57,15 @@ void showHttpExceptionErrorDialog(WgerHttpException exception, BuildContext cont final List errorList = []; for (final key in exception.errors!.keys) { // Error headers - errorList.add(Text(key, style: const TextStyle(fontWeight: FontWeight.bold))); + // Ensure that the error heading first letter is capitalized. + final String errorHeaderMsg = key[0].toUpperCase() + key.substring(1, key.length); + + errorList.add( + Text( + errorHeaderMsg, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ); // Error messages if (exception.errors![key] is String) { @@ -74,6 +83,7 @@ void showHttpExceptionErrorDialog(WgerHttpException exception, BuildContext cont builder: (ctx) => AlertDialog( title: Text(AppLocalizations.of(ctx).anErrorOccurred), content: Column( + crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [...errorList], ), @@ -93,8 +103,13 @@ void showHttpExceptionErrorDialog(WgerHttpException exception, BuildContext cont // showDialog(context: context, builder: (context) => Container()); } -dynamic showDeleteDialog(BuildContext context, String confirmDeleteName, Log log, Exercise exercise, - Map> _exerciseData) async { +dynamic showDeleteDialog( + BuildContext context, + String confirmDeleteName, + Log log, + Translation exercise, + Map> exerciseData, +) async { final res = await showDialog( context: context, builder: (BuildContext contextDialog) { @@ -113,7 +128,7 @@ dynamic showDeleteDialog(BuildContext context, String confirmDeleteName, Log log style: TextStyle(color: Theme.of(context).errorColor), ), onPressed: () { - _exerciseData[exercise]!.removeWhere((el) => el.id == log.id); + exerciseData[exercise]!.removeWhere((el) => el.id == log.id); Provider.of(context, listen: false).deleteLog( log, ); diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/lib/l10n/app_ar.arb @@ -0,0 +1 @@ +{} diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 9dd51a8f..b75194d5 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -194,9 +194,9 @@ "@logHelpEntriesUnits": {}, "logHelpEntries": "Gibt es an einem Tag mehrere Einträge mit der gleichen Anzahl von Wiederholungen, aber unterschiedlichen Gewichten, wird nur der Eintrag mit dem höheren Gewicht im Diagramm angezeigt.", "@logHelpEntries": {}, - "loginInstead": "Stattdessen anmelden", + "loginInstead": "Du hast bereits einen Account? Stattdessen anmelden", "@loginInstead": {}, - "registerInstead": "Stattdessen registrieren", + "registerInstead": "Du hast keinen Account? Jetzt registrieren", "@registerInstead": {}, "reset": "Zurücksetzen", "@reset": { @@ -573,5 +573,53 @@ "scanBarcode": "Strichcode scannen", "@scanBarcode": { "description": "Label for scan barcode button" - } + }, + "abs": "Bauch", + "@abs": {}, + "arms": "Arme", + "@arms": {}, + "back": "Rücken", + "@back": {}, + "calves": "Waden", + "@calves": {}, + "chest": "Brust", + "@chest": {}, + "legs": "Beine", + "@legs": {}, + "shoulders": "Schultern", + "@shoulders": {}, + "barbell": "Langhantel", + "@barbell": {}, + "noMeasurementEntries": "Du hast keine Messeingaben", + "@noMeasurementEntries": {}, + "moreMeasurementEntries": "Neue Messung hinzufügen", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, + "selectEntry": "Bitte einen Eintrag auswählen", + "@selectEntry": {}, + "exercises": "Übung", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "userProfile": "Dein Profil", + "@userProfile": {}, + "exerciseList": "Trainingsplan", + "@exerciseList": {}, + "exerciseName": "Name der Übung", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "translation": "Übersetzung", + "@translation": {}, + "translateExercise": "Diese Übung jetzt übersetzen", + "@translateExercise": {}, + "baseData": "Grundlagen auf Englisch", + "@baseData": { + "description": "The base data for an exercise such as category, trained muscles, etc." + }, + "images": "Bilder", + "@images": {}, + "language": "Bilder", + "@language": {} } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 0e569b54..14e6759e 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1,5 +1,6 @@ { "@@last_modified": "2020-11-11T15:04:05.523531", + "userProfile": "Your profile", "login": "Log in", "@login": { "description": "Text for login button" @@ -56,7 +57,7 @@ "@customServerUrl": { "description": "Label in the form where the users can enter their own wger instance" }, - "customServerHint": "Enter the the address of your own server, otherwise the default one will be used", + "customServerHint": "Enter the address of your own server, otherwise the default one will be used", "@customServerHint": { "description": "Hint text for the form where the users can enter their own wger instance" }, @@ -64,9 +65,9 @@ "@reset": { "description": "Button text allowing the user to reset the entered values to the default" }, - "registerInstead": "Register instead", + "registerInstead": "Don't have an account? Register now", "@registerInstead": {}, - "loginInstead": "Log in instead", + "loginInstead": "Already have an account? Login", "@loginInstead": {}, "labelWorkoutPlans": "Workout plans", "@labelWorkoutPlans": { @@ -100,10 +101,19 @@ "@successfullySaved": { "description": "Message when an item was successfully saved" }, + "exerciseList": "Exercise list", "exercise": "Exercise", "@exercise": { "description": "An exercise for a workout" }, + "exercises": "Exercises", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "exerciseName": "Exercise Name", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, "searchExercise": "Search exercise to add", "@searchExercise": { "description": "Label on set form. Selected exercises are added to the set" @@ -136,10 +146,6 @@ "@noWorkoutPlans": { "description": "Message shown when the user has no workout plans" }, - "repetitions": "Repetitions", - "@repetitions": { - "description": "Repetitions for an exercise set" - }, "reps": "Reps", "@reps": { "description": "Shorthand for repetitions, used when space constraints are tighter" @@ -265,12 +271,15 @@ "description": "The weight of a workout log or body weight entry" }, "measurement": "Measurement", + "@measurement": {}, "measurements": "Measurements", "@measurements": { "description": "Categories for the measurements such as biceps size, body fat, etc." }, "measurementCategoriesHelpText": "Measurement category, such as 'biceps' or 'body fat'", + "@measurementCategoriesHelpText": {}, "measurementEntriesHelpText": "The unit used to measure the category such as 'cm' or '%'", + "@measurementEntriesHelpText": {}, "date": "Date", "@date": { "description": "The date of a workout log or body weight entry" @@ -296,6 +305,7 @@ "description": "The end time of a workout" }, "timeStartAhead": "Start time cannot be ahead of end time", + "@timeStartAhead": {}, "ingredient": "Ingredient", "@ingredient": {}, "energy": "Energy", @@ -311,6 +321,7 @@ "description": "Energy in a meal in kilocalories, kcal" }, "macronutrients": "Macronutrients", + "@macronutrients": {}, "planned": "Planned", "@planned": { "description": "Header for the column of 'planned' nutritional values, i.e. what should be eaten" @@ -324,7 +335,9 @@ "description": "Header for the column of '7 day average' nutritional values, i.e. what was logged last week" }, "difference": "Difference", + "@difference": {}, "percentEnergy": "Percent of energy", + "@percentEnergy": {}, "gPerBodyKg": "g per body kg", "@gPerBodyKg": { "description": "Label used for total sums of e.g. calories or similar in grams per Kg of body weight" @@ -345,13 +358,13 @@ "@protein": {}, "proteinShort": "P", "@proteinShort": { - "description" : "The first letter or short name of the word 'Protein', used in overviews" + "description": "The first letter or short name of the word 'Protein', used in overviews" }, "carbohydrates": "Carbohydrates", "@carbohydrates": {}, "carbohydratesShort": "C", "@carbohydratesShort": { - "description" : "The first letter or short name of the word 'Carbohydrates', used in overviews" + "description": "The first letter or short name of the word 'Carbohydrates', used in overviews" }, "sugars": "Sugars", "@sugars": {}, @@ -359,7 +372,7 @@ "@fat": {}, "fatShort": "F", "@fatShort": { - "description" : "The first letter or short name of the word 'Fat', used in overviews" + "description": "The first letter or short name of the word 'Fat', used in overviews" }, "saturatedFat": "Saturated fat", "@saturatedFat": {}, @@ -383,6 +396,14 @@ "@noWeightEntries": { "description": "Message shown when the user has no logged weight entries" }, + "noMeasurementEntries": "You have no measurement entries", + "@noMeasurementntries": { + "description": "Message shown when the user has no logged measurement entries" + }, + "moreMeasurementEntries": "Add new measurement", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, "edit": "Edit", "@edit": {}, "loadingText": "Loading...", @@ -406,6 +427,7 @@ "description": "Switch to toggle detail / overview" }, "goToDetailPage": "Go to detail page", + "@goToDetailPage": {}, "aboutDescription": "Thank you for using wger! wger is a collaborative open source project, made by fitness enthusiasts from around the world.", "@aboutDescription": { "description": "Text in the about dialog" @@ -456,6 +478,7 @@ "@enterValue": { "description": "Error message when the user hasn't entered a value on a required field" }, + "selectEntry": "Please select an entry", "selectExercise": "Please select an exercise", "@selectExercise": { "description": "Error message when the user hasn't selected an exercise in the form" @@ -469,6 +492,15 @@ "max": {} } }, + "enterMinCharacters": "Please enter at least {min} characters", + "@enterMinCharacters": { + "description": "Error message when the user hasn't entered the minimum amount characters in a form", + "type": "text", + "placeholders": { + "min": {} + } + }, + "baseNameEnglish": "All exercises need a base name in English", "nrOfSets": "Sets per exercise: {nrOfSets}", "@nrOfSets": { "description": "Label shown on the slider where the user selects the nr of sets", @@ -503,21 +535,25 @@ "description": "Label for the popup with general app options" }, "takePicture": "Take a picture", + "@takePicture": {}, "chooseFromLibrary": "Choose from photo library", + "@chooseFromLibrary": {}, "gallery": "Gallery", + "@gallery": {}, "addImage": "Add image", + "@addImage": {}, "dataCopied": "Data copied to new entry", "@dataCopied": { "description": "Snackbar message to show on copying data to a new log entry" }, - "appUpdateTitle" : "Update needed", - "appUpdateContent" : "This version of the app is not compatible with the server, please update your application.", - + "appUpdateTitle": "Update needed", + "@appUpdateTitle": {}, + "appUpdateContent": "This version of the app is not compatible with the server, please update your application.", + "@appUpdateContent": {}, "productFound": "Product found", "@productFound": { "description": "Header label for dialog when product is found with barcode" }, - "productFoundDescription": "The barcode corresponds to this product: {productName}. Do you want to continue?", "@productFoundDescription": { "description": "Dialog info when product is found with barcode", @@ -545,5 +581,83 @@ "close": "Close", "@close": { "description": "Translation for close" - } + }, + "add_exercise_image_license": "Images must be compatible with the CC BY SA license. If in doubt, upload only photos you've taken yourself.", + "variations": "Variations", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "alsoKnownAs": "Also known as: {aliases}", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "verifiedEmail": "Verified email", + "unVerifiedEmail": "Unverified email", + "verifiedEmailReason": "You need to verify your email to contribute exercises", + "verifiedEmailInfo": "A verification email was sent to {email}", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "alternativeNames": "Alternative names", + "oneNamePerLine": "One name per line", + "whatVariationsExist": "What variations of this exercise exist, if any?", + "previous": "Previous", + "next": "Next", + "images": "Images", + "language": "Language", + "addExercise": "Add exercise", + "contributeExercise": "Contribute an exercise", + "translation": "Translation", + "translateExercise": "Translate this exercise now", + "baseData": "Basics in English", + "@baseData": { + "description": "The base data for an exercise such as category, trained muscles, etc." + }, + "aboutPageTitle": "About Wger", + "contributeExerciseWarning": "You can only contribute exercises if your account is older than {days} days and have verified your email", + "@contributeExerciseWarning": { + "description": "Number of days before which a person can add exercise", + "placeholders": { + "days": { + "type": "String", + "example": "14" + } + } + }, + "abs": "Abs", + "arms": "Arms", + "back": "Back", + "barbell": "Barbell", + "bench": "Bench", + "biceps": "Biceps", + "calves": "Calves", + "cardio": "Cardio", + "chest": "Chest", + "dumbbell": "Dumbbell", + "glutes": "Glutes", + "gym_mat": "Gym mat", + "hamstrings": "Hamstrings", + "incline_bench": "Incline bench", + "kettlebell": "Kettlebell", + "kilometers": "Kilometers", + "lats": "Lats", + "legs": "Legs", + "lower_back": "Lower back", + "miles": "Miles", + "minutes": "Minutes", + "pull_up_bar": "Pull-up bar", + "quads": "Quads", + "repetitions": "Repetitions", + "sz_bar": "SZ-Bar", + "seconds": "Seconds", + "shoulders": "Shoulders", + "swiss_ball": "Swiss Ball", + "triceps": "Triceps", + "until_failure": "Until Failure", + "none__bodyweight_exercise_": "none (bodyweight exercise)" } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index c295a7b2..8a54be8b 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -7,7 +7,7 @@ "@kcal": { "description": "Energy in a meal in kilocalories, kcal" }, - "reps": "Rep", + "reps": "Reps", "@reps": { "description": "Shorthand for repetitions, used when space constraints are tighter" }, @@ -140,7 +140,7 @@ "@sugars": {}, "carbohydrates": "Carbohidratos", "@carbohydrates": {}, - "protein": "Proteina", + "protein": "Proteína", "@protein": {}, "g": "g", "@g": { @@ -212,9 +212,9 @@ "@save": {}, "description": "Descripción", "@description": {}, - "logHelpEntriesUnits": "Nota que solo las entradas con una unidad de peso (Kg o lb) y sus repeticiones están tabuladas, las demás combinaciones como por tiempo o hasta el fallo son ignoradas aquí.", + "logHelpEntriesUnits": "Tenga en cuenta que solo se registran las entradas con una unidad de peso (kg o lb) y las repeticiones; aquí se ignoran otras combinaciones, como el tiempo o hasta el fallo.", "@logHelpEntriesUnits": {}, - "logHelpEntries": "Si en un solo día hay más de una entrada con el mismo número de repeticiones pero diferentes pesos, solo la entrada con mayor peso se mostrará en el diagrama.", + "logHelpEntries": "Si en un solo día hay más de una entrada con el mismo número de repeticiones, pero diferentes pesos, solo la entrada con mayor peso se mostrará en el diagrama.", "@logHelpEntries": {}, "todaysWorkout": "Tu rutina de hoy", "@todaysWorkout": {}, @@ -222,7 +222,7 @@ "@gymMode": { "description": "Label when starting the gym mode" }, - "selectExercises": "Si buscas realizar una superserie, puedes buscar algunos ejercicios, estos estarán agrupados juntos", + "selectExercises": "Si quieres hacer una superserie puedes buscar varios ejercicios, se agruparán juntos", "@selectExercises": {}, "newSet": "Nueva serie", "@newSet": { @@ -230,7 +230,7 @@ }, "newDay": "Nuevo día", "@newDay": {}, - "workoutSession": "Sesión de ejercicios", + "workoutSession": "Sesión de entrenamiento", "@workoutSession": { "description": "A (logged) workout session" }, @@ -242,7 +242,7 @@ "@impression": { "description": "General impression (e.g. for a workout session) such as good, bad, etc." }, - "sameRepetitions": "Si realizas las mismas repeticiones y pesos en todas las series, puedes rellenarlas solo en una fila. Por ejemplo, para 4 series solo ingresa 10 para las repeticiones, entonces automáticamente se convertirá en \"4 x 10\".", + "sameRepetitions": "Si haces las mismas repeticiones y el mismo peso para todas las series, solo puedes completar una fila. Por ejemplo, para 4 series solo ingrese 10 para las repeticiones, esto automáticamente se convierte en \"4 x 10\".", "@sameRepetitions": {}, "comment": "Comentario", "@comment": { @@ -256,7 +256,7 @@ "nr": {} } }, - "dayDescriptionHelp": "Una descripción de que se hace este día (ej. 'día de levantamientos') o qué partes del cuerpo se entrenan (ej. 'pecho y espalda')", + "dayDescriptionHelp": "Una descripción de lo que se hace este día (ej. 'día de levantamientos') o qué partes del cuerpo se entrenan (ej. 'pecho y hombros')", "@dayDescriptionHelp": {}, "set": "Serie", "@set": { @@ -316,15 +316,15 @@ "@labelWorkoutPlans": { "description": "Title for screen workout plans" }, - "loginInstead": "Iniciar sesión en su lugar", + "loginInstead": "¿Ya tiene una cuenta? Inicia sesión", "@loginInstead": {}, - "registerInstead": "Registrarse en su lugar", + "registerInstead": "¿No tienes una cuenta? Regístrate ahora", "@registerInstead": {}, "reset": "Reiniciar", "@reset": { "description": "Button text allowing the user to reset the entered values to the default" }, - "customServerHint": "Ingresa la dirección de tu propio servidor (para usar la dirección por defecto dejar este campo en blanco)", + "customServerHint": "Ingresa la dirección de tu propio servidor, de lo contrario se utilizará la dirección por default", "@customServerHint": { "description": "Hint text for the form where the users can enter their own wger instance" }, @@ -340,7 +340,7 @@ "@username": {}, "email": "Dirección de correo electrónico", "@email": {}, - "invalidEmail": "Por favor ingrese una dirección de correo electrónica válida", + "invalidEmail": "Por favor ingrese una dirección de correo electrónico válida", "@invalidEmail": { "description": "Error message when the user enters an invalid email" }, @@ -376,13 +376,13 @@ "@logout": { "description": "Text for logout button" }, - "login": "Acceder", + "login": "Iniciar sesión", "@login": { "description": "Text for login button" }, "addImage": "Añadir imagen", "@addImage": {}, - "gallery": "galería", + "gallery": "Galería", "@gallery": {}, "chooseFromLibrary": "Elije de la biblioteca de fotos", "@chooseFromLibrary": {}, @@ -440,7 +440,7 @@ "@difference": {}, "macronutrients": "Macronutrientes", "@macronutrients": {}, - "timeStartAhead": "La hora de inicio no puede ser anterior a la hora de finalización", + "timeStartAhead": "La hora de inicio no puede adelantarse a la hora de finalización", "@timeStartAhead": {}, "measurements": "Medidas", "@measurements": { @@ -450,7 +450,7 @@ "@measurement": {}, "measurementCategoriesHelpText": "Categoría de medición, como \"bíceps\" o \"grasa corporal", "@measurementCategoriesHelpText": {}, - "measurementEntriesHelpText": "La unidad utilizada para medir la categoría, como p.ej. \"cm\" o \"%\"", + "measurementEntriesHelpText": "La unidad utilizada para medir la categoría, como \"cm\" o \"%\"", "@measurementEntriesHelpText": {}, "value": "Valor", "@value": { @@ -464,7 +464,7 @@ "@energyShort": { "description": "The first letter or short name of the word 'Energy', used in overviews" }, - "searchExercise": "Busca ejercicio para añadirlo", + "searchExercise": "Busca el ejercicio para añadirlo", "@searchExercise": { "description": "Label on set form. Selected exercises are added to the set" }, @@ -498,7 +498,7 @@ "@supersetWith": { "description": "Text used between exercise cards when adding a new set. Translate as something like 'in a superset with'" }, - "rirNotUsed": "Valor RER sin usar", + "rirNotUsed": "Valor ReR sin usar", "@rirNotUsed": { "description": "Label used in RiR slider when the RiR value is not used/saved for the current setting or log" }, @@ -514,7 +514,7 @@ "@gPerBodyKg": { "description": "Label used for total sums of e.g. calories or similar in grams per Kg of body weight" }, - "setUnitsAndRir": "Unidades de serie y RER", + "setUnitsAndRir": "Unidades de serie y ReR", "@setUnitsAndRir": { "description": "Label shown on the slider where the user can toggle showing units and RiR", "type": "text" @@ -527,7 +527,7 @@ "@appUpdateTitle": {}, "appUpdateContent": "Esta versión de la aplicación no es compatible con el servidor. Por favor, actualízala.", "@appUpdateContent": {}, - "productFoundDescription": "El código de barras corresponde a este producto: {productName}. Deseas continuar?", + "productFoundDescription": "El código de barras corresponde a este producto: {productName}. ¿Deseas continuar?", "@productFoundDescription": { "description": "Dialog info when product is found with barcode", "type": "text", @@ -562,5 +562,144 @@ "close": "Cerrar", "@close": { "description": "Translation for close" - } + }, + "noMeasurementEntries": "No has ingresado medidas", + "@noMeasurementEntries": {}, + "moreMeasurementEntries": "Agrega una nueva medida", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, + "variations": "Variantes", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "alsoKnownAs": "También conocido como: {aliases}", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "verifiedEmail": "Correo electrónico verificado", + "@verifiedEmail": {}, + "alternativeNames": "Nombres alternativos", + "@alternativeNames": {}, + "unVerifiedEmail": "Correo electrónico no verificado", + "@unVerifiedEmail": {}, + "verifiedEmailInfo": "Se envió un correo electrónico de verificación a {email}", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "oneNamePerLine": "Un nombre por línea", + "@oneNamePerLine": {}, + "whatVariationsExist": "¿Qué variantes de este ejercicio existen, si las hay?", + "@whatVariationsExist": {}, + "previous": "Anterior", + "@previous": {}, + "next": "Siguiente", + "@next": {}, + "images": "Imágenes", + "@images": {}, + "language": "Lenguaje", + "@language": {}, + "contributeExercise": "Aporta un ejercicio", + "@contributeExercise": {}, + "translation": "Traducción", + "@translation": {}, + "translateExercise": "Traduce este ejercicio ahora", + "@translateExercise": {}, + "baseData": "Conceptos básicos en Inglés", + "@baseData": { + "description": "The base data for an exercise such as category, trained muscles, etc." + }, + "minutes": "Minutos", + "@minutes": {}, + "glutes": "Glúteos", + "@glutes": {}, + "kilometers": "Kilómetros", + "@kilometers": {}, + "until_failure": "Hasta el fallo", + "@until_failure": {}, + "seconds": "Segundos", + "@seconds": {}, + "bench": "Banco", + "@bench": {}, + "barbell": "Barra con pesas", + "@barbell": {}, + "triceps": "Tríceps", + "@triceps": {}, + "swiss_ball": "Pelota Suiza", + "@swiss_ball": {}, + "none__bodyweight_exercise_": "Ninguno (ejercicio de peso corporal)", + "@none__bodyweight_exercise_": {}, + "lower_back": "Espalda baja", + "@lower_back": {}, + "hamstrings": "Isquiotibiales", + "@hamstrings": {}, + "calves": "Pantorrillas", + "@calves": {}, + "chest": "Pecho", + "@chest": {}, + "kettlebell": "Pesa rusa", + "@kettlebell": {}, + "dumbbell": "Mancuerna", + "@dumbbell": {}, + "gym_mat": "Colchoneta", + "@gym_mat": {}, + "abs": "Abdominales", + "@abs": {}, + "incline_bench": "Banco inclinado", + "@incline_bench": {}, + "miles": "Millas", + "@miles": {}, + "legs": "Piernas", + "@legs": {}, + "back": "Espalda", + "@back": {}, + "quads": "Cuádriceps", + "@quads": {}, + "arms": "Brazos", + "@arms": {}, + "aboutPageTitle": "Acerca de Wger", + "@aboutPageTitle": {}, + "userProfile": "Tu perfil", + "@userProfile": {}, + "exerciseList": "Lista de ejercicios", + "@exerciseList": {}, + "exercises": "Ejercicios", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "exerciseName": "Nombre del Ejercicio", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "selectEntry": "Por favor selecciona una entrada", + "@selectEntry": {}, + "baseNameEnglish": "Todos los ejercicios necesitan un nombre base en Inglés", + "@baseNameEnglish": {}, + "lats": "Laterales", + "@lats": {}, + "enterMinCharacters": "Por favor ingresa al menos {min} caracteres", + "@enterMinCharacters": { + "description": "Error message when the user hasn't entered the minimum amount characters in a form", + "type": "text", + "placeholders": { + "min": {} + } + }, + "add_exercise_image_license": "Las imágenes deben ser compatibles con la licencia CC BY SA. Si tienes dudas, sube solamente fotos que hayas tomado tú mismo.", + "@add_exercise_image_license": {}, + "biceps": "Bíceps", + "@biceps": {}, + "verifiedEmailReason": "Necesitas verificar tu correo electrónico para contribuir con ejercicios", + "@verifiedEmailReason": {}, + "pull_up_bar": "Barra de dominadas", + "@pull_up_bar": {}, + "shoulders": "Hombros", + "@shoulders": {}, + "sz_bar": "Barra SZ", + "@sz_bar": {} } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index c063ea69..7d04863e 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -536,5 +536,13 @@ "close": "Fermer", "@close": { "description": "Translation for close" + }, + "productFound": "Produit trouvé", + "@productFound": { + "description": "Header label for dialog when product is found with barcode" + }, + "weekAverage": "Moyenne sur 7 jours", + "@weekAverage": { + "description": "Header for the column of '7 day average' nutritional values, i.e. what was logged last week" } } diff --git a/lib/l10n/app_he.arb b/lib/l10n/app_he.arb index f11ed425..e045a48e 100644 --- a/lib/l10n/app_he.arb +++ b/lib/l10n/app_he.arb @@ -123,7 +123,7 @@ }, "dayDescriptionHelp": "תיאור של מה נעשה ביום זה (למשל ,יום משיכה') או אילו חלקי גוף יהיו באימון (למשל 'חזה וכתפיים')", "@dayDescriptionHelp": {}, - "setNr": "סט מספר", + "setNr": "סט {nr}", "@setNr": { "description": "Header in form indicating the number of the current set. Can also be translated as something like 'Set Nr. xy'.", "type": "text", @@ -299,7 +299,7 @@ "@edit": {}, "delete": "מחיקה", "@delete": {}, - "confirmDelete": "האם את/ה בטוח/ה שאת/ה רוצה למחוק את '{אלמנט למחיקה}'?", + "confirmDelete": "האם את/ה בטוח/ה שאת/ה רוצה למחוק את '{toDelete}'?", "@confirmDelete": { "description": "Confirmation text before the user deletes an object", "type": "text", @@ -360,7 +360,7 @@ "@selectExercise": { "description": "Error message when the user hasn't selected an exercise in the form" }, - "enterCharacters": "אנא בחר/י ערך בין {מינימום} ו-{מקסימום} תווים", + "enterCharacters": "אנא בחר/י ערך בין {min} ו-{max} תווים", "@enterCharacters": { "description": "Error message when the user hasn't entered the correct number of characters in a form", "type": "text", @@ -369,7 +369,7 @@ "max": {} } }, - "nrOfSets": "כמות סטים לאימון: {כמות}", + "nrOfSets": "כמות סטים לאימון: {nrOfSets}", "@nrOfSets": { "description": "Label shown on the slider where the user selects the nr of sets", "type": "text", diff --git a/lib/l10n/app_hr.arb b/lib/l10n/app_hr.arb index 08173668..32bfd599 100644 --- a/lib/l10n/app_hr.arb +++ b/lib/l10n/app_hr.arb @@ -95,7 +95,7 @@ "@logHelpEntriesUnits": {}, "description": "Opis", "@description": {}, - "name": "Naziv", + "name": "Ime", "@name": { "description": "Name for a workout or nutritional plan" }, @@ -381,7 +381,7 @@ "@noWeightEntries": { "description": "Message shown when the user has no logged weight entries" }, - "loadingText": "Učitavanje...", + "loadingText": "Učitavanje …", "@loadingText": { "description": "Text to show when entries are being loaded in the background: Loading..." }, diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb new file mode 100644 index 00000000..49bff8de --- /dev/null +++ b/lib/l10n/app_id.arb @@ -0,0 +1,549 @@ +{ + "@@last_modified": "2020-11-11T15:04:05.523531", + "login": "Masuk", + "@login": { + "description": "Text for login button" + }, + "logout": "Keluar", + "@logout": { + "description": "Text for logout button" + }, + "register": "Daftar", + "@register": { + "description": "Text for registration button" + }, + "useDefaultServer": "Gunakan server bawaan ", + "@useDefaultServer": { + "description": "Toggle button allowing users to switch between the default and a custom wger server" + }, + "useCustomServer": "Gunakan server lain", + "@useCustomServer": { + "description": "Toggle button allowing users to switch between the default and a custom wger server" + }, + "invalidUrl": "Mohon masukkan URL yang valid", + "@invalidUrl": { + "description": "Error message when the user enters an invalid URL, e.g. in the login form" + }, + "usernameValidChars": "Username hanya dapat diisi dengan hiruf, angka, dan karakter @, +, ., -, dan _", + "@usernameValidChars": { + "description": "Error message when the user tries to register a username with forbidden characters" + }, + "passwordsDontMatch": "Password tidak sesuai", + "@passwordsDontMatch": { + "description": "Error message when the user enters two different passwords during registration" + }, + "passwordTooShort": "Password terlalu pendek", + "@passwordTooShort": { + "description": "Error message when the user a password that is too short" + }, + "password": "Password", + "@password": {}, + "confirmPassword": "Konfirmasi Password", + "@confirmPassword": {}, + "invalidEmail": "Mohon masukkan E-mail yang valid", + "@invalidEmail": { + "description": "Error message when the user enters an invalid email" + }, + "email": "Alamat E-mail", + "@email": {}, + "username": "Username", + "@username": {}, + "invalidUsername": "Mohon masukkan username yang valid", + "@invalidUsername": { + "description": "Error message when the user enters an invalid username" + }, + "customServerUrl": "URL dari wger", + "@customServerUrl": { + "description": "Label in the form where the users can enter their own wger instance" + }, + "customServerHint": "Masukkan alamat servermu sendiri, jika tidak akan menggunakan server bawaan", + "@customServerHint": { + "description": "Hint text for the form where the users can enter their own wger instance" + }, + "reset": "Reset", + "@reset": { + "description": "Button text allowing the user to reset the entered values to the default" + }, + "registerInstead": "Mohon daftar terlebih dahulu", + "@registerInstead": {}, + "loginInstead": "Mohon masuk terlebih dahulu", + "@loginInstead": {}, + "labelWorkoutPlans": "Daftar rencana workout", + "@labelWorkoutPlans": { + "description": "Title for screen workout plans" + }, + "labelBottomNavWorkout": "Workout", + "@labelBottomNavWorkout": { + "description": "Label used in bottom navigation, use a short word" + }, + "labelBottomNavNutrition": "Nutrisi", + "@labelBottomNavNutrition": { + "description": "Label used in bottom navigation, use a short word" + }, + "labelWorkoutLogs": "Log latihan", + "@labelWorkoutLogs": { + "description": "(Workout) logs" + }, + "labelWorkoutPlan": "Rencana workout", + "@labelWorkoutPlan": { + "description": "Title for screen workout plan" + }, + "labelDashboard": "Dashboard", + "@labelDashboard": { + "description": "Title for screen dashboard" + }, + "successfullyDeleted": "Terhapus", + "@successfullyDeleted": { + "description": "Message when an item was successfully deleted" + }, + "successfullySaved": "Tersimpan", + "@successfullySaved": { + "description": "Message when an item was successfully saved" + }, + "exercise": "Latihan", + "@exercise": { + "description": "An exercise for a workout" + }, + "searchExercise": "Cari latihan untuk ditambahkan", + "@searchExercise": { + "description": "Label on set form. Selected exercises are added to the set" + }, + "supersetWith": "tambahkan dengan", + "@supersetWith": { + "description": "Text used between exercise cards when adding a new set. Translate as something like 'in a superset with'" + }, + "equipment": "Perlengkapan", + "@equipment": { + "description": "Equipment needed to perform an exercise" + }, + "muscles": "Otot", + "@muscles": { + "description": "(main) muscles trained by an exercise" + }, + "musclesSecondary": "Otot sekunder", + "@musclesSecondary": { + "description": "secondary muscles trained by an exercise" + }, + "category": "Kategori", + "@category": { + "description": "Category for an exercise, ingredient, etc." + }, + "newWorkout": "Rencana workout baru", + "@newWorkout": { + "description": "Header when adding a new workout" + }, + "noWorkoutPlans": "Kamu belum mempunyain rencana workout", + "@noWorkoutPlans": { + "description": "Message shown when the user has no workout plans" + }, + "repetitions": "Pengulangan", + "@repetitions": { + "description": "Repetitions for an exercise set" + }, + "reps": "Reps", + "@reps": { + "description": "Shorthand for repetitions, used when space constraints are tighter" + }, + "rir": "RiR", + "@rir": { + "description": "Shorthand for Repetitions In Reserve" + }, + "rirNotUsed": "RiR tidak digunakan", + "@rirNotUsed": { + "description": "Label used in RiR slider when the RiR value is not used/saved for the current setting or log" + }, + "weightUnit": "Satuan bobot", + "@weightUnit": {}, + "repetitionUnit": "Satuan pengulangan", + "@repetitionUnit": {}, + "set": "Set", + "@set": { + "description": "A set in a workout plan" + }, + "dayDescriptionHelp": "Deskripsi untuk yang sudah diselesaikan hari ini (contoh: 'pull day') atau bagian tubuh mana yang sudah dilatih (contoh: 'dada dan pundak')", + "@dayDescriptionHelp": {}, + "setNr": "Set {nr}", + "@setNr": { + "description": "Header in form indicating the number of the current set. Can also be translated as something like 'Set Nr. xy'.", + "type": "text", + "placeholders": { + "nr": {} + } + }, + "sameRepetitions": "Jika Anda melakukan pengulangan dan bobot yang sama untuk semua set, Anda cukup mengisi satu baris. Misalnya untuk 4 set cukup masukkan 10 untuk pengulangan, ini secara otomatis menjadi \"4 x 10\".", + "@sameRepetitions": {}, + "comment": "Komentar", + "@comment": { + "description": "Comment, additional information" + }, + "impression": "Kesan", + "@impression": { + "description": "General impression (e.g. for a workout session) such as good, bad, etc." + }, + "notes": "Catatan", + "@notes": { + "description": "Personal notes, e.g. for a workout session" + }, + "workoutSession": "Sesi workout", + "@workoutSession": { + "description": "A (logged) workout session" + }, + "newDay": "Hari baru", + "@newDay": {}, + "newSet": "Set baru", + "@newSet": { + "description": "Header when adding a new set to a workout day" + }, + "selectExercises": "Jika Anda ingin melakukan superset, Anda dapat mencari beberapa latihan, mereka akan dikelompokkan bersama", + "@selectExercises": {}, + "gymMode": "Mode gym", + "@gymMode": { + "description": "Label when starting the gym mode" + }, + "plateCalculator": "Plates", + "@plateCalculator": { + "description": "Label used for the plate calculator in the gym mode" + }, + "plateCalculatorNotDivisible": "Tidak memungkinkan untuk mencapai bobot dengan plate yang tersedia", + "@plateCalculatorNotDivisible": { + "description": "Error message when the current weight is not reachable with plates (e.g. 33.1 kg)" + }, + "pause": "Jeda", + "@pause": { + "description": "Noun, not an imperative! Label used for the pause when using the gym mode" + }, + "jumpTo": "Lompat ke", + "@jumpTo": { + "description": "Imperative. Label used in popup allowing the user to jump to a specific exercise while in the gym mode" + }, + "todaysWorkout": "Latihanmu hari ini", + "@todaysWorkout": {}, + "logHelpEntries": "If on a single day there is more than one entry with the same number of repetitions, but different weights, only the entry with the higher weight is shown in the diagram.", + "@logHelpEntries": {}, + "logHelpEntriesUnits": "Note that only entries with a weight unit (kg or lb) and repetitions are charted, other combinations such as time or until failure are ignored here.", + "@logHelpEntriesUnits": {}, + "description": "Description", + "@description": {}, + "name": "Nama", + "@name": { + "description": "Name for a workout or nutritional plan" + }, + "save": "Simpan", + "@save": {}, + "addSet": "Tambah set", + "@addSet": { + "description": "Label for the button that adds a set (to a workout day)" + }, + "addMeal": "Tambah makanan", + "@addMeal": {}, + "mealLogged": "Meal logged to diary", + "@mealLogged": {}, + "logMeal": "Catat makanan ini", + "@logMeal": {}, + "addIngredient": "Tambah komposisi", + "@addIngredient": {}, + "logIngredient": "Simpan di diari nutrisi", + "@logIngredient": {}, + "searchIngredient": "Cari komposisi", + "@searchIngredient": { + "description": "Label on ingredient search form" + }, + "nutritionalPlan": "Nutritional plan", + "@nutritionalPlan": {}, + "nutritionalDiary": "Nutritional diary", + "@nutritionalDiary": {}, + "nutritionalPlans": "Nutritional plans", + "@nutritionalPlans": {}, + "noNutritionalPlans": "You have no nutritional plans", + "@noNutritionalPlans": { + "description": "Message shown when the user has no nutritional plans" + }, + "anErrorOccurred": "An Error Occurred!", + "@anErrorOccurred": {}, + "weight": "Weight", + "@weight": { + "description": "The weight of a workout log or body weight entry" + }, + "measurement": "Ukuran", + "measurements": "Measurements", + "@measurements": { + "description": "Categories for the measurements such as biceps size, body fat, etc." + }, + "measurementCategoriesHelpText": "Measurement category, such as 'biceps' or 'body fat'", + "measurementEntriesHelpText": "The unit used to measure the category such as 'cm' or '%'", + "date": "Date", + "@date": { + "description": "The date of a workout log or body weight entry" + }, + "value": "Value", + "@value": { + "description": "The value of a measurement entry" + }, + "start": "Start", + "@start": { + "description": "Label on button to start the gym mode (i.e., an imperative)" + }, + "time": "Time", + "@time": { + "description": "The time of a meal or workout" + }, + "timeStart": "Start time", + "@timeStart": { + "description": "The starting time of a workout" + }, + "timeEnd": "End time", + "@timeEnd": { + "description": "The end time of a workout" + }, + "timeStartAhead": "Start time cannot be ahead of end time", + "ingredient": "Ingredient", + "@ingredient": {}, + "energy": "Energy", + "@energy": { + "description": "Energy in a meal, ingredient etc. e.g. in kJ" + }, + "energyShort": "E", + "@energyShort": { + "description": "The first letter or short name of the word 'Energy', used in overviews" + }, + "kcal": "kcal", + "@kcal": { + "description": "Energy in a meal in kilocalories, kcal" + }, + "macronutrients": "Macronutrients", + "planned": "Planned", + "@planned": { + "description": "Header for the column of 'planned' nutritional values, i.e. what should be eaten" + }, + "logged": "Logged", + "@logged": { + "description": "Header for the column of 'logged' nutritional values, i.e. what was eaten" + }, + "weekAverage": "7 day average", + "@weekAverage": { + "description": "Header for the column of '7 day average' nutritional values, i.e. what was logged last week" + }, + "difference": "Difference", + "percentEnergy": "Percent of energy", + "gPerBodyKg": "g per body kg", + "@gPerBodyKg": { + "description": "Label used for total sums of e.g. calories or similar in grams per Kg of body weight" + }, + "total": "Total", + "@total": { + "description": "Label used for total sums of e.g. calories or similar" + }, + "kJ": "kJ", + "@kJ": { + "description": "Energy in a meal in kilo joules, kJ" + }, + "g": "g", + "@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": "Carbohydrates", + "@carbohydrates": {}, + "carbohydratesShort": "C", + "@carbohydratesShort": { + "description" : "The first letter or short name of the word 'Carbohydrates', used in overviews" + }, + "sugars": "Sugars", + "@sugars": {}, + "fat": "Fat", + "@fat": {}, + "fatShort": "F", + "@fatShort": { + "description" : "The first letter or short name of the word 'Fat', used in overviews" + }, + "saturatedFat": "Saturated fat", + "@saturatedFat": {}, + "fibres": "Fibre", + "@fibres": {}, + "sodium": "Sodium", + "@sodium": {}, + "amount": "Amount", + "@amount": { + "description": "The amount (e.g. in grams) of an ingredient in a meal" + }, + "unit": "Unit", + "@unit": { + "description": "The unit used for a repetition (kg, time, etc.)" + }, + "newEntry": "New entry", + "@newEntry": { + "description": "Title when adding a new entry such as a weight or log entry" + }, + "noWeightEntries": "You have no weight entries", + "@noWeightEntries": { + "description": "Message shown when the user has no logged weight entries" + }, + "edit": "Edit", + "@edit": {}, + "loadingText": "Loading...", + "@loadingText": { + "description": "Text to show when entries are being loaded in the background: Loading..." + }, + "delete": "Delete", + "@delete": {}, + "confirmDelete": "Are you sure you want to delete '{toDelete}'?", + "@confirmDelete": { + "description": "Confirmation text before the user deletes an object", + "type": "text", + "placeholders": { + "toDelete": {} + } + }, + "newNutritionalPlan": "New nutritional plan", + "@newNutritionalPlan": {}, + "toggleDetails": "Toggle details", + "@toggleDetails": { + "description": "Switch to toggle detail / overview" + }, + "goToDetailPage": "Go to detail page", + "aboutDescription": "Thank you for using wger! wger is a collaborative open source project, made by fitness enthusiasts from around the world.", + "@aboutDescription": { + "description": "Text in the about dialog" + }, + "aboutSourceTitle": "Source code", + "@aboutSourceTitle": { + "description": "Title for source code section in the about dialog" + }, + "aboutSourceText": "Get the source code of this application and its server on github", + "@aboutSourceText": { + "description": "Text for source code section in the about dialog" + }, + "aboutBugsTitle": "Have a problem or idea?", + "@aboutBugsTitle": { + "description": "Title for bugs section in the about dialog" + }, + "aboutBugsText": "Get in touch if something didn't behave as expected or if there is a feature that you feel is missing.", + "@aboutBugsText": { + "description": "Text for bugs section in the about dialog" + }, + "aboutContactUsTitle": "Say hi!", + "@aboutContactUsTitle": { + "description": "Title for contact us section in the about dialog" + }, + "aboutContactUsText": "If you want to chat with us, hop on the Discord server and get in touch", + "@aboutContactUsText": { + "description": "Text for contact us section in the about dialog" + }, + "aboutTranslationTitle": "Translation", + "@aboutTranslationTitle": { + "description": "Title for translation section in the about dialog" + }, + "aboutTranslationText": "This application is translated on weblate. If you also want to help, click the link and start translating", + "@aboutTranslationText": { + "description": "Text for translation section in the about dialog" + }, + "calendar": "Calendar", + "@calendar": {}, + "goToToday": "Go to today", + "@goToToday": { + "description": "Label on button to jump back to 'today' in the calendar widget" + }, + "enterRepetitionsOrWeight": "Please fill in either the repetitions or the weight for at least one of the sets", + "@enterRepetitionsOrWeight": { + "description": "Error message when the user hasn't filled in the forms for exercise sets" + }, + "enterValue": "Please enter a value", + "@enterValue": { + "description": "Error message when the user hasn't entered a value on a required field" + }, + "selectExercise": "Please select an exercise", + "@selectExercise": { + "description": "Error message when the user hasn't selected an exercise in the form" + }, + "enterCharacters": "Please enter between {min} and {max} characters", + "@enterCharacters": { + "description": "Error message when the user hasn't entered the correct number of characters in a form", + "type": "text", + "placeholders": { + "min": {}, + "max": {} + } + }, + "nrOfSets": "Sets per exercise: {nrOfSets}", + "@nrOfSets": { + "description": "Label shown on the slider where the user selects the nr of sets", + "type": "text", + "placeholders": { + "nrOfSets": {} + } + }, + "setUnitsAndRir": "Set units and RiR", + "@setUnitsAndRir": { + "description": "Label shown on the slider where the user can toggle showing units and RiR", + "type": "text" + }, + "enterValidNumber": "Please enter a valid number", + "@enterValidNumber": { + "description": "Error message when the user has submitted an invalid number (e.g. '3,.,.,.')" + }, + "selectIngredient": "Please select an ingredient", + "@selectIngredient": { + "description": "Error message when the user hasn't selected an ingredient from the autocompleter" + }, + "recentlyUsedIngredients": "Recently added ingredients", + "@recentlyUsedIngredients": { + "description": "A message when a user adds a new ingredient to a meal." + }, + "selectImage": "Please select an image", + "@selectImage": { + "description": "Label and error message when the user hasn't selected an image to save" + }, + "optionsLabel": "Options", + "@optionsLabel": { + "description": "Label for the popup with general app options" + }, + "takePicture": "Take a picture", + "chooseFromLibrary": "Choose from photo library", + "gallery": "Gallery", + "addImage": "Add image", + "dataCopied": "Data copied to new entry", + "@dataCopied": { + "description": "Snackbar message to show on copying data to a new log entry" + }, + "appUpdateTitle" : "Update needed", + "appUpdateContent" : "This version of the app is not compatible with the server, please update your application.", + + "productFound": "Product found", + "@productFound": { + "description": "Header label for dialog when product is found with barcode" + }, + + "productFoundDescription": "The barcode corresponds to this product: {productName}. Do you want to continue?", + "@productFoundDescription": { + "description": "Dialog info when product is found with barcode", + "type": "text", + "placeholders": { + "productName": {} + } + }, + "productNotFound": "Product not found", + "@productNotFound": { + "description": "Header label for dialog when product is not found with barcode" + }, + "productNotFoundDescription": "The product with the scanned barcode {barcode} was not found in the wger database", + "@productNotFoundDescription": { + "description": "Dialog info when product is not found with barcode", + "type": "text", + "placeholders": { + "barcode": {} + } + }, + "scanBarcode": "Scan barcode", + "@scanBarcode": { + "description": "Label for scan barcode button" + }, + "close": "Close", + "@close": { + "description": "Translation for close" + } +} diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 70fbf904..961ceb40 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -568,5 +568,21 @@ "searchIngredient": "Cerca ingrediente", "@searchIngredient": { "description": "Label on ingredient search form" - } + }, + "userProfile": "Il tuo profilo", + "@userProfile": {}, + "exerciseList": "Lista esercizi", + "@exerciseList": {}, + "exercises": "Esercizi", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "exerciseName": "Nome Esercizio", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "previous": "Precedente", + "@previous": {}, + "next": "Successivo", + "@next": {} } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 9fd2ce77..07932a02 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -262,9 +262,9 @@ "@measurements": { "description": "Categories for the measurements such as biceps size, body fat, etc." }, - "registerInstead": "Zarejestruj zamiast", + "registerInstead": "Nie posiadasz konta? Zarejestruj się teraz", "@registerInstead": {}, - "loginInstead": "Zaloguj się zamiast tego", + "loginInstead": "Posiadasz konto? Zaloguj się", "@loginInstead": {}, "labelWorkoutPlans": "Plany treningowe", "@labelWorkoutPlans": { @@ -556,5 +556,146 @@ "enterValidNumber": "Proszę wprowadzić poprawny numer", "@enterValidNumber": { "description": "Error message when the user has submitted an invalid number (e.g. '3,.,.,.')" - } + }, + "noMeasurementEntries": "Nie masz wpisów pomiarowych", + "@noMeasurementEntries": {}, + "moreMeasurementEntries": "Dodaj nowy pomiar", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, + "enterMinCharacters": "Proszę wpisać co najmniej {min} znaków", + "@enterMinCharacters": { + "description": "Error message when the user hasn't entered the minimum amount characters in a form", + "type": "text", + "placeholders": { + "min": {} + } + }, + "baseNameEnglish": "Wszystkie ćwiczenia wymagają nazwy podstawowej w języku angielskim", + "@baseNameEnglish": {}, + "images": "Obrazy", + "@images": {}, + "language": "Język", + "@language": {}, + "add_exercise_image_license": "Obrazy muszą być zgodne z licencją CC BY SA. Jeśli masz wątpliwości przesyłaj tylko zdjęcia które sam zrobiłeś.", + "@add_exercise_image_license": {}, + "variations": "Wariacje", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "alsoKnownAs": "Znany również jako: {aliases}", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "unVerifiedEmail": "Niezweryfikowany adres e-mail", + "@unVerifiedEmail": {}, + "verifiedEmail": "Zweryfikowany adres e-mail", + "@verifiedEmail": {}, + "verifiedEmailReason": "Aby współtworzyć ćwiczenia musisz zweryfikować swój adres e-mail", + "@verifiedEmailReason": {}, + "verifiedEmailInfo": "Wiadomość weryfikacyjna została wysłana na adres {email}", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "alternativeNames": "Alternatywne nazwy", + "@alternativeNames": {}, + "oneNamePerLine": "Jedna nazwa w wierszu", + "@oneNamePerLine": {}, + "whatVariationsExist": "Czy istnieją wariacje tego ćwiczenia?", + "@whatVariationsExist": {}, + "previous": "Wstecz", + "@previous": {}, + "next": "Następny", + "@next": {}, + "addExercise": "Dodaj ćwiczenie", + "@addExercise": {}, + "translation": "Tłumaczenie", + "@translation": {}, + "contributeExercise": "Przekaż ćwiczenie", + "@contributeExercise": {}, + "translateExercise": "Przetłumacz to ćwiczenie teraz", + "@translateExercise": {}, + "minutes": "Minuty", + "@minutes": {}, + "kilometers": "Kilometry", + "@kilometers": {}, + "until_failure": "Aż do awarii", + "@until_failure": {}, + "seconds": "Sekundy", + "@seconds": {}, + "bench": "Ławka", + "@bench": {}, + "triceps": "Triceps", + "@triceps": {}, + "swiss_ball": "Piłka lekarska", + "@swiss_ball": {}, + "none__bodyweight_exercise_": "brak (ćwiczenie z masą ciała)", + "@none__bodyweight_exercise_": {}, + "pull_up_bar": "Drążek do podciągania", + "@pull_up_bar": {}, + "biceps": "Biceps", + "@biceps": {}, + "userProfile": "Twój profil", + "@userProfile": {}, + "exerciseList": "Lista ćwiczeń", + "@exerciseList": {}, + "exercises": "Ćwiczenia", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "exerciseName": "Nazwa ćwiczenia", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "selectEntry": "Wybierz wpis", + "@selectEntry": {}, + "incline_bench": "Ławka skośna", + "@incline_bench": {}, + "gym_mat": "Mata gimnastyczna", + "@gym_mat": {}, + "aboutPageTitle": "Więcej o Wger", + "@aboutPageTitle": {}, + "glutes": "Pośladki", + "@glutes": {}, + "baseData": "Podstawy po angielsku", + "@baseData": { + "description": "The base data for an exercise such as category, trained muscles, etc." + }, + "barbell": "Sztanga", + "@barbell": {}, + "lats": "Mięsień najszerszy pleców", + "@lats": {}, + "legs": "Nogi", + "@legs": {}, + "arms": "Ręce", + "@arms": {}, + "sz_bar": "Gryf łamany", + "@sz_bar": {}, + "miles": "Mile", + "@miles": {}, + "shoulders": "Barki", + "@shoulders": {}, + "calves": "Łydki", + "@calves": {}, + "hamstrings": "Mięsień dwugłowy uda", + "@hamstrings": {}, + "chest": "Klatka piersiowa", + "@chest": {}, + "back": "Plecy", + "@back": {}, + "lower_back": "Dolna część pleców", + "@lower_back": {}, + "kettlebell": "Kettle", + "@kettlebell": {}, + "dumbbell": "Hantla", + "@dumbbell": {}, + "abs": "Brzuch", + "@abs": {}, + "quads": "Mięsień czworogłowy uda", + "@quads": {} } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 143e10b4..44325e71 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -253,12 +253,6 @@ "@selectImage": { "description": "Label and error message when the user hasn't selected an image to save" }, - "takePicture": "Tirar uma foto", - "@takePicture": {}, - "chooseFromLibrary": "Escolha na biblioteca de fotos", - "@chooseFromLibrary": {}, - "gallery": "Galeria", - "@gallery": {}, "addImage": "Adicionar imagem", "@addImage": {}, "dataCopied": "Dados copiados para nova entrada", @@ -285,10 +279,6 @@ "@scanBarcode": { "description": "Label for scan barcode button" }, - "close": "Fechar", - "@close": { - "description": "Translation for close" - }, "register": "Registrar", "@register": { "description": "Text for registration button" @@ -556,5 +546,72 @@ "placeholders": { "productName": {} } - } + }, + "alsoKnownAs": "Também chamado de: {aliases}", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "verifiedEmail": "Email verificado", + "unVerifiedEmail": "Verificação pendente", + "verifiedEmailReason": "É necessário verificar seu email para contribuir com exercícios", + "verifiedEmailInfo": "Um email de verificação foi enviado para {email}", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "close": "Fechar", + "@close": { + "description": "Translation for close" + }, + "variations": "Variações", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "oneNamePerLine": "Somente um nome por linha", + "whatVariationsExist": "Se houver alguma, quais as possíveis variações para esse exercício?", + "takePicture": "Tirar uma foto", + "@takePicture": {}, + "chooseFromLibrary": "Escolher da galeria", + "@chooseFromLibrary": {}, + "gallery": "Galeria de fotos", + "@gallery": {}, + "addExercise": "Adicionar exercício", + "translation": "Tradução", + "translateExercise": "Traduzir este exercício", + "alternativeNames": "Outros nomes", + "images": "Imagens", + "language": "Idioma", + "previous": "Anterior", + "next": "Próximo", + "minutes": "Minutos", + "seconds": "Segundos", + "until_failure": "Até a falha", + "kilometers": "Quilômetros", + "glutes": "Glúteos", + "bench": "Supino", + "barbell": "Barra", + "triceps": "Tríceps", + "biceps": "Bíceps", + "dumbbell": "Haltere", + "abs": "Abdominal", + "chest": "Peito", + "shoulders": "Ombro", + "gym_mat": "Colchonete", + "incline_bench": "Supino inclinado", + "calves": "Panturrilha", + "legs": "Pernas", + "lats": "Dorsal", + "quads": "Quadríceps", + "hamstrings": "Posterior de coxa", + "arms": "Braços", + "pull_up_bar": "Barra fixa", + "lower_back": "Lombar", + "swiss_ball": "Bola suíça", + "kettlebell": "Kettlebell", + "none__bodyweight_exercise_": "nenhum (somente peso do corpo)", + "aboutPageTitle": "Sobre Wger" } diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index f7bbc05c..ae0da020 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -55,9 +55,9 @@ "@labelBottomNavWorkout": { "description": "Label used in bottom navigation, use a short word" }, - "loginInstead": "Bunun yerine giriş yapın", + "loginInstead": "Zaten hesabınız var mı? Oturum açın", "@loginInstead": {}, - "registerInstead": "Bunun yerine kaydolun", + "registerInstead": "Hesabınız yok mu? Şimdi kaydolun", "@registerInstead": {}, "reset": "Sıfırla", "@reset": { @@ -556,5 +556,158 @@ "dataCopied": "Veriler yeni girişe kopyalandı", "@dataCopied": { "description": "Snackbar message to show on copying data to a new log entry" + }, + "alsoKnownAs": "{aliases} olarak da bilinir", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "exerciseList": "Egzersiz listesi", + "@exerciseList": {}, + "images": "Resimler", + "@images": {}, + "exerciseName": "Egzersiz Adı", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "enterMinCharacters": "Lütfen en az {min} karakter girin", + "@enterMinCharacters": { + "description": "Error message when the user hasn't entered the minimum amount characters in a form", + "type": "text", + "placeholders": { + "min": {} + } + }, + "add_exercise_image_license": "Görseller CC BY SA lisansı ile uyumlu olmalıdır. Emin değilseniz, yalnızca kendi çektiğiniz fotoğrafları yükleyin.", + "@add_exercise_image_license": {}, + "verifiedEmailReason": "Egzersizlere katkıda bulunmak için e-posta adresinizi doğrulamanız gerekiyor", + "@verifiedEmailReason": {}, + "alternativeNames": "Alternatif isimler", + "@alternativeNames": {}, + "minutes": "Dakika", + "@minutes": {}, + "seconds": "Saniye", + "@seconds": {}, + "verifiedEmailInfo": "{email} adresine bir doğrulama e-postası gönderildi", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "previous": "Önceki", + "@previous": {}, + "next": "Sonraki", + "@next": {}, + "translateExercise": "Bu egzersizi şimdi çevir", + "@translateExercise": {}, + "glutes": "Kalça kasları", + "@glutes": {}, + "kilometers": "Kilometre", + "@kilometers": {}, + "dumbbell": "Dambıl", + "@dumbbell": {}, + "bench": "Benç", + "@bench": {}, + "none__bodyweight_exercise_": "yok (vücut ağırlığı egzersizi)", + "@none__bodyweight_exercise_": {}, + "shoulders": "Omuzlar", + "@shoulders": {}, + "biceps": "Pazılar", + "@biceps": {}, + "arms": "Kollar", + "@arms": {}, + "incline_bench": "Eğim tezgahı", + "@incline_bench": {}, + "userProfile": "Profilin", + "@userProfile": {}, + "selectEntry": "Lütfen bir giriş seçin", + "@selectEntry": {}, + "baseNameEnglish": "Tüm egzersizlerin İngilizce bir ismi olmalıdır", + "@baseNameEnglish": {}, + "variations": "Varyasyonlar", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "verifiedEmail": "Doğrulanmış e-posta adresi", + "@verifiedEmail": {}, + "unVerifiedEmail": "Doğrulanmamış e-posta adresi", + "@unVerifiedEmail": {}, + "oneNamePerLine": "Satır başına bir ad", + "@oneNamePerLine": {}, + "whatVariationsExist": "Varsa, bu egzersizin hangi varyasyonları vardır?", + "@whatVariationsExist": {}, + "language": "Dil", + "@language": {}, + "addExercise": "Egzersiz ekle", + "@addExercise": {}, + "contributeExercise": "Egzersize katkıda bulunun", + "@contributeExercise": {}, + "until_failure": "Başarısız olana kadar", + "@until_failure": {}, + "barbell": "Halter", + "@barbell": {}, + "lower_back": "Alt sırt", + "@lower_back": {}, + "pull_up_bar": "Barfiks çubuğu", + "@pull_up_bar": {}, + "calves": "Baldırlar", + "@calves": {}, + "chest": "Göğüs", + "@chest": {}, + "triceps": "Triceps kasları", + "@triceps": {}, + "swiss_ball": "Egzersiz Topu", + "@swiss_ball": {}, + "hamstrings": "Hamstringler", + "@hamstrings": {}, + "gym_mat": "Spor matı", + "@gym_mat": {}, + "miles": "Mil", + "@miles": {}, + "kettlebell": "Kettlebell", + "@kettlebell": {}, + "abs": "Karın Kasları", + "@abs": {}, + "lats": "Lat kasları", + "@lats": {}, + "legs": "Bacaklar", + "@legs": {}, + "back": "Sırt", + "@back": {}, + "quads": "Quad kasları", + "@quads": {}, + "sz_bar": "Z-Bar", + "@sz_bar": {}, + "exercises": "Egzersizler", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "translation": "Çeviri", + "@translation": {}, + "baseData": "İngilizce'de temel bilgiler", + "@baseData": { + "description": "The base data for an exercise such as category, trained muscles, etc." + }, + "noMeasurementEntries": "Ölçüm girdiniz yok", + "@noMeasurementEntries": {}, + "moreMeasurementEntries": "Yeni ölçüm ekle", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, + "aboutPageTitle": "Wger Hakkında", + "@aboutPageTitle": {}, + "cardio": "Kardiyo", + "@cardio": {}, + "contributeExerciseWarning": "Yalnızca hesabınız {days} günden eskiyse ve e-posta adresinizi doğruladıysanız egzersizlere katkıda bulunabilirsiniz", + "@contributeExerciseWarning": { + "description": "Number of days before which a person can add exercise", + "placeholders": { + "days": { + "type": "String", + "example": "14" + } + } } } diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index e7c81a5b..0f844d8f 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -57,7 +57,7 @@ }, "username": "Ім'я користувача", "@username": {}, - "customServerHint": "Введіть адресу свого власного сервера, інакше буде використовуватися сервер за промовчанням", + "customServerHint": "Введіть адресу власного сервера, інакше буде використовуватися за замовчуванням", "@customServerHint": { "description": "Hint text for the form where the users can enter their own wger instance" }, @@ -65,7 +65,7 @@ "@reset": { "description": "Button text allowing the user to reset the entered values to the default" }, - "loginInstead": "Натомість увійти", + "loginInstead": "Вже маєте обліковий запис? Увійти", "@loginInstead": {}, "labelWorkoutPlans": "Плани тренувань", "@labelWorkoutPlans": { @@ -203,7 +203,7 @@ "@successfullySaved": { "description": "Message when an item was successfully saved" }, - "registerInstead": "Натомість зареєструватися", + "registerInstead": "У вас немає облікового запису? Зареєструйтесь зараз", "@registerInstead": {}, "labelBottomNavNutrition": "Харчування", "@labelBottomNavNutrition": { @@ -443,7 +443,7 @@ "@aboutSourceTitle": { "description": "Title for source code section in the about dialog" }, - "aboutSourceText": "Отримайте джерельний код цього додатка та його сервера на github", + "aboutSourceText": "Отримайте джерельний код цього застосунку та його сервера на github", "@aboutSourceText": { "description": "Text for source code section in the about dialog" }, @@ -463,7 +463,7 @@ "@aboutTranslationTitle": { "description": "Title for translation section in the about dialog" }, - "aboutTranslationText": "Цей додаток перекладено на Weblate. Якщо ви також хочете допомогти, клацніть на посилання та почніть переклад", + "aboutTranslationText": "Цей заатосунок перекладено на Weblate. Якщо ви також хочете допомогти, клацніть на посилання та почніть переклад", "@aboutTranslationText": { "description": "Text for translation section in the about dialog" }, @@ -527,7 +527,7 @@ }, "appUpdateTitle": "Потрібне оновлення", "@appUpdateTitle": {}, - "appUpdateContent": "Ця версія програми несумісна з сервером, будь ласка, оновіть додаток.", + "appUpdateContent": "Ця версія застосунку несумісна з сервером, будь ласка, оновіть застосунок.", "@appUpdateContent": {}, "productFound": "Виріб знайдено", "@productFound": { @@ -552,5 +552,162 @@ "close": "Закрити", "@close": { "description": "Translation for close" + }, + "rir": "RiR", + "@rir": { + "description": "Shorthand for Repetitions In Reserve" + }, + "miles": "Милі", + "@miles": {}, + "aboutPageTitle": "Про Wger", + "@aboutPageTitle": {}, + "noMeasurementEntries": "У вас немає записів вимірювання", + "@noMeasurementEntries": {}, + "moreMeasurementEntries": "Додати нове вимірювання", + "@moreMeasurementEntries": { + "description": "Message shown when the user wants to add new measurement" + }, + "verifiedEmailInfo": "Повідомлення з підтвердженням електронної пошти надіслано на {email}", + "@verifiedEmailInfo": { + "placeholders": { + "email": {} + } + }, + "addExercise": "Додати вправу", + "@addExercise": {}, + "none__bodyweight_exercise_": "немає (вправи з власною вагою)", + "@none__bodyweight_exercise_": {}, + "abs": "Живіт", + "@abs": {}, + "baseData": "Основи англійської", + "@baseData": { + "description": "The base data for an exercise such as category, trained muscles, etc." + }, + "minutes": "Хвилини", + "@minutes": {}, + "glutes": "Сідниці", + "@glutes": {}, + "kilometers": "Кілометри", + "@kilometers": {}, + "seconds": "Секунди", + "@seconds": {}, + "bench": "Лавка", + "@bench": {}, + "barbell": "Штанга", + "@barbell": {}, + "triceps": "Трицепс", + "@triceps": {}, + "swiss_ball": "Швейцарський м'яч", + "@swiss_ball": {}, + "lower_back": "Нижня частина спини", + "@lower_back": {}, + "shoulders": "Плечі", + "@shoulders": {}, + "hamstrings": "Підколінні сухожилля", + "@hamstrings": {}, + "chest": "Груди", + "@chest": {}, + "biceps": "Біцепс", + "@biceps": {}, + "dumbbell": "Гантеля", + "@dumbbell": {}, + "gym_mat": "Гімнастичний мат", + "@gym_mat": {}, + "incline_bench": "Похила лавка", + "@incline_bench": {}, + "lats": "Найширші м'язи спини", + "@lats": {}, + "legs": "Ноги", + "@legs": {}, + "back": "Спина", + "@back": {}, + "quads": "Квадроцикли", + "@quads": {}, + "arms": "Руки", + "@arms": {}, + "sz_bar": "SZ-Штанга", + "@sz_bar": {}, + "kettlebell": "Гиря", + "@kettlebell": {}, + "calves": "Ікри", + "@calves": {}, + "pull_up_bar": "Перекладина", + "@pull_up_bar": {}, + "until_failure": "До відмови", + "@until_failure": {}, + "userProfile": "Твій профіль", + "@userProfile": {}, + "exerciseList": "Список вправ", + "@exerciseList": {}, + "exercises": "Вправи", + "@exercises": { + "description": "Multiple exercises for a workout" + }, + "exerciseName": "Назва вправи", + "@exerciseName": { + "description": "Label for the name of a workout exercise" + }, + "add_exercise_image_license": "Зображення повинні бути сумісні з ліцензією CC BY SA. Якщо ви сумніваєтеся, завантажуйте лише фотографії, які ви зробили самі.", + "@add_exercise_image_license": {}, + "translateExercise": "Перекладіть цю вправу зараз", + "@translateExercise": {}, + "selectEntry": "Будь ласка, виберіть запис", + "@selectEntry": {}, + "enterMinCharacters": "Будь ласка, введіть принаймні {min} символи", + "@enterMinCharacters": { + "description": "Error message when the user hasn't entered the minimum amount characters in a form", + "type": "text", + "placeholders": { + "min": {} + } + }, + "baseNameEnglish": "Всі вправи потребують базової назви англійською", + "@baseNameEnglish": {}, + "variations": "Варіації", + "@variations": { + "description": "Variations of one exercise (e.g. benchpress and benchpress narrow)" + }, + "alsoKnownAs": "Також відомий як: {aliases}", + "@alsoKnownAs": { + "placeholders": { + "aliases": {} + }, + "description": "List of alternative names for an exercise" + }, + "verifiedEmail": "Підтверджена електронна пошта", + "@verifiedEmail": {}, + "unVerifiedEmail": "Непідтверджена електронна пошта", + "@unVerifiedEmail": {}, + "verifiedEmailReason": "Вам потрібно підтвердити свою електронну пошту, щоб виконувати вправи", + "@verifiedEmailReason": {}, + "alternativeNames": "Альтернативні назви", + "@alternativeNames": {}, + "oneNamePerLine": "Одне ім'я на рядок", + "@oneNamePerLine": {}, + "whatVariationsExist": "Які варіації цієї вправи існують, якщо такі є?", + "@whatVariationsExist": {}, + "previous": "Попередній", + "@previous": {}, + "next": "Наступний", + "@next": {}, + "images": "Зображення", + "@images": {}, + "language": "Мова", + "@language": {}, + "contributeExercise": "Внести вправу", + "@contributeExercise": {}, + "translation": "Переклад", + "@translation": {}, + "cardio": "Кардіо", + "@cardio": {}, + "contributeExerciseWarning": "Ви можете брати участь у вправах, лише якщо ваш обліковий запис старший за {days} днів і підтвердив вашу електронну пошту", + "@contributeExerciseWarning": { + "description": "Number of days before which a person can add exercise", + "placeholders": { + "days": { + "type": "String", + "example": "14" + } + } } } diff --git a/lib/main.dart b/lib/main.dart index a56e1aaf..56109959 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,15 +19,20 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:provider/provider.dart'; +import 'package:wger/providers/add_exercise.dart'; import 'package:wger/providers/base_provider.dart'; import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/gallery.dart'; import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/nutrition.dart'; +import 'package:wger/providers/user.dart'; import 'package:wger/providers/workout_plans.dart'; +import 'package:wger/screens/add_exercise_screen.dart'; import 'package:wger/screens/auth_screen.dart'; import 'package:wger/screens/dashboard.dart'; +import 'package:wger/screens/exercise_screen.dart'; +import 'package:wger/screens/exercises_screen.dart'; import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/gallery_screen.dart'; import 'package:wger/screens/gym_mode.dart'; @@ -38,11 +43,11 @@ import 'package:wger/screens/nutritional_diary_screen.dart'; import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/screens/nutritional_plans_screen.dart'; import 'package:wger/screens/splash_screen.dart'; -import 'package:wger/screens/update_app_screen.dart'; import 'package:wger/screens/weight_screen.dart'; import 'package:wger/screens/workout_plan_screen.dart'; import 'package:wger/screens/workout_plans_screen.dart'; import 'package:wger/theme/theme.dart'; +import 'package:wger/widgets/core/about.dart'; import 'providers/auth.dart'; @@ -64,8 +69,10 @@ class MyApp extends StatelessWidget { create: (ctx) => AuthProvider(), ), ChangeNotifierProxyProvider( - create: (context) => ExercisesProvider(context.read(), []), - update: (context, auth, previous) => previous ?? ExercisesProvider(auth, []), + create: (context) => ExercisesProvider( + WgerBaseProvider(context.read())), + update: (context, base, previous) => + previous ?? ExercisesProvider(WgerBaseProvider(base)), ), ChangeNotifierProxyProvider2( create: (context) => WorkoutPlansProvider( @@ -91,27 +98,34 @@ class MyApp extends StatelessWidget { update: (context, auth, previous) => previous ?? MeasurementProvider(WgerBaseProvider(auth)), ), + ChangeNotifierProxyProvider( + create: (context) => UserProvider( + WgerBaseProvider(Provider.of(context, listen: false)), + ), + update: (context, base, previous) => previous ?? UserProvider(WgerBaseProvider(base)), + ), ChangeNotifierProxyProvider( - create: (context) => BodyWeightProvider(context.read(), []), - update: (context, auth, previous) => previous ?? BodyWeightProvider(auth, []), + create: (context) => BodyWeightProvider(WgerBaseProvider(context.read())), + update: (context, base, previous) => previous ?? BodyWeightProvider(WgerBaseProvider(base)), ), ChangeNotifierProxyProvider( create: (context) => GalleryProvider(context.read(), []), update: (context, auth, previous) => previous ?? GalleryProvider(auth, []), ), + ChangeNotifierProxyProvider( + create: (context) => AddExerciseProvider( + WgerBaseProvider(Provider.of(context, listen: false)), + ), + update: (context, base, previous) => + previous ?? AddExerciseProvider(WgerBaseProvider(base)), + ) ], child: Consumer( builder: (ctx, auth, _) => MaterialApp( title: 'wger', theme: wgerTheme, home: auth.isAuth - ? FutureBuilder( - future: auth.applicationUpdateRequired(), - builder: (ctx, snapshot) => - snapshot.connectionState == ConnectionState.done && snapshot.data == true - ? UpdateAppScreen() - : HomeTabsScreen(), - ) + ? HomeTabsScreen() : FutureBuilder( future: auth.tryAutoLogin(), builder: (ctx, authResultSnapshot) => @@ -133,10 +147,21 @@ class MyApp extends StatelessWidget { WeightScreen.routeName: (ctx) => WeightScreen(), WorkoutPlanScreen.routeName: (ctx) => WorkoutPlanScreen(), WorkoutPlansScreen.routeName: (ctx) => WorkoutPlansScreen(), + ExercisesScreen.routeName: (ctx) => const ExercisesScreen(), + ExerciseDetailScreen.routeName: (ctx) => const ExerciseDetailScreen(), + AddExerciseScreen.routeName: (ctx) => const AddExerciseScreen(), + AboutPage.routeName: (ctx) => const AboutPage(), }, localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, - debugShowCheckedModeBanner: false, + + // Workaround for https://github.com/flutter/flutter/issues/100857 + localeResolutionCallback: (deviceLocale, supportedLocales) { + if (supportedLocales.contains(deviceLocale)) { + return deviceLocale; + } + return const Locale('en'); + }, ), ), ); diff --git a/lib/models/exercises/alias.dart b/lib/models/exercises/alias.dart new file mode 100644 index 00000000..842eb9f9 --- /dev/null +++ b/lib/models/exercises/alias.dart @@ -0,0 +1,43 @@ +/* + * 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. + * + * This program 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:json_annotation/json_annotation.dart'; + +part 'alias.g.dart'; + +@JsonSerializable() +class Alias { + @JsonKey(required: true) + final int? id; + + @JsonKey(required: true, name: 'exercise') + final int exerciseId; + + @JsonKey(required: true) + final String alias; + + Alias({ + this.id, + required this.exerciseId, + required this.alias, + }); + + // Boilerplate + factory Alias.fromJson(Map json) => _$AliasFromJson(json); + Map toJson() => _$AliasToJson(this); +} diff --git a/lib/models/exercises/alias.g.dart b/lib/models/exercises/alias.g.dart new file mode 100644 index 00000000..86eae28e --- /dev/null +++ b/lib/models/exercises/alias.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'alias.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Alias _$AliasFromJson(Map json) { + $checkKeys( + json, + requiredKeys: const ['id', 'exercise', 'alias'], + ); + return Alias( + id: json['id'] as int?, + exerciseId: json['exercise'] as int, + alias: json['alias'] as String, + ); +} + +Map _$AliasToJson(Alias instance) => { + 'id': instance.id, + 'exercise': instance.exerciseId, + 'alias': instance.alias, + }; diff --git a/lib/models/exercises/base.dart b/lib/models/exercises/base.dart new file mode 100644 index 00000000..14d7e3a2 --- /dev/null +++ b/lib/models/exercises/base.dart @@ -0,0 +1,176 @@ +/* + * 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. + * + * This program 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:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:wger/helpers/consts.dart'; +import 'package:wger/models/exercises/category.dart'; +import 'package:wger/models/exercises/equipment.dart'; +import 'package:wger/models/exercises/image.dart'; +import 'package:wger/models/exercises/muscle.dart'; +import 'package:wger/models/exercises/translation.dart'; +import 'package:wger/models/exercises/video.dart'; + +part 'base.g.dart'; + +@JsonSerializable(explicitToJson: true) +class ExerciseBase extends Equatable { + @JsonKey(required: true) + final int? id; + + @JsonKey(required: true) + final String? uuid; + + @JsonKey(required: true, name: 'variations') + final int? variationId; + + @JsonKey(required: true, name: 'creation_date') + final DateTime? creationDate; + + @JsonKey(required: true, name: 'update_date') + final DateTime? updateDate; + + @JsonKey(required: true, name: 'category') + late int categoryId; + + @JsonKey(includeFromJson: false, includeToJson: false) + late final ExerciseCategory category; + + @JsonKey(required: true, name: 'muscles') + List musclesIds = []; + + @JsonKey(includeFromJson: false, includeToJson: false) + List muscles = []; + + @JsonKey(required: true, name: 'muscles_secondary') + List musclesSecondaryIds = []; + + @JsonKey(includeFromJson: false, includeToJson: false) + List musclesSecondary = []; + + @JsonKey(required: true, name: 'equipment') + List equipmentIds = []; + + @JsonKey(includeFromJson: false, includeToJson: false) + List equipment = []; + + @JsonKey(includeFromJson: false, includeToJson: false) + List images = []; + + @JsonKey(includeFromJson: false, includeToJson: false) + List translations = []; + + @JsonKey(includeFromJson: false, includeToJson: false) + List