mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Merge branch 'master' into adyhnat_master
# Conflicts: # .gitignore # pubspec.lock
This commit is contained in:
3
.github/workflows/android-release.yml
vendored
3
.github/workflows/android-release.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
- name: Decrypt config files
|
||||
run: |
|
||||
cd ./fastlane/android/envfiles
|
||||
cd ./fastlane/metadata/envfiles
|
||||
chmod +x ./decrypt_secrets.sh
|
||||
./decrypt_secrets.sh
|
||||
env:
|
||||
@@ -81,7 +81,6 @@ jobs:
|
||||
uses: maierj/fastlane-action@v2.1.0
|
||||
with:
|
||||
lane: production
|
||||
subdirectory: android
|
||||
|
||||
- name: Make Github release
|
||||
uses: softprops/action-gh-release@v1
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -43,8 +43,7 @@ app.*.map.json
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||
/fastlane/metadata/android/envfiles/playstore.json
|
||||
/fastlane/metadata/android/envfiles/wger.properties
|
||||
/fastlane/metadata/android/envfiles/keys.jks
|
||||
/fastlane/metadata/android/envfiles/key.properties
|
||||
/coverage/lcov.info
|
||||
/fastlane/metadata/envfiles/playstore.json
|
||||
/fastlane/metadata/envfiles/wger.properties
|
||||
/fastlane/metadata/envfiles/keys.jks
|
||||
/fastlane/metadata/envfiles/key.properties
|
||||
|
||||
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,25 +1,11 @@
|
||||
🚀 Features:
|
||||
* Allow users to give meals a description #89
|
||||
* Allow users to delete workout log entries #97
|
||||
* Allow users to log individual ingredients/products #114
|
||||
* New loading animation during first run #99
|
||||
* Added reference from log to meal #105
|
||||
* ...
|
||||
|
||||
|
||||
🐛 Bug Fixes:
|
||||
* Improve usability for workout logs #91
|
||||
* Preselect correct time in session form #93
|
||||
* Fixed infinite loader bug during auth #96
|
||||
* Fix error not showing up in auth screen #102
|
||||
* Fix for chart legend bug #112
|
||||
* Fix for RiR slider #113
|
||||
* ...
|
||||
|
||||
|
||||
🧰 Maintenance:
|
||||
* Better linting #87 #98
|
||||
* Improve automatic build system for publication on play store
|
||||
* Notify the user when saving entries in gym mode #92
|
||||
* Consistenly display nutritional values #94
|
||||
* Add minimum required server version #29
|
||||
* Make order field of sets required #109
|
||||
* ...
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
🚀 Features:
|
||||
*
|
||||
* ...
|
||||
|
||||
|
||||
🐛 Bug Fixes:
|
||||
*
|
||||
* ...
|
||||
|
||||
|
||||
🧰 Maintenance:
|
||||
*
|
||||
* ...
|
||||
15
README.md
15
README.md
@@ -7,19 +7,21 @@ app written with Flutter, it talks via REST with the main server.
|
||||
If you want to contribute, hop on the Discord server and say hi!
|
||||
|
||||
|
||||
<p float="left">
|
||||
<img src="https://github.com/wger-project/flutter/blob/master/android/fastlane/metadata/android/en-US/images/phoneScreenshots/01%20-%20workout%20plan.png?raw=true" width="200" />
|
||||
<p>
|
||||
<img src="https://raw.githubusercontent.com/wger-project/flutter/master/fastlane/metadata/android/en-US/images/phoneScreenshots/01%20-%20workout%20plan.png" width="200" />
|
||||
|
||||
<img src="https://github.com/wger-project/flutter/blob/master/android/fastlane/metadata/android/en-US/images/phoneScreenshots/02%20-%20workout%20log.png?raw=true" width="200" />
|
||||
<img src="https://raw.githubusercontent.com/wger-project/flutter/master/fastlane/metadata/android/en-US/images/phoneScreenshots/02%20-%20workout%20log.png" width="200" />
|
||||
|
||||
<img src="https://github.com/wger-project/flutter/blob/master/android/fastlane/metadata/android/en-US/images/phoneScreenshots/04%20-%20nutritional%20plan.png?raw=true" width="200" />
|
||||
<img src="https://raw.githubusercontent.com/wger-project/flutter/master/fastlane/metadata/android/en-US/images/phoneScreenshots/04%20-%20nutritional%20plan.png" width="200" />
|
||||
</p>
|
||||
|
||||
## Installation
|
||||
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png"
|
||||
alt="Get it on Google Play"
|
||||
height="80">](https://play.google.com/store/apps/details?id=de.wger.flutter)
|
||||
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
alt="Get it on F-Droid"
|
||||
height="80">](https://f-droid.org/packages/de.wger.flutter/)
|
||||
|
||||
## Development
|
||||
|
||||
@@ -50,6 +52,9 @@ on your local instance and then run ``python3 manage.py add-user-rest theusernam
|
||||
|
||||
You can later list all the registered users with: ``python3 manage.py list-users-api``
|
||||
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
alt="Get it on F-Droid"
|
||||
height="80">](https://f-droid.org/packages/de.wger.flutter)
|
||||
|
||||
### 4
|
||||
Start the application with ``flutter run`` or use your IDE
|
||||
|
||||
@@ -27,14 +27,14 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
// Keys for the android play store
|
||||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('../fastlane/metadata/android/envfiles/key.properties')
|
||||
def keystorePropertiesFile = rootProject.file('../fastlane/metadata/envfiles/key.properties')
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
// Key for wger.de REST API
|
||||
def wgerProperties = new Properties()
|
||||
def localMapsPropertiesFile = rootProject.file('../fastlane/metadata/android/envfiles/wger.properties')
|
||||
def localMapsPropertiesFile = rootProject.file('../fastlane/metadata/envfiles/wger.properties')
|
||||
if (localMapsPropertiesFile.exists()) {
|
||||
project.logger.info('Load maps properties from local file')
|
||||
localMapsPropertiesFile.withReader('UTF-8') { reader ->
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
|
||||
BIN
assets/images/barcode_scanner_icon.png
Normal file
BIN
assets/images/barcode_scanner_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
@@ -29,6 +29,7 @@ platform :android do
|
||||
lane :test_configuration do
|
||||
begin
|
||||
upload_to_play_store(
|
||||
json_key: 'fastlane/metadata/envfiles/playstore.json',
|
||||
track: 'production',
|
||||
validate_only: true,
|
||||
aab: './build/app/outputs/bundle/release/app-release.aab',
|
||||
@@ -41,6 +42,7 @@ platform :android do
|
||||
lane :production do
|
||||
begin
|
||||
upload_to_play_store(
|
||||
json_key: 'fastlane/metadata/envfiles/playstore.json',
|
||||
track: 'production',
|
||||
aab: './build/app/outputs/bundle/release/app-release.aab',
|
||||
skip_upload_metadata: false,
|
||||
@@ -56,6 +58,7 @@ platform :android do
|
||||
lane :update_alpha do
|
||||
begin
|
||||
upload_to_play_store(
|
||||
json_key: 'fastlane/metadata/envfiles/playstore.json',
|
||||
track: 'alpha',
|
||||
aab: './build/app/outputs/bundle/release/app-release.aab',
|
||||
skip_upload_metadata: true,
|
||||
|
||||
@@ -1,47 +1,59 @@
|
||||
fastlane documentation
|
||||
================
|
||||
----
|
||||
|
||||
# Installation
|
||||
|
||||
Make sure you have the latest version of the Xcode command line tools installed:
|
||||
|
||||
```
|
||||
```sh
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
Install _fastlane_ using
|
||||
```
|
||||
[sudo] gem install fastlane -NV
|
||||
```
|
||||
or alternatively using `brew install fastlane`
|
||||
For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane)
|
||||
|
||||
# Available Actions
|
||||
|
||||
### playstore
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane playstore
|
||||
```
|
||||
fastlane playstore
|
||||
```
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
## Android
|
||||
|
||||
### android test_configuration
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android test_configuration
|
||||
```
|
||||
fastlane android test_configuration
|
||||
```
|
||||
Check configuration
|
||||
|
||||
Check playstore configuration
|
||||
|
||||
### android production
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android production
|
||||
```
|
||||
fastlane android production
|
||||
```
|
||||
|
||||
Upload app to production
|
||||
|
||||
### android update_alpha
|
||||
|
||||
```sh
|
||||
[bundle exec] fastlane android update_alpha
|
||||
```
|
||||
fastlane android update_alpha
|
||||
```
|
||||
|
||||
Upload closed alpha app and update store entry
|
||||
|
||||
----
|
||||
|
||||
This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run.
|
||||
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
|
||||
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
|
||||
More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools).
|
||||
|
||||
The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
|
||||
|
||||
1
fastlane/metadata/android/ca/short_description.txt
Normal file
1
fastlane/metadata/android/ca/short_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
Registre de la forma física, entrenament, nutrició i pes corporal
|
||||
Binary file not shown.
@@ -1,39 +1,39 @@
|
||||
From fitness lovers to fitness lovers – get your health organized with WGER, your Workout Manager!
|
||||
Por amantes del fitness para amantes del fitness – ¡Organiza tu salud con WGER, tu gestor de entrenamientos!
|
||||
|
||||
Have you already found your #1 fitness app and do you love to create your own sports routines? No matter what type of sporty beast you are – we all have something in common: We love to keep track of our health data <3
|
||||
¿Has encontrado ya tu app de fitnes nº1 y te encanta crear tus propias rutinas deportivas? No importa qué clase de bestia deportista eres – todos tenemos algo en común: amamos hacer el seguimiento de los datos de nuestra salud <3
|
||||
|
||||
So we don’t judge you for still managing your fitness journey with your handy little workout log book but welcome to 2021!
|
||||
Así que no vamos a juzgarte si aún gestionas tu andadura en el fitness con tu pequeño y práctico diario de entrenamientos, ¡pero te damos la bienvenida a 2022!
|
||||
|
||||
We have developed a 100% free digital health and fitness tracker app for you, sized down to the most relevant features to make your life easier. Get started, keep training and celebrate your progress!
|
||||
Hemos desarrollado una app de seguimiento digital de la salud y el fitness 100% libre, reducida a las funcionalidades más relevantes para hacerte la vida más fácil. ¡Empieza ya, no pares tomar datos y celebra tus progresos!
|
||||
|
||||
wger is an Open Source project and all about:
|
||||
* Your Body
|
||||
* Your Workouts
|
||||
* Your Progress
|
||||
* Your Data
|
||||
wger es un proyecto de código abierto centrado en:
|
||||
* Tu Cuerpo
|
||||
* Tus Entrenamientos
|
||||
* Tus Progresos
|
||||
* Tus Datos
|
||||
|
||||
Your Body:
|
||||
No need to google for the ingredients of your favourite treats – choose your daily meals from more than 78000 products and see the nutritional values. Add meals to the nutritional plan and keep an overview of your diet in the calendar.
|
||||
Tu Cuerpo:
|
||||
No hace falta buscar en Google los ingredientes de tus caprichos favoritos – elige tus comidas diarias entre más de 78000 productos para ver sus valores nutricionales. Añade comidas a tu plan nutricional y ten una vista general de tu dieta en el calendario.
|
||||
|
||||
Your Workouts:
|
||||
You know what is best for your body. Create your own workouts out of a growing variety from 200 different exercises. Then, use the Gym Mode to guide you through the training while you log your weights with one tap.
|
||||
Tus Entrenamientos:
|
||||
Sabes qué es lo mejor para tu cuerpo. Crea tus propios entrenamientos entre una gama creciente de 200 ejercicios diferentes. Después, usa el Modo Gimnasio para que te guíe a través del entrenamiento mientras registras tu peso con un toque de dedo.
|
||||
|
||||
Your Progress:
|
||||
Never lose sight of your goals. Track your weight and keep your statistics.
|
||||
Tus Progresos:
|
||||
Nunca pierdas de vista tus objetivos. Lleva la cuenta de tu peso y mantén tus estadísticas.
|
||||
|
||||
Your Data:
|
||||
wger is your personalized fitness diary – but you own your data. Use the REST API to access and do amazing things with it.
|
||||
Tus Datos:
|
||||
wger es tu diario de fitness personalizado – pero tus datos te pertenecen a ti. Usa la API REST para acceder y hacer cosas increíbles con ella.
|
||||
|
||||
Please note: This free app is not based on additional fundings and we don’t ask you to donate money. More than that it is a community project which is growing constantly. So be prepared for new features anytime!
|
||||
Por favor, ten en cuenta: esta app no se basa en financiación adicional y no te pedimos que dones dinero. Más que eso, es un proyecto comunitario que no para de crecer. ¡Así que estate preparado para nuevas funcionalidades en cualquier momento!
|
||||
|
||||
#OpenSource – what does that mean?
|
||||
#OpenSource – ¿qué significa?
|
||||
|
||||
Open Source means that the whole source code for this app and the server it talks to is free and available to anybody:
|
||||
* Do you want to run wger on your own server for you or your local gym? Go ahead!
|
||||
* Do you miss a feature and want to implement it? Start now!
|
||||
* Do you want to check that nothing is being sent anywhere? You can!
|
||||
Open Source (o código abierto) significa que la totalidad del código fuente para esta app y el servidor con el que habla es libre y está disponible para cualquiera:
|
||||
* ¿Quieres usar wger en tu propio servidor para tu propio ginmasio local? ¡Adelante!
|
||||
* ¿Echas de menos una funcionalidad y quieres implementarla? ¡Empieza ya!
|
||||
* ¿Quieres asegurarte de que nada se envía a ningún sitio? ¡Puedes!
|
||||
|
||||
Join our community and become a part of sport enthusiasts and IT geeks from all over the world. We keep working on adjusting and optimizing the app customized to our needs. We love your input so feel free to jump in anytime and contribute your wishes and ideas!
|
||||
Entra en nuestra comunidad y únete a entusiastas de los deportes y genios de la informática de todo el mundo. No paramos de trabajar en afinar y optimizar la app adaptada a nuestras necesidades. Nos encantará tu aporte, así que no dudes en meterte en cualquier momento y contribuir con tus deseos e ideas!
|
||||
|
||||
-> find the source code on https://github.com/wger-project
|
||||
-> ask your questions or just say hello on our discord Server https://discord.gg/rPWFv6W
|
||||
-> encuentra el código fuente en https://github.com/wger-project
|
||||
-> haz tus preguntas o simplemente di hola en nuestro servidor de Discord https://discord.gg/rPWFv6W
|
||||
|
||||
@@ -1 +1 @@
|
||||
wger Workout Manager
|
||||
wger Workout Manager
|
||||
|
||||
39
fastlane/metadata/android/hi-IN/full_description.txt
Normal file
39
fastlane/metadata/android/hi-IN/full_description.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
अपना स्वास्थ का ख्याल रखिये WGER, आपका वर्कआउट मैनेजर के साथ!
|
||||
|
||||
क्या आपने अपना #1 फिटनेस आप चुना है और क्या आप अपना खुद स्पोर्ट रूटीन बनाते है? चाहे आपका स्वास्थ किसी भी प्रकार का हो: हम सब अपना हेल्थ डाटा को ट्रैक करना चाहते है <3
|
||||
|
||||
हम आपको अपने फिटनेस जर्नी को एक छोटे लॉग पे दर्ज करने के लिए जज नहीं करते। इक्कीसवीं सदी में आपका स्वागत है!
|
||||
|
||||
हमने आपले लिए के 100% मुफ्त डिजिटल हेल्थ और फिटनेस ट्रैकर बनाया है, सबसे महत्वपूर्ण फीचर्स के साथ जिससे आपका जीवन बोहोत आसान बन जायेगा। तो चलिए, आगे बारे, ट्रैन करे, और अपने प्रोग्रेस का मज़े लीजिये!
|
||||
|
||||
wger एक ओपनसोर्स प्रोजेक्ट है और निम्मलिखित चीज़ो से सम्बन्धित है:
|
||||
* आपका शरीर
|
||||
* आपका वर्कऑउट्स
|
||||
* आपका प्रोग्रेस
|
||||
* आपका डाटा
|
||||
|
||||
आपका शरीर:
|
||||
आपको अपना मनपसंद खानो का अवयव गूगल में ढूंढ़ना नहीं पड़ेगा - अपना दैनिक भोजन 78000 से ज़्यादा प्रोडक्ट्स में से चून्हे और उनका न्यूट्रिशनल वैल्यूज देखे। नुट्रिशन प्लान में अपना भोजन दर्ज कीजिये और अपने कैलेंडर में अपना डाइट को ट्रैक करे।
|
||||
|
||||
आपका वर्कऑउट्स:
|
||||
आपको पता है की आपके बॉडी के लिए सबसे अच्छा क्या है। अपना वर्कऑउट्स खुद बनाये। उसके बाद जिम मोड का इस्तेमाल करिये आपके ट्रेनिंग के लिए।
|
||||
|
||||
आपका प्रोग्रेस:
|
||||
कभी अपना गोल्स के बारे में न भूले। अपना वज़न और स्टेटिस्टिक्स को ट्रैक कीजिये।
|
||||
|
||||
आपका डाटा:
|
||||
wger आपका निजीकृत फ़िटनेस डायरी है - आप अपना डाटा के मालिक है। हमारा REST API का प्रयोग करके कुछ मज़ेदार काम करे।
|
||||
|
||||
क्रियण नोट कीजिये: यह मुफ्त आप कोई भी एडिशनल फ़ंडिंग्स पे नहीं चलता और हम आपको पैसा डोनेट करने के लिए नहीं पूछते। यह एक कम्युनिटी प्रोजेक्ट है को हर वक्त बढ़ रहा है। तो नए फीटर्स के लिए हमेशा तैयार रहे!
|
||||
|
||||
#ओपनसोर्स - इसका अर्थ क्या है?
|
||||
|
||||
ओपनसोर्स का अर्थ यह है की इस अप्प का पूरा सोर्स कोड और जिस सर्वर से यह बात करता है - सबके लिए मुफ्त और उपलब्ध है।
|
||||
* क्या आप wger को अपने लोकल सर्वर में या फिर अपने स्थानीय जिम के लिए प्रयोग करना चाहते है? आगे बढ़िए!
|
||||
* क्या आपको किसी फीचर का कमी नज़र आया है और आप उसको खुद इम्प्लीमेंट करना चाहते है? अभी शुरू कीजिये!
|
||||
* क्या आपको देखना है की कुछ भी कही भी नहीं भेजा जा रहा है? आप कर सकते है!
|
||||
|
||||
हमारा कम्युनिटी ज्वाइन करिये और संसार के अन्य स्पोर्ट्स एवं IT गीक्स के साथ जुड़े। हम इस अप्प को अपने खुद के लिए ऑप्टिमिसे और बदल ते रहते है। आपका इनपुट भी चाहिए तो कृपया हमारे कम्युनिटी ज्वाइन करिये और अपना विचार धरा हमें बोले।
|
||||
|
||||
-> सोर्स कोड यहाँ पाए : https://github.com/wger-project
|
||||
-> प्रश्न पूछे या फिर केवल नमस्ते बोले हमारे डिस्कॉर्ड सर्वर पे : https://discord.gg/rPWFv6W
|
||||
1
fastlane/metadata/android/hi-IN/short_description.txt
Normal file
1
fastlane/metadata/android/hi-IN/short_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
फिटनेस/वर्कआउट, नुट्रिशन और वज़न ट्रैकर
|
||||
1
fastlane/metadata/android/hi-IN/title.txt
Normal file
1
fastlane/metadata/android/hi-IN/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
wger Workout Manager
|
||||
39
fastlane/metadata/android/ru-RU/full_description.txt
Normal file
39
fastlane/metadata/android/ru-RU/full_description.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
От любителей фитнеса для любителей фитнеса - организуйте свое здоровье с WGER, вашим менеджером тренировок!
|
||||
|
||||
Вы уже нашли свое фитнес-приложение №1 и любите создавать свои собственные спортивные программы? Независимо от того, какой вы спортивный зверь - у всех нас есть нечто общее: мы любим отслеживать данные о своем здоровье <3
|
||||
|
||||
Поэтому мы не осуждаем вас за то, что вы все еще ведете свой фитнес-путь с помощью удобного маленького журнала тренировок, но добро пожаловать в 2021 год!
|
||||
|
||||
Мы разработали для вас на 100% свободное цифровое приложение для отслеживания состояния здоровья и фитнес-тренировок, сократив его до самых необходимых функций, чтобы облегчить вам жизнь. Начните, продолжайте тренироваться и отмечайте свой прогресс!
|
||||
|
||||
wger - это проект с открытым исходным кодом и все о:
|
||||
* Вашем теле
|
||||
* Ваших тренировках
|
||||
* Вашем прогрессе
|
||||
* Ваших данных
|
||||
|
||||
Вашем теле:
|
||||
Не нужно "гуглить" ингредиенты любимых лакомств - выбирайте ежедневные блюда из более чем 78000 продуктов и смотрите их пищевую ценность. Добавляйте блюда в план питания и следите за своим рационом в календаре.
|
||||
|
||||
Ваших тренировках:
|
||||
Вы знаете, что лучше всего подходит для вашего тела. Создавайте свои собственные тренировки из растущего разнообразия 200 различных упражнений. Затем используйте режим тренажерного зала, чтобы направлять вас во время тренировки, а также регистрируйте свои веса одним касанием.
|
||||
|
||||
Вашем прогрессе:
|
||||
Никогда не теряйте из виду свои цели. Отслеживайте свой вес и ведите статистику.
|
||||
|
||||
Ваших данных:
|
||||
wger - это ваш персональный фитнес-дневник - но ваши данные принадлежат вам. Используйте REST API для доступа к ним и делайте с ними удивительные вещи.
|
||||
|
||||
Обратите внимание: это свободное приложение не основано на дополнительном финансировании, и мы не просим вас жертвовать деньги. Более того, это проект сообщества, который постоянно растет. Так что будьте готовы к появлению новых функций в любое время!
|
||||
|
||||
#OpenSource #ОткрытыйИсходныйКод - что это значит?
|
||||
|
||||
Открытый исходный код означает, что весь исходный код этого приложения и сервера, с которым оно работает, свободен и доступен любому:
|
||||
* Вы хотите запустить wger на собственном сервере для себя или своего спортзала? Вперед!
|
||||
* Вам не хватает какой-то функции и вы хотите ее реализовать? Начните прямо сейчас!
|
||||
* Хотите проверить, что ничего никуда не отправляется? Вы можете!
|
||||
|
||||
Присоединяйтесь к нашему сообществу и станьте частью спортивных энтузиастов и IT-гиков со всего мира. Мы продолжаем работать над корректировкой и оптимизацией приложения в соответствии с нашими потребностями. Нам нравится ваш вклад, поэтому не стесняйтесь вступать в сообщество в любое время и высказывать свои пожелания и идеи!
|
||||
|
||||
-> найти исходный код на https://github.com/wger-project
|
||||
-> задавайте свои вопросы или просто поздоровайтесь на нашем discord-сервере https://discord.gg/rPWFv6W
|
||||
1
fastlane/metadata/android/ru-RU/short_description.txt
Normal file
1
fastlane/metadata/android/ru-RU/short_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
Трекер фитнеса/тренировок, питания и веса
|
||||
1
fastlane/metadata/android/ru-RU/title.txt
Normal file
1
fastlane/metadata/android/ru-RU/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
wger Workout Manager
|
||||
1
fastlane/metadata/android/tr-TR/title.txt
Normal file
1
fastlane/metadata/android/tr-TR/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
wger Workout Manager
|
||||
1
fastlane/metadata/android/zh-CN/title.txt
Normal file
1
fastlane/metadata/android/zh-CN/title.txt
Normal file
@@ -0,0 +1 @@
|
||||
wger Workout Manager
|
||||
BIN
fastlane/metadata/envfiles/key.properties.gpg
Normal file
BIN
fastlane/metadata/envfiles/key.properties.gpg
Normal file
Binary file not shown.
524
lib/l10n/app_ca.arb
Normal file
524
lib/l10n/app_ca.arb
Normal file
@@ -0,0 +1,524 @@
|
||||
{
|
||||
"login": "Entra",
|
||||
"@login": {
|
||||
"description": "Text for login button"
|
||||
},
|
||||
"logout": "Surt",
|
||||
"@logout": {
|
||||
"description": "Text for logout button"
|
||||
},
|
||||
"usernameValidChars": "Un nom d'usuari només pot contenir lletres, números i els caràcters @, +, ., -, i _",
|
||||
"@usernameValidChars": {
|
||||
"description": "Error message when the user tries to register a username with forbidden characters"
|
||||
},
|
||||
"passwordsDontMatch": "Les contrasenyes no coincideixen",
|
||||
"@passwordsDontMatch": {
|
||||
"description": "Error message when the user enters two different passwords during registration"
|
||||
},
|
||||
"passwordTooShort": "La contrasenya és massa curta",
|
||||
"@passwordTooShort": {
|
||||
"description": "Error message when the user a password that is too short"
|
||||
},
|
||||
"password": "Contrasenya",
|
||||
"@password": {},
|
||||
"confirmPassword": "Confirma la contrasenya",
|
||||
"@confirmPassword": {},
|
||||
"invalidEmail": "Introdueix una adreça electrònica vàlida",
|
||||
"@invalidEmail": {
|
||||
"description": "Error message when the user enters an invalid email"
|
||||
},
|
||||
"email": "Adreça electrònica",
|
||||
"@email": {},
|
||||
"username": "Nom d'usuari",
|
||||
"@username": {},
|
||||
"customServerUrl": "URL de la instància de wger",
|
||||
"@customServerUrl": {
|
||||
"description": "Label in the form where the users can enter their own wger instance"
|
||||
},
|
||||
"reset": "Reinicialitza",
|
||||
"@reset": {
|
||||
"description": "Button text allowing the user to reset the entered values to the default"
|
||||
},
|
||||
"registerInstead": "Registra't",
|
||||
"@registerInstead": {},
|
||||
"labelBottomNavWorkout": "Entrenament",
|
||||
"@labelBottomNavWorkout": {
|
||||
"description": "Label used in bottom navigation, use a short word"
|
||||
},
|
||||
"labelWorkoutLogs": "Registes d'entrenament",
|
||||
"@labelWorkoutLogs": {
|
||||
"description": "(Workout) logs"
|
||||
},
|
||||
"labelWorkoutPlan": "Pla d'entrenament",
|
||||
"@labelWorkoutPlan": {
|
||||
"description": "Title for screen workout plan"
|
||||
},
|
||||
"labelDashboard": "Consola",
|
||||
"@labelDashboard": {
|
||||
"description": "Title for screen dashboard"
|
||||
},
|
||||
"successfullyDeleted": "Esborrat",
|
||||
"@successfullyDeleted": {
|
||||
"description": "Message when an item was successfully deleted"
|
||||
},
|
||||
"successfullySaved": "Desat",
|
||||
"@successfullySaved": {
|
||||
"description": "Message when an item was successfully saved"
|
||||
},
|
||||
"exercise": "Exercici",
|
||||
"@exercise": {
|
||||
"description": "An exercise for a workout"
|
||||
},
|
||||
"searchExercise": "Cerca exercici a afegir",
|
||||
"@searchExercise": {
|
||||
"description": "Label on set form. Selected exercises are added to the set"
|
||||
},
|
||||
"supersetWith": "en conjunt amb",
|
||||
"@supersetWith": {
|
||||
"description": "Text used between exercise cards when adding a new set. Translate as something like 'in a superset with'"
|
||||
},
|
||||
"equipment": "Equipament",
|
||||
"@equipment": {
|
||||
"description": "Equipment needed to perform an exercise"
|
||||
},
|
||||
"muscles": "Músculs",
|
||||
"@muscles": {
|
||||
"description": "(main) muscles trained by an exercise"
|
||||
},
|
||||
"musclesSecondary": "Músculs secundaris",
|
||||
"@musclesSecondary": {
|
||||
"description": "secondary muscles trained by an exercise"
|
||||
},
|
||||
"category": "Categoria",
|
||||
"@category": {
|
||||
"description": "Category for an exercise, ingredient, etc."
|
||||
},
|
||||
"newWorkout": "Nou pla d'entrenament",
|
||||
"@newWorkout": {
|
||||
"description": "Header when adding a new workout"
|
||||
},
|
||||
"noWorkoutPlans": "No tens cap pla d'entrenament",
|
||||
"@noWorkoutPlans": {
|
||||
"description": "Message shown when the user has no workout plans"
|
||||
},
|
||||
"repetitions": "Repeticions",
|
||||
"@repetitions": {
|
||||
"description": "Repetitions for an exercise set"
|
||||
},
|
||||
"reps": "Reps",
|
||||
"@reps": {
|
||||
"description": "Shorthand for repetitions, used when space constraints are tighter"
|
||||
},
|
||||
"rir": "RER",
|
||||
"@rir": {
|
||||
"description": "Shorthand for Repetitions In Reserve"
|
||||
},
|
||||
"rirNotUsed": "Valor RER no usat",
|
||||
"@rirNotUsed": {
|
||||
"description": "Label used in RiR slider when the RiR value is not used/saved for the current setting or log"
|
||||
},
|
||||
"repetitionUnit": "Unitat de repetició",
|
||||
"@repetitionUnit": {},
|
||||
"set": "Sèrie",
|
||||
"@set": {
|
||||
"description": "A set in a workout plan"
|
||||
},
|
||||
"sameRepetitions": "Si fas les mateixes repeticions i pesos per a totes les sèries, pots omplir només una línia. Per exemple, per a 4 sèries simplement introdueix 10 per a les repeticions; això esdevé automàticament «4 x 10».",
|
||||
"@sameRepetitions": {},
|
||||
"comment": "Comentaris",
|
||||
"@comment": {
|
||||
"description": "Comment, additional information"
|
||||
},
|
||||
"impression": "Impressió",
|
||||
"@impression": {
|
||||
"description": "General impression (e.g. for a workout session) such as good, bad, etc."
|
||||
},
|
||||
"notes": "Notes",
|
||||
"@notes": {
|
||||
"description": "Personal notes, e.g. for a workout session"
|
||||
},
|
||||
"workoutSession": "Sessió d'entrenament",
|
||||
"@workoutSession": {
|
||||
"description": "A (logged) workout session"
|
||||
},
|
||||
"newDay": "Nou dia",
|
||||
"@newDay": {},
|
||||
"newSet": "Nova sèrie",
|
||||
"@newSet": {
|
||||
"description": "Header when adding a new set to a workout day"
|
||||
},
|
||||
"selectExercises": "Si vols fer una supersèrie, pots cercar diversos exercicis: s'agruparan junts",
|
||||
"@selectExercises": {},
|
||||
"plateCalculator": "Plaques",
|
||||
"@plateCalculator": {
|
||||
"description": "Label used for the plate calculator in the gym mode"
|
||||
},
|
||||
"plateCalculatorNotDivisible": "No es pot assolir aquest pes amb les plaques disponibles",
|
||||
"@plateCalculatorNotDivisible": {
|
||||
"description": "Error message when the current weight is not reachable with plates (e.g. 33.1 kg)"
|
||||
},
|
||||
"pause": "Pausa",
|
||||
"@pause": {
|
||||
"description": "Noun, not an imperative! Label used for the pause when using the gym mode"
|
||||
},
|
||||
"jumpTo": "Vés a",
|
||||
"@jumpTo": {
|
||||
"description": "Imperative. Label used in popup allowing the user to jump to a specific exercise while in the gym mode"
|
||||
},
|
||||
"todaysWorkout": "El teu entrenament avui",
|
||||
"@todaysWorkout": {},
|
||||
"logHelpEntriesUnits": "Tingues en compte que només es fa la gràfica de les entrades amb unitats de pes (kg o lb) i repeticions, altres combinacions com ara temps o fins la fallada s'ignoren aquí.",
|
||||
"@logHelpEntriesUnits": {},
|
||||
"description": "Descripció",
|
||||
"@description": {},
|
||||
"name": "Nom",
|
||||
"@name": {
|
||||
"description": "Name for a workout or nutritional plan"
|
||||
},
|
||||
"save": "Desa",
|
||||
"@save": {},
|
||||
"addSet": "Afegeix sèrie",
|
||||
"@addSet": {
|
||||
"description": "Label for the button that adds a set (to a workout day)"
|
||||
},
|
||||
"addMeal": "Afegeix àpat",
|
||||
"@addMeal": {},
|
||||
"mealLogged": "Àpat registrat al diari",
|
||||
"@mealLogged": {},
|
||||
"addIngredient": "Afegeix ingredient",
|
||||
"@addIngredient": {},
|
||||
"logIngredient": "Desa al diari nutricional",
|
||||
"@logIngredient": {},
|
||||
"nutritionalPlan": "Pla nutricional",
|
||||
"@nutritionalPlan": {},
|
||||
"nutritionalDiary": "Diari nutricional",
|
||||
"@nutritionalDiary": {},
|
||||
"anErrorOccurred": "S'ha produït un error!",
|
||||
"@anErrorOccurred": {},
|
||||
"weight": "Pes",
|
||||
"@weight": {
|
||||
"description": "The weight of a workout log or body weight entry"
|
||||
},
|
||||
"measurement": "Mesura",
|
||||
"@measurement": {},
|
||||
"measurementEntriesHelpText": "La unitat usada per a mesurar la categoria, com ara «cm» o «%»",
|
||||
"@measurementEntriesHelpText": {},
|
||||
"start": "Comença",
|
||||
"@start": {
|
||||
"description": "Label on button to start the gym mode (i.e., an imperative)"
|
||||
},
|
||||
"time": "Temps",
|
||||
"@time": {
|
||||
"description": "The time of a meal or workout"
|
||||
},
|
||||
"timeStart": "Hora d'inici",
|
||||
"@timeStart": {
|
||||
"description": "The starting time of a workout"
|
||||
},
|
||||
"timeEnd": "Hora de finalització",
|
||||
"@timeEnd": {
|
||||
"description": "The end time of a workout"
|
||||
},
|
||||
"ingredient": "Ingredient",
|
||||
"@ingredient": {},
|
||||
"energy": "Energia",
|
||||
"@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"
|
||||
},
|
||||
"macronutrients": "Macronutrients",
|
||||
"@macronutrients": {},
|
||||
"logged": "Registrat",
|
||||
"@logged": {
|
||||
"description": "Header for the column of 'logged' nutritional values, i.e. what was eaten"
|
||||
},
|
||||
"percentEnergy": "Percentatge d'energia",
|
||||
"@percentEnergy": {},
|
||||
"gPerBodyKg": "g per kg de pes corporal",
|
||||
"@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": "Proteïna",
|
||||
"@protein": {},
|
||||
"carbohydrates": "Carbohidrats",
|
||||
"@carbohydrates": {},
|
||||
"carbohydratesShort": "C",
|
||||
"@carbohydratesShort": {
|
||||
"description": "The first letter or short name of the word 'Carbohydrates', used in overviews"
|
||||
},
|
||||
"sugars": "Sucres",
|
||||
"@sugars": {},
|
||||
"fat": "Greix",
|
||||
"@fat": {},
|
||||
"amount": "Quantitat",
|
||||
"@amount": {
|
||||
"description": "The amount (e.g. in grams) of an ingredient in a meal"
|
||||
},
|
||||
"unit": "Unitat",
|
||||
"@unit": {
|
||||
"description": "The unit used for a repetition (kg, time, etc.)"
|
||||
},
|
||||
"newEntry": "Nova entrada",
|
||||
"@newEntry": {
|
||||
"description": "Title when adding a new entry such as a weight or log entry"
|
||||
},
|
||||
"edit": "Edita",
|
||||
"@edit": {},
|
||||
"loadingText": "Carregant...",
|
||||
"@loadingText": {
|
||||
"description": "Text to show when entries are being loaded in the background: Loading..."
|
||||
},
|
||||
"newNutritionalPlan": "Nou pla nutricional",
|
||||
"@newNutritionalPlan": {},
|
||||
"toggleDetails": "Commuta detalls",
|
||||
"@toggleDetails": {
|
||||
"description": "Switch to toggle detail / overview"
|
||||
},
|
||||
"goToDetailPage": "Vés a la pàgina dels detalls",
|
||||
"@goToDetailPage": {},
|
||||
"aboutSourceTitle": "Codi font",
|
||||
"@aboutSourceTitle": {
|
||||
"description": "Title for source code section in the about dialog"
|
||||
},
|
||||
"aboutBugsTitle": "Teniu cap problema o idea?",
|
||||
"@aboutBugsTitle": {
|
||||
"description": "Title for bugs section in the about dialog"
|
||||
},
|
||||
"aboutBugsText": "Poseu-vos en contacte si alguna cosa no funciona com s'esperava o si hi ha alguna funció que penseu que manca.",
|
||||
"@aboutBugsText": {
|
||||
"description": "Text for bugs section in the about dialog"
|
||||
},
|
||||
"aboutContactUsTitle": "Saludeu!",
|
||||
"@aboutContactUsTitle": {
|
||||
"description": "Title for contact us section in the about dialog"
|
||||
},
|
||||
"aboutContactUsText": "Si voleu xatejar amb nosaltres, entreu al servidor de Discord i poseu-vos en contacte",
|
||||
"@aboutContactUsText": {
|
||||
"description": "Text for contact us section in the about dialog"
|
||||
},
|
||||
"aboutTranslationTitle": "Traducció",
|
||||
"@aboutTranslationTitle": {
|
||||
"description": "Title for translation section in the about dialog"
|
||||
},
|
||||
"aboutTranslationText": "Aquesta aplicació es tradueix a weblate. Si voleu ajudar-hi també, feu clic al vincle i comenceu a traduir",
|
||||
"@aboutTranslationText": {
|
||||
"description": "Text for translation section in the about dialog"
|
||||
},
|
||||
"calendar": "Calendari",
|
||||
"@calendar": {},
|
||||
"enterValue": "Introduïu un valor",
|
||||
"@enterValue": {
|
||||
"description": "Error message when the user hasn't entered a value on a required field"
|
||||
},
|
||||
"nrOfSets": "Sèries per exercici: {nrOfSets}",
|
||||
"@nrOfSets": {
|
||||
"description": "Label shown on the slider where the user selects the nr of sets",
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"nrOfSets": {}
|
||||
}
|
||||
},
|
||||
"setUnitsAndRir": "Unitats de la sèrie i RER",
|
||||
"@setUnitsAndRir": {
|
||||
"description": "Label shown on the slider where the user can toggle showing units and RiR",
|
||||
"type": "text"
|
||||
},
|
||||
"enterValidNumber": "Introduïu un número vàlid",
|
||||
"@enterValidNumber": {
|
||||
"description": "Error message when the user has submitted an invalid number (e.g. '3,.,.,.')"
|
||||
},
|
||||
"selectIngredient": "Seleccioneu un ingredient",
|
||||
"@selectIngredient": {
|
||||
"description": "Error message when the user hasn't selected an ingredient from the autocompleter"
|
||||
},
|
||||
"selectImage": "Seleccioneu una imatge",
|
||||
"@selectImage": {
|
||||
"description": "Label and error message when the user hasn't selected an image to save"
|
||||
},
|
||||
"optionsLabel": "Opcions",
|
||||
"@optionsLabel": {
|
||||
"description": "Label for the popup with general app options"
|
||||
},
|
||||
"takePicture": "Fes una foto",
|
||||
"@takePicture": {},
|
||||
"chooseFromLibrary": "Escull del rodet de fotos",
|
||||
"@chooseFromLibrary": {},
|
||||
"appUpdateTitle": "Cal actualitzar",
|
||||
"@appUpdateTitle": {},
|
||||
"invalidUrl": "Entra un URL vàlid",
|
||||
"@invalidUrl": {
|
||||
"description": "Error message when the user enters an invalid URL, e.g. in the login form"
|
||||
},
|
||||
"invalidUsername": "Introdueix un nom d'usuari vàlid",
|
||||
"@invalidUsername": {
|
||||
"description": "Error message when the user enters an invalid username"
|
||||
},
|
||||
"register": "Registra't",
|
||||
"@register": {
|
||||
"description": "Text for registration button"
|
||||
},
|
||||
"useDefaultServer": "Usa el servidor per defecte",
|
||||
"@useDefaultServer": {
|
||||
"description": "Toggle button allowing users to switch between the default and a custom wger server"
|
||||
},
|
||||
"useCustomServer": "Usa un servidor personalitzat",
|
||||
"@useCustomServer": {
|
||||
"description": "Toggle button allowing users to switch between the default and a custom wger server"
|
||||
},
|
||||
"customServerHint": "Introdueix l'adreça del teu servidor propi, altrament s'usarà el servidor per defecte",
|
||||
"@customServerHint": {
|
||||
"description": "Hint text for the form where the users can enter their own wger instance"
|
||||
},
|
||||
"loginInstead": "Entra",
|
||||
"@loginInstead": {},
|
||||
"labelWorkoutPlans": "Plans d'entrenament",
|
||||
"@labelWorkoutPlans": {
|
||||
"description": "Title for screen workout plans"
|
||||
},
|
||||
"labelBottomNavNutrition": "Nutrició",
|
||||
"@labelBottomNavNutrition": {
|
||||
"description": "Label used in bottom navigation, use a short word"
|
||||
},
|
||||
"weightUnit": "Unitat de pes",
|
||||
"@weightUnit": {},
|
||||
"setNr": "Sèrie {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": {}
|
||||
}
|
||||
},
|
||||
"dayDescriptionHelp": "Descripció de què es fa aquest dia (p. e. «dia de tracció») o quines parts del cos d'exerciten (p. e. «pit i espatlles»)",
|
||||
"@dayDescriptionHelp": {},
|
||||
"aboutDescription": "Gràcies per usar wger! wger és un projecte col·laboratiu de codi obert, fet per entusiastes del fitness d'arreu del món.",
|
||||
"@aboutDescription": {
|
||||
"description": "Text in the about dialog"
|
||||
},
|
||||
"gymMode": "Mode gimnàs",
|
||||
"@gymMode": {
|
||||
"description": "Label when starting the gym mode"
|
||||
},
|
||||
"logHelpEntries": "Si en un únic dia hi ha més d'una entrada amb el mateix nombre de repeticions però diferents pesos, al diagrama es mostra només l'entrada amb el pes més gran.",
|
||||
"@logHelpEntries": {},
|
||||
"noNutritionalPlans": "No tens plans nutricionals",
|
||||
"@noNutritionalPlans": {
|
||||
"description": "Message shown when the user has no nutritional plans"
|
||||
},
|
||||
"planned": "Previst",
|
||||
"@planned": {
|
||||
"description": "Header for the column of 'planned' nutritional values, i.e. what should be eaten"
|
||||
},
|
||||
"timeStartAhead": "L'hora d'inici no pot ser posterior a la de finalització",
|
||||
"@timeStartAhead": {},
|
||||
"logMeal": "Registra aquest àpat",
|
||||
"@logMeal": {},
|
||||
"searchIngredient": "Cerca ingredient",
|
||||
"@searchIngredient": {
|
||||
"description": "Label on ingredient search form"
|
||||
},
|
||||
"nutritionalPlans": "Plans nutricionals",
|
||||
"@nutritionalPlans": {},
|
||||
"measurements": "Mesures",
|
||||
"@measurements": {
|
||||
"description": "Categories for the measurements such as biceps size, body fat, etc."
|
||||
},
|
||||
"measurementCategoriesHelpText": "Categoria de la mesura, com ara «bíceps» o «greix corporal»",
|
||||
"@measurementCategoriesHelpText": {},
|
||||
"date": "Data",
|
||||
"@date": {
|
||||
"description": "The date of a workout log or body weight entry"
|
||||
},
|
||||
"value": "Valor",
|
||||
"@value": {
|
||||
"description": "The value of a measurement entry"
|
||||
},
|
||||
"difference": "Diferència",
|
||||
"@difference": {},
|
||||
"kcal": "kcal",
|
||||
"@kcal": {
|
||||
"description": "Energy in a meal in kilocalories, kcal"
|
||||
},
|
||||
"proteinShort": "P",
|
||||
"@proteinShort": {
|
||||
"description": "The first letter or short name of the word 'Protein', used in overviews"
|
||||
},
|
||||
"enterRepetitionsOrWeight": "Ompliu les repeticions o bé el pes per a una de les sèries com a mínim",
|
||||
"@enterRepetitionsOrWeight": {
|
||||
"description": "Error message when the user hasn't filled in the forms for exercise sets"
|
||||
},
|
||||
"fatShort": "G",
|
||||
"@fatShort": {
|
||||
"description": "The first letter or short name of the word 'Fat', used in overviews"
|
||||
},
|
||||
"saturatedFat": "Greix saturat",
|
||||
"@saturatedFat": {},
|
||||
"noWeightEntries": "No teniu cap entrada de pes",
|
||||
"@noWeightEntries": {
|
||||
"description": "Message shown when the user has no logged weight entries"
|
||||
},
|
||||
"fibres": "Fibra",
|
||||
"@fibres": {},
|
||||
"sodium": "Sodi",
|
||||
"@sodium": {},
|
||||
"delete": "Esborra",
|
||||
"@delete": {},
|
||||
"aboutSourceText": "Obtingueu el codi font d'aquesta aplicació i el seu servidor a Github",
|
||||
"@aboutSourceText": {
|
||||
"description": "Text for source code section in the about dialog"
|
||||
},
|
||||
"confirmDelete": "Esteu segur de voler esborrar '{toDelete}'?",
|
||||
"@confirmDelete": {
|
||||
"description": "Confirmation text before the user deletes an object",
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"toDelete": {}
|
||||
}
|
||||
},
|
||||
"goToToday": "Vés a avui",
|
||||
"@goToToday": {
|
||||
"description": "Label on button to jump back to 'today' in the calendar widget"
|
||||
},
|
||||
"selectExercise": "Seleccioneu un exercici",
|
||||
"@selectExercise": {
|
||||
"description": "Error message when the user hasn't selected an exercise in the form"
|
||||
},
|
||||
"enterCharacters": "Introduïu entre {min} i {max} caràcters",
|
||||
"@enterCharacters": {
|
||||
"description": "Error message when the user hasn't entered the correct number of characters in a form",
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"min": {},
|
||||
"max": {}
|
||||
}
|
||||
},
|
||||
"recentlyUsedIngredients": "Ingredients afegits recentment",
|
||||
"@recentlyUsedIngredients": {
|
||||
"description": "A message when a user adds a new ingredient to a meal."
|
||||
},
|
||||
"gallery": "Galeria",
|
||||
"@gallery": {},
|
||||
"addImage": "Afegeix imatge",
|
||||
"@addImage": {},
|
||||
"dataCopied": "Dades copiades a una nova entrada",
|
||||
"@dataCopied": {
|
||||
"description": "Snackbar message to show on copying data to a new log entry"
|
||||
},
|
||||
"appUpdateContent": "Aquesta versió de l'app no és compatible amb el servidor, actualitzeu l'aplicació.",
|
||||
"@appUpdateContent": {}
|
||||
}
|
||||
@@ -478,7 +478,7 @@
|
||||
},
|
||||
"percentEnergy": "Prozent der Energie",
|
||||
"@percentEnergy": {},
|
||||
"difference": "Unterschied",
|
||||
"difference": "Differenz",
|
||||
"@difference": {},
|
||||
"logged": "Protokolliert",
|
||||
"@logged": {
|
||||
|
||||
@@ -507,5 +507,43 @@
|
||||
"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."
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"@enterValidNumber": {
|
||||
"description": "Error message when the user has submitted an invalid number (e.g. '3,.,.,.')"
|
||||
},
|
||||
"nrOfSets": "Número de series: {nrOfSets}",
|
||||
"nrOfSets": "Series por ejercicio: {nrOfSets}",
|
||||
"@nrOfSets": {
|
||||
"description": "Label shown on the slider where the user selects the nr of sets",
|
||||
"type": "text",
|
||||
@@ -222,7 +222,7 @@
|
||||
"@gymMode": {
|
||||
"description": "Label when starting the gym mode"
|
||||
},
|
||||
"selectExercises": "Si buscas realizar una súper serie, puedes buscar algunos ejercicios, estos estarán agrupados juntos",
|
||||
"selectExercises": "Si buscas realizar una superserie, puedes buscar algunos ejercicios, estos estarán agrupados juntos",
|
||||
"@selectExercises": {},
|
||||
"newSet": "Nueva serie",
|
||||
"@newSet": {
|
||||
@@ -479,5 +479,52 @@
|
||||
"fatShort": "G",
|
||||
"@fatShort": {
|
||||
"description": "The first letter or short name of the word 'Fat', used in overviews"
|
||||
}
|
||||
},
|
||||
"logIngredient": "Guardar en el diario nutricional",
|
||||
"@logIngredient": {},
|
||||
"plateCalculatorNotDivisible": "No se puede obtener el peso con las placas disponbles",
|
||||
"@plateCalculatorNotDivisible": {
|
||||
"description": "Error message when the current weight is not reachable with plates (e.g. 33.1 kg)"
|
||||
},
|
||||
"plateCalculator": "Placas",
|
||||
"@plateCalculator": {
|
||||
"description": "Label used for the plate calculator in the gym mode"
|
||||
},
|
||||
"searchIngredient": "Buscar ingrediente",
|
||||
"@searchIngredient": {
|
||||
"description": "Label on ingredient search form"
|
||||
},
|
||||
"supersetWith": "en conjunto con",
|
||||
"@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": {
|
||||
"description": "Label used in RiR slider when the RiR value is not used/saved for the current setting or log"
|
||||
},
|
||||
"planned": "Previsto",
|
||||
"@planned": {
|
||||
"description": "Header for the column of 'planned' nutritional values, i.e. what should be eaten"
|
||||
},
|
||||
"logged": "Registrado",
|
||||
"@logged": {
|
||||
"description": "Header for the column of 'logged' nutritional values, i.e. what was eaten"
|
||||
},
|
||||
"gPerBodyKg": "g por kg de peso corporal",
|
||||
"@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": {
|
||||
"description": "Label shown on the slider where the user can toggle showing units and RiR",
|
||||
"type": "text"
|
||||
},
|
||||
"recentlyUsedIngredients": "Ingredientes añadidos recientemente",
|
||||
"@recentlyUsedIngredients": {
|
||||
"description": "A message when a user adds a new ingredient to a meal."
|
||||
},
|
||||
"appUpdateTitle": "Es necesario actualizar",
|
||||
"@appUpdateTitle": {},
|
||||
"appUpdateContent": "Esta versión de la aplicación no es compatible con el servidor. Por favor, actualízala.",
|
||||
"@appUpdateContent": {}
|
||||
}
|
||||
|
||||
26
lib/l10n/app_hi.arb
Normal file
26
lib/l10n/app_hi.arb
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"login": "लोग इन",
|
||||
"@login": {
|
||||
"description": "Text for login button"
|
||||
},
|
||||
"logout": "लोग आउट",
|
||||
"@logout": {
|
||||
"description": "Text for logout button"
|
||||
},
|
||||
"useDefaultServer": "डिफ़ॉल्ट सर्वर का प्रयोग करें",
|
||||
"@useDefaultServer": {
|
||||
"description": "Toggle button allowing users to switch between the default and a custom wger server"
|
||||
},
|
||||
"register": "रजिस्टर",
|
||||
"@register": {
|
||||
"description": "Text for registration button"
|
||||
},
|
||||
"useCustomServer": "कस्टम सर्वर का प्रयोग करें",
|
||||
"@useCustomServer": {
|
||||
"description": "Toggle button allowing users to switch between the default and a custom wger server"
|
||||
},
|
||||
"invalidUrl": "कृपया एक वैलिड URL दीजिये",
|
||||
"@invalidUrl": {
|
||||
"description": "Error message when the user enters an invalid URL, e.g. in the login form"
|
||||
}
|
||||
}
|
||||
@@ -268,5 +268,7 @@
|
||||
"logout": "Logg ut",
|
||||
"@logout": {
|
||||
"description": "Text for logout button"
|
||||
}
|
||||
},
|
||||
"difference": "Forskjell",
|
||||
"@difference": {}
|
||||
}
|
||||
|
||||
524
lib/l10n/app_ru.arb
Normal file
524
lib/l10n/app_ru.arb
Normal file
@@ -0,0 +1,524 @@
|
||||
{
|
||||
"useCustomServer": "Использовать пользовательский сервер",
|
||||
"@useCustomServer": {
|
||||
"description": "Toggle button allowing users to switch between the default and a custom wger server"
|
||||
},
|
||||
"email": "Адрес электронной почты",
|
||||
"@email": {},
|
||||
"labelWorkoutPlans": "Планы тренировок",
|
||||
"@labelWorkoutPlans": {
|
||||
"description": "Title for screen workout plans"
|
||||
},
|
||||
"registerInstead": "Зарегистроваться вместо этого",
|
||||
"@registerInstead": {},
|
||||
"loginInstead": "Войти вместо этого",
|
||||
"@loginInstead": {},
|
||||
"labelDashboard": "Панель управления",
|
||||
"@labelDashboard": {
|
||||
"description": "Title for screen dashboard"
|
||||
},
|
||||
"muscles": "Мышцы",
|
||||
"@muscles": {
|
||||
"description": "(main) muscles trained by an exercise"
|
||||
},
|
||||
"reps": "Повтор",
|
||||
"@reps": {
|
||||
"description": "Shorthand for repetitions, used when space constraints are tighter"
|
||||
},
|
||||
"rir": "ПвЗ",
|
||||
"@rir": {
|
||||
"description": "Shorthand for Repetitions In Reserve"
|
||||
},
|
||||
"rirNotUsed": "ПвЗ не используется",
|
||||
"@rirNotUsed": {
|
||||
"description": "Label used in RiR slider when the RiR value is not used/saved for the current setting or log"
|
||||
},
|
||||
"notes": "Заметки",
|
||||
"@notes": {
|
||||
"description": "Personal notes, e.g. for a workout session"
|
||||
},
|
||||
"workoutSession": "Тренировка",
|
||||
"@workoutSession": {
|
||||
"description": "A (logged) workout session"
|
||||
},
|
||||
"newDay": "Новый день",
|
||||
"@newDay": {},
|
||||
"selectExercises": "Если вы хотите сделать суперсет, вы можете найти несколько упражнений, они будут сгруппированы вместе",
|
||||
"@selectExercises": {},
|
||||
"plateCalculator": "Пластины",
|
||||
"@plateCalculator": {
|
||||
"description": "Label used for the plate calculator in the gym mode"
|
||||
},
|
||||
"save": "Сохранить",
|
||||
"@save": {},
|
||||
"logMeal": "Записать это блюдо",
|
||||
"@logMeal": {},
|
||||
"nutritionalPlan": "План питания",
|
||||
"@nutritionalPlan": {},
|
||||
"noNutritionalPlans": "У вас нет планов питания",
|
||||
"@noNutritionalPlans": {
|
||||
"description": "Message shown when the user has no nutritional plans"
|
||||
},
|
||||
"measurementEntriesHelpText": "Единица, используемая для измерения в категории, например 'см' или '%'",
|
||||
"@measurementEntriesHelpText": {},
|
||||
"value": "Значение",
|
||||
"@value": {
|
||||
"description": "The value of a measurement entry"
|
||||
},
|
||||
"time": "Время",
|
||||
"@time": {
|
||||
"description": "The time of a meal or workout"
|
||||
},
|
||||
"timeStart": "Время начала",
|
||||
"@timeStart": {
|
||||
"description": "The starting time of a workout"
|
||||
},
|
||||
"ingredient": "Ингредиент",
|
||||
"@ingredient": {},
|
||||
"energy": "Энергия",
|
||||
"@energy": {
|
||||
"description": "Energy in a meal, ingredient etc. e.g. in kJ"
|
||||
},
|
||||
"energyShort": "Э",
|
||||
"@energyShort": {
|
||||
"description": "The first letter or short name of the word 'Energy', used in overviews"
|
||||
},
|
||||
"macronutrients": "Макроэлементы",
|
||||
"@macronutrients": {},
|
||||
"logged": "Записано",
|
||||
"@logged": {
|
||||
"description": "Header for the column of 'logged' nutritional values, i.e. what was eaten"
|
||||
},
|
||||
"difference": "Разница",
|
||||
"@difference": {},
|
||||
"kJ": "кДж",
|
||||
"@kJ": {
|
||||
"description": "Energy in a meal in kilo joules, kJ"
|
||||
},
|
||||
"g": "г",
|
||||
"@g": {
|
||||
"description": "Abbreviation for gram"
|
||||
},
|
||||
"goToDetailPage": "Перейти на страницу сведений",
|
||||
"@goToDetailPage": {},
|
||||
"aboutSourceTitle": "Исходный код",
|
||||
"@aboutSourceTitle": {
|
||||
"description": "Title for source code section in the about dialog"
|
||||
},
|
||||
"aboutContactUsTitle": "Скажите привет!",
|
||||
"@aboutContactUsTitle": {
|
||||
"description": "Title for contact us section in the about dialog"
|
||||
},
|
||||
"aboutTranslationTitle": "Перевод",
|
||||
"@aboutTranslationTitle": {
|
||||
"description": "Title for translation section in the about dialog"
|
||||
},
|
||||
"calendar": "Календарь",
|
||||
"@calendar": {},
|
||||
"enterValue": "Пожалуйста, введите значение",
|
||||
"@enterValue": {
|
||||
"description": "Error message when the user hasn't entered a value on a required field"
|
||||
},
|
||||
"selectExercise": "Пожалуйста, выберите упражнение",
|
||||
"@selectExercise": {
|
||||
"description": "Error message when the user hasn't selected an exercise in the form"
|
||||
},
|
||||
"enterCharacters": "Пожалуйста, введите между {min} и {max} символами",
|
||||
"@enterCharacters": {
|
||||
"description": "Error message when the user hasn't entered the correct number of characters in a form",
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"min": {},
|
||||
"max": {}
|
||||
}
|
||||
},
|
||||
"nrOfSets": "Количество сетов на упражнение: {nrOfSets}",
|
||||
"@nrOfSets": {
|
||||
"description": "Label shown on the slider where the user selects the nr of sets",
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"nrOfSets": {}
|
||||
}
|
||||
},
|
||||
"selectIngredient": "Пожалуйста, выберите ингредиент",
|
||||
"@selectIngredient": {
|
||||
"description": "Error message when the user hasn't selected an ingredient from the autocompleter"
|
||||
},
|
||||
"recentlyUsedIngredients": "Недавно добавленные ингредиенты",
|
||||
"@recentlyUsedIngredients": {
|
||||
"description": "A message when a user adds a new ingredient to a meal."
|
||||
},
|
||||
"selectImage": "Пожалуйста, выберите изображение",
|
||||
"@selectImage": {
|
||||
"description": "Label and error message when the user hasn't selected an image to save"
|
||||
},
|
||||
"takePicture": "Сфотографировать",
|
||||
"@takePicture": {},
|
||||
"chooseFromLibrary": "Выбрать из библиотеки фотографий",
|
||||
"@chooseFromLibrary": {},
|
||||
"gallery": "Галерея",
|
||||
"@gallery": {},
|
||||
"addImage": "Добавить изображение",
|
||||
"@addImage": {},
|
||||
"appUpdateTitle": "Требуется обновление",
|
||||
"@appUpdateTitle": {},
|
||||
"passwordTooShort": "Пароль слишком короткий",
|
||||
"@passwordTooShort": {
|
||||
"description": "Error message when the user a password that is too short"
|
||||
},
|
||||
"category": "Категория",
|
||||
"@category": {
|
||||
"description": "Category for an exercise, ingredient, etc."
|
||||
},
|
||||
"noWorkoutPlans": "У вас нет планов тренировок",
|
||||
"@noWorkoutPlans": {
|
||||
"description": "Message shown when the user has no workout plans"
|
||||
},
|
||||
"login": "Войти",
|
||||
"@login": {
|
||||
"description": "Text for login button"
|
||||
},
|
||||
"register": "Зарегистрироваться",
|
||||
"@register": {
|
||||
"description": "Text for registration button"
|
||||
},
|
||||
"password": "Пароль",
|
||||
"@password": {},
|
||||
"logout": "Выйти",
|
||||
"@logout": {
|
||||
"description": "Text for logout button"
|
||||
},
|
||||
"useDefaultServer": "Использовать сервер по умолчанию",
|
||||
"@useDefaultServer": {
|
||||
"description": "Toggle button allowing users to switch between the default and a custom wger server"
|
||||
},
|
||||
"invalidUrl": "Пожалуйста, введите действительный URL",
|
||||
"@invalidUrl": {
|
||||
"description": "Error message when the user enters an invalid URL, e.g. in the login form"
|
||||
},
|
||||
"usernameValidChars": "Имя пользователя может содержать только буквы, цифры и символы @, +, ., - и _",
|
||||
"@usernameValidChars": {
|
||||
"description": "Error message when the user tries to register a username with forbidden characters"
|
||||
},
|
||||
"passwordsDontMatch": "Пароли не совпадают",
|
||||
"@passwordsDontMatch": {
|
||||
"description": "Error message when the user enters two different passwords during registration"
|
||||
},
|
||||
"confirmPassword": "Подтверждение пароля",
|
||||
"@confirmPassword": {},
|
||||
"invalidEmail": "Пожалуйста, введите действительный адрес электронной почты",
|
||||
"@invalidEmail": {
|
||||
"description": "Error message when the user enters an invalid email"
|
||||
},
|
||||
"username": "Имя пользователя",
|
||||
"@username": {},
|
||||
"invalidUsername": "Пожалуйста, введите действительное имя пользователя",
|
||||
"@invalidUsername": {
|
||||
"description": "Error message when the user enters an invalid username"
|
||||
},
|
||||
"customServerHint": "Введите адрес вашего собственного сервера, иначе будет использован адрес по умолчанию",
|
||||
"@customServerHint": {
|
||||
"description": "Hint text for the form where the users can enter their own wger instance"
|
||||
},
|
||||
"reset": "Сброс",
|
||||
"@reset": {
|
||||
"description": "Button text allowing the user to reset the entered values to the default"
|
||||
},
|
||||
"labelBottomNavWorkout": "Тренировка",
|
||||
"@labelBottomNavWorkout": {
|
||||
"description": "Label used in bottom navigation, use a short word"
|
||||
},
|
||||
"customServerUrl": "URL-адрес экземпляра wger",
|
||||
"@customServerUrl": {
|
||||
"description": "Label in the form where the users can enter their own wger instance"
|
||||
},
|
||||
"labelBottomNavNutrition": "Питание",
|
||||
"@labelBottomNavNutrition": {
|
||||
"description": "Label used in bottom navigation, use a short word"
|
||||
},
|
||||
"labelWorkoutPlan": "План тренировки",
|
||||
"@labelWorkoutPlan": {
|
||||
"description": "Title for screen workout plan"
|
||||
},
|
||||
"labelWorkoutLogs": "Журналы тренировок",
|
||||
"@labelWorkoutLogs": {
|
||||
"description": "(Workout) logs"
|
||||
},
|
||||
"exercise": "Упражнение",
|
||||
"@exercise": {
|
||||
"description": "An exercise for a workout"
|
||||
},
|
||||
"successfullySaved": "Сохранено",
|
||||
"@successfullySaved": {
|
||||
"description": "Message when an item was successfully saved"
|
||||
},
|
||||
"successfullyDeleted": "Удалено",
|
||||
"@successfullyDeleted": {
|
||||
"description": "Message when an item was successfully deleted"
|
||||
},
|
||||
"searchExercise": "Найдите упражнение, которое нужно добавить",
|
||||
"@searchExercise": {
|
||||
"description": "Label on set form. Selected exercises are added to the set"
|
||||
},
|
||||
"equipment": "Оборудование",
|
||||
"@equipment": {
|
||||
"description": "Equipment needed to perform an exercise"
|
||||
},
|
||||
"musclesSecondary": "Вторичные мышцы",
|
||||
"@musclesSecondary": {
|
||||
"description": "secondary muscles trained by an exercise"
|
||||
},
|
||||
"newWorkout": "Новый план тренировок",
|
||||
"@newWorkout": {
|
||||
"description": "Header when adding a new workout"
|
||||
},
|
||||
"dayDescriptionHelp": "Описание того, что делается в этот день (например, 'день подтягиваний') или какие части тела тренируются (например, 'грудь и плечи')",
|
||||
"@dayDescriptionHelp": {},
|
||||
"weightUnit": "Единица веса",
|
||||
"@weightUnit": {},
|
||||
"repetitionUnit": "Единица повторения",
|
||||
"@repetitionUnit": {},
|
||||
"repetitions": "Повторений",
|
||||
"@repetitions": {
|
||||
"description": "Repetitions for an exercise set"
|
||||
},
|
||||
"comment": "Комментарий",
|
||||
"@comment": {
|
||||
"description": "Comment, additional information"
|
||||
},
|
||||
"impression": "Впечатление",
|
||||
"@impression": {
|
||||
"description": "General impression (e.g. for a workout session) such as good, bad, etc."
|
||||
},
|
||||
"set": "Сет",
|
||||
"@set": {
|
||||
"description": "A set in a workout plan"
|
||||
},
|
||||
"gymMode": "Режим тренажерного зала",
|
||||
"@gymMode": {
|
||||
"description": "Label when starting the gym mode"
|
||||
},
|
||||
"jumpTo": "Перейти к",
|
||||
"@jumpTo": {
|
||||
"description": "Imperative. Label used in popup allowing the user to jump to a specific exercise while in the gym mode"
|
||||
},
|
||||
"logHelpEntriesUnits": "Обратите внимание, что в таблицу заносятся только записи с единицей веса (кг или фунты) и повторениями, другие комбинации, такие как время или до отказа, здесь не учитываются.",
|
||||
"@logHelpEntriesUnits": {},
|
||||
"pause": "Пауза",
|
||||
"@pause": {
|
||||
"description": "Noun, not an imperative! Label used for the pause when using the gym mode"
|
||||
},
|
||||
"plateCalculatorNotDivisible": "Невозможно достичь веса с имеющимися пластинами",
|
||||
"@plateCalculatorNotDivisible": {
|
||||
"description": "Error message when the current weight is not reachable with plates (e.g. 33.1 kg)"
|
||||
},
|
||||
"todaysWorkout": "Ваша тренировка сегодня",
|
||||
"@todaysWorkout": {},
|
||||
"logHelpEntries": "Если в один день есть несколько записей с одинаковым количеством повторений, но разными весами, то на диаграмме отображается только запись с большим весом.",
|
||||
"@logHelpEntries": {},
|
||||
"description": "Описание",
|
||||
"@description": {},
|
||||
"weight": "Вес",
|
||||
"@weight": {
|
||||
"description": "The weight of a workout log or body weight entry"
|
||||
},
|
||||
"name": "Имя",
|
||||
"@name": {
|
||||
"description": "Name for a workout or nutritional plan"
|
||||
},
|
||||
"addIngredient": "Добавить ингредиент",
|
||||
"@addIngredient": {},
|
||||
"nutritionalPlans": "Планы питания",
|
||||
"@nutritionalPlans": {},
|
||||
"timeStartAhead": "Время начала не может быть раньше времени окончания",
|
||||
"@timeStartAhead": {},
|
||||
"logIngredient": "Сохранить в дневнике питания",
|
||||
"@logIngredient": {},
|
||||
"searchIngredient": "Поиск ингредиента",
|
||||
"@searchIngredient": {
|
||||
"description": "Label on ingredient search form"
|
||||
},
|
||||
"nutritionalDiary": "Дневник питания",
|
||||
"@nutritionalDiary": {},
|
||||
"measurements": "Измерения",
|
||||
"@measurements": {
|
||||
"description": "Categories for the measurements such as biceps size, body fat, etc."
|
||||
},
|
||||
"anErrorOccurred": "Произошла ошибка!",
|
||||
"@anErrorOccurred": {},
|
||||
"measurement": "Измерение",
|
||||
"@measurement": {},
|
||||
"measurementCategoriesHelpText": "Категория измерения, например 'бицепс' или 'жир'",
|
||||
"@measurementCategoriesHelpText": {},
|
||||
"date": "Дата",
|
||||
"@date": {
|
||||
"description": "The date of a workout log or body weight entry"
|
||||
},
|
||||
"start": "Начать",
|
||||
"@start": {
|
||||
"description": "Label on button to start the gym mode (i.e., an imperative)"
|
||||
},
|
||||
"timeEnd": "Время окончания",
|
||||
"@timeEnd": {
|
||||
"description": "The end time of a workout"
|
||||
},
|
||||
"kcal": "ккал",
|
||||
"@kcal": {
|
||||
"description": "Energy in a meal in kilocalories, kcal"
|
||||
},
|
||||
"edit": "Редактировать",
|
||||
"@edit": {},
|
||||
"delete": "Удалить",
|
||||
"@delete": {},
|
||||
"confirmDelete": "Вы уверены, что хотите удалить '{toDelete}'?",
|
||||
"@confirmDelete": {
|
||||
"description": "Confirmation text before the user deletes an object",
|
||||
"type": "text",
|
||||
"placeholders": {
|
||||
"toDelete": {}
|
||||
}
|
||||
},
|
||||
"setUnitsAndRir": "Установите единицы измерения и ПвЗ",
|
||||
"@setUnitsAndRir": {
|
||||
"description": "Label shown on the slider where the user can toggle showing units and RiR",
|
||||
"type": "text"
|
||||
},
|
||||
"planned": "Запланировано",
|
||||
"@planned": {
|
||||
"description": "Header for the column of 'planned' nutritional values, i.e. what should be eaten"
|
||||
},
|
||||
"fatShort": "Ж",
|
||||
"@fatShort": {
|
||||
"description": "The first letter or short name of the word 'Fat', used in overviews"
|
||||
},
|
||||
"gPerBodyKg": "г на кг тела",
|
||||
"@gPerBodyKg": {
|
||||
"description": "Label used for total sums of e.g. calories or similar in grams per Kg of body weight"
|
||||
},
|
||||
"total": "Всего",
|
||||
"@total": {
|
||||
"description": "Label used for total sums of e.g. calories or similar"
|
||||
},
|
||||
"fibres": "Клетчатка",
|
||||
"@fibres": {},
|
||||
"percentEnergy": "Процент энергии",
|
||||
"@percentEnergy": {},
|
||||
"proteinShort": "Б",
|
||||
"@proteinShort": {
|
||||
"description": "The first letter or short name of the word 'Protein', used in overviews"
|
||||
},
|
||||
"carbohydratesShort": "У",
|
||||
"@carbohydratesShort": {
|
||||
"description": "The first letter or short name of the word 'Carbohydrates', used in overviews"
|
||||
},
|
||||
"sugars": "Сахар",
|
||||
"@sugars": {},
|
||||
"saturatedFat": "Насыщенные жиры",
|
||||
"@saturatedFat": {},
|
||||
"sodium": "Натрий",
|
||||
"@sodium": {},
|
||||
"amount": "Количество",
|
||||
"@amount": {
|
||||
"description": "The amount (e.g. in grams) of an ingredient in a meal"
|
||||
},
|
||||
"unit": "Единица",
|
||||
"@unit": {
|
||||
"description": "The unit used for a repetition (kg, time, etc.)"
|
||||
},
|
||||
"noWeightEntries": "У вас нет записей о весе",
|
||||
"@noWeightEntries": {
|
||||
"description": "Message shown when the user has no logged weight entries"
|
||||
},
|
||||
"supersetWith": "суперсет с",
|
||||
"@supersetWith": {
|
||||
"description": "Text used between exercise cards when adding a new set. Translate as something like 'in a superset with'"
|
||||
},
|
||||
"newEntry": "Новая запись",
|
||||
"@newEntry": {
|
||||
"description": "Title when adding a new entry such as a weight or log entry"
|
||||
},
|
||||
"loadingText": "Загрузка…",
|
||||
"@loadingText": {
|
||||
"description": "Text to show when entries are being loaded in the background: Loading..."
|
||||
},
|
||||
"newNutritionalPlan": "Новый план питания",
|
||||
"@newNutritionalPlan": {},
|
||||
"toggleDetails": "Переключить сведения",
|
||||
"@toggleDetails": {
|
||||
"description": "Switch to toggle detail / overview"
|
||||
},
|
||||
"aboutDescription": "Спасибо за использование wger! wger - это совместный проект с открытым исходным кодом, созданный фитнес энтузиастами со всего мира.",
|
||||
"@aboutDescription": {
|
||||
"description": "Text in the about dialog"
|
||||
},
|
||||
"aboutContactUsText": "Если вы хотите пообщаться с нами, зайдите на сервер Discord и свяжитесь с нами",
|
||||
"@aboutContactUsText": {
|
||||
"description": "Text for contact us section in the about dialog"
|
||||
},
|
||||
"aboutTranslationText": "Это приложение переведено на weblate. Если вы тоже хотите помочь, нажмите на ссылку и начните переводить",
|
||||
"@aboutTranslationText": {
|
||||
"description": "Text for translation section in the about dialog"
|
||||
},
|
||||
"aboutSourceText": "Получите исходный код этого приложения и его сервера на github",
|
||||
"@aboutSourceText": {
|
||||
"description": "Text for source code section in the about dialog"
|
||||
},
|
||||
"aboutBugsTitle": "Есть проблема или идея?",
|
||||
"@aboutBugsTitle": {
|
||||
"description": "Title for bugs section in the about dialog"
|
||||
},
|
||||
"enterValidNumber": "Пожалуйста, введите правильное число",
|
||||
"@enterValidNumber": {
|
||||
"description": "Error message when the user has submitted an invalid number (e.g. '3,.,.,.')"
|
||||
},
|
||||
"aboutBugsText": "Свяжитесь с нами, если что-то пошло не так или если вам кажется, что какой-то функции не хватает.",
|
||||
"@aboutBugsText": {
|
||||
"description": "Text for bugs section in the about dialog"
|
||||
},
|
||||
"goToToday": "Перейти на сегодня",
|
||||
"@goToToday": {
|
||||
"description": "Label on button to jump back to 'today' in the calendar widget"
|
||||
},
|
||||
"enterRepetitionsOrWeight": "Пожалуйста, укажите количество повторений или вес хотя бы для одного из сетов",
|
||||
"@enterRepetitionsOrWeight": {
|
||||
"description": "Error message when the user hasn't filled in the forms for exercise sets"
|
||||
},
|
||||
"optionsLabel": "Опции",
|
||||
"@optionsLabel": {
|
||||
"description": "Label for the popup with general app options"
|
||||
},
|
||||
"sameRepetitions": "Если вы делаете одинаковые повторения и вес для всех сетов, вы можете просто заполнить одну строку. Например, для 4 сетов просто введите 10 повторений, это автоматически превратится в \"4 x 10\".",
|
||||
"@sameRepetitions": {},
|
||||
"newSet": "Новый сет",
|
||||
"@newSet": {
|
||||
"description": "Header when adding a new set to a workout day"
|
||||
},
|
||||
"dataCopied": "Данные копируются в новую запись",
|
||||
"@dataCopied": {
|
||||
"description": "Snackbar message to show on copying data to a new log entry"
|
||||
},
|
||||
"appUpdateContent": "Эта версия приложения не совместима с сервером, пожалуйста, обновите ваше приложение.",
|
||||
"@appUpdateContent": {},
|
||||
"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",
|
||||
"placeholders": {
|
||||
"nr": {}
|
||||
}
|
||||
},
|
||||
"addSet": "Добавить сет",
|
||||
"@addSet": {
|
||||
"description": "Label for the button that adds a set (to a workout day)"
|
||||
},
|
||||
"addMeal": "Добавить блюдо",
|
||||
"@addMeal": {},
|
||||
"mealLogged": "Блюдо записано в дневник",
|
||||
"@mealLogged": {},
|
||||
"protein": "Белки",
|
||||
"@protein": {},
|
||||
"carbohydrates": "Углеводы",
|
||||
"@carbohydrates": {},
|
||||
"fat": "Жиры",
|
||||
"@fat": {}
|
||||
}
|
||||
@@ -358,5 +358,9 @@
|
||||
"saturatedFat": "Doymuş yağ",
|
||||
"@saturatedFat": {},
|
||||
"fibres": "Lif",
|
||||
"@fibres": {}
|
||||
"@fibres": {},
|
||||
"delete": "Sil",
|
||||
"@delete": {},
|
||||
"edit": "Düzenle",
|
||||
"@edit": {}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ class Ingredient {
|
||||
@JsonKey(required: true)
|
||||
final int id;
|
||||
|
||||
/// Barcode of the product
|
||||
@JsonKey(required: true)
|
||||
final String code;
|
||||
|
||||
/// Name of the product
|
||||
@JsonKey(required: true)
|
||||
final String name;
|
||||
@@ -66,6 +70,7 @@ class Ingredient {
|
||||
|
||||
const Ingredient({
|
||||
required this.id,
|
||||
required this.code,
|
||||
required this.name,
|
||||
required this.creationDate,
|
||||
required this.energy,
|
||||
|
||||
@@ -11,6 +11,7 @@ Ingredient _$IngredientFromJson(Map<String, dynamic> json) {
|
||||
json,
|
||||
requiredKeys: const [
|
||||
'id',
|
||||
'code',
|
||||
'name',
|
||||
'creation_date',
|
||||
'energy',
|
||||
@@ -25,6 +26,7 @@ Ingredient _$IngredientFromJson(Map<String, dynamic> json) {
|
||||
);
|
||||
return Ingredient(
|
||||
id: json['id'] as int,
|
||||
code: json['code'] as String,
|
||||
name: json['name'] as String,
|
||||
creationDate: DateTime.parse(json['creation_date'] as String),
|
||||
energy: json['energy'] as int,
|
||||
@@ -40,6 +42,7 @@ Ingredient _$IngredientFromJson(Map<String, dynamic> json) {
|
||||
|
||||
Map<String, dynamic> _$IngredientToJson(Ingredient instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'code': instance.code,
|
||||
'name': instance.name,
|
||||
'creation_date': toDate(instance.creationDate),
|
||||
'energy': instance.energy,
|
||||
|
||||
@@ -326,6 +326,27 @@ class NutritionPlansProvider extends WgerBaseProvider with ChangeNotifier {
|
||||
return json.decode(utf8.decode(response.bodyBytes))['suggestions'] as List<dynamic>;
|
||||
}
|
||||
|
||||
/// Searches for an ingredient with code
|
||||
Future<Ingredient?> searchIngredientWithCode(String code) async {
|
||||
if (code.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Send the request
|
||||
final data = await fetch(
|
||||
makeUrl(
|
||||
_ingredientPath,
|
||||
query: {'code': code},
|
||||
),
|
||||
);
|
||||
|
||||
if (data["count"] == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return Ingredient.fromJson(data['results'][0]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Log meal to nutrition diary
|
||||
Future<void> logMealToDiary(Meal meal) async {
|
||||
for (final item in meal.mealItems) {
|
||||
|
||||
@@ -352,9 +352,11 @@ class _DashboardWorkoutWidgetState extends State<DashboardWorkoutWidget> {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
MutedText(
|
||||
day.getDaysText,
|
||||
textAlign: TextAlign.right,
|
||||
Expanded(
|
||||
child: MutedText(
|
||||
day.getDaysText,
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.play_arrow),
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/exceptions/http_exception.dart';
|
||||
@@ -116,17 +117,25 @@ class MealItemForm extends StatelessWidget {
|
||||
final Meal _meal;
|
||||
late final MealItem _mealItem;
|
||||
final List<MealItem> _listMealItems;
|
||||
late String _barcode;
|
||||
late bool _test;
|
||||
|
||||
final _form = GlobalKey<FormState>();
|
||||
final _ingredientIdController = TextEditingController();
|
||||
final _ingredientController = TextEditingController();
|
||||
final _amountController = TextEditingController();
|
||||
|
||||
MealItemForm(this._meal, this._listMealItems, [mealItem]) {
|
||||
MealItemForm(this._meal, this._listMealItems, [mealItem, code, test]) {
|
||||
_mealItem = mealItem ?? MealItem.empty();
|
||||
_test = test ?? false;
|
||||
_barcode = code ?? '';
|
||||
_mealItem.mealId = _meal.id!;
|
||||
}
|
||||
|
||||
TextEditingController get ingredientIdController => _ingredientIdController;
|
||||
|
||||
MealItem get mealItem => _mealItem;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final String unit = AppLocalizations.of(context).g;
|
||||
@@ -136,8 +145,15 @@ class MealItemForm extends StatelessWidget {
|
||||
key: _form,
|
||||
child: Column(
|
||||
children: [
|
||||
IngredientTypeahead(_ingredientIdController, _ingredientController),
|
||||
IngredientTypeahead(
|
||||
_ingredientIdController,
|
||||
_ingredientController,
|
||||
true,
|
||||
_barcode,
|
||||
_test,
|
||||
),
|
||||
TextFormField(
|
||||
key: const Key('field-weight'),
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context).weight),
|
||||
controller: _amountController,
|
||||
keyboardType: TextInputType.number,
|
||||
@@ -155,6 +171,7 @@ class MealItemForm extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
key: const Key(SUBMIT_BUTTON_KEY_NAME),
|
||||
child: Text(AppLocalizations.of(context).save),
|
||||
onPressed: () async {
|
||||
if (!_form.currentState!.validate()) {
|
||||
@@ -235,7 +252,13 @@ class IngredientLogForm extends StatelessWidget {
|
||||
key: _form,
|
||||
child: Column(
|
||||
children: [
|
||||
IngredientTypeahead(_ingredientIdController, _ingredientController),
|
||||
IngredientTypeahead(
|
||||
_ingredientIdController,
|
||||
_ingredientController,
|
||||
true,
|
||||
'',
|
||||
false,
|
||||
),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(labelText: AppLocalizations.of(context).weight),
|
||||
controller: _amountController,
|
||||
|
||||
@@ -17,22 +17,44 @@
|
||||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/helpers/ui.dart';
|
||||
import 'package:wger/providers/nutrition.dart';
|
||||
|
||||
class IngredientTypeahead extends StatefulWidget {
|
||||
final TextEditingController _ingredientController;
|
||||
final TextEditingController _ingredientIdController;
|
||||
late String? _barcode;
|
||||
late final bool? _test;
|
||||
final bool _showScanner;
|
||||
|
||||
const IngredientTypeahead(this._ingredientIdController, this._ingredientController);
|
||||
IngredientTypeahead(this._ingredientIdController, this._ingredientController, this._showScanner,
|
||||
[this._barcode, this._test]);
|
||||
|
||||
@override
|
||||
_IngredientTypeaheadState createState() => _IngredientTypeaheadState();
|
||||
}
|
||||
|
||||
Future<String> scanBarcode(BuildContext context) async {
|
||||
String barcode;
|
||||
try {
|
||||
barcode = await FlutterBarcodeScanner.scanBarcode(
|
||||
'#ff6666', AppLocalizations.of(context).close, true, ScanMode.BARCODE);
|
||||
if (barcode.compareTo('-1') == 0) {
|
||||
return '';
|
||||
}
|
||||
} on PlatformException {
|
||||
return '';
|
||||
}
|
||||
|
||||
return barcode;
|
||||
}
|
||||
|
||||
class _IngredientTypeaheadState extends State<IngredientTypeahead> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -40,8 +62,9 @@ class _IngredientTypeaheadState extends State<IngredientTypeahead> {
|
||||
textFieldConfiguration: TextFieldConfiguration(
|
||||
controller: widget._ingredientController,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.search),
|
||||
labelText: AppLocalizations.of(context).searchIngredient,
|
||||
suffixIcon: const Icon(Icons.search),
|
||||
suffixIcon: widget._showScanner ? scanButton() : null,
|
||||
),
|
||||
),
|
||||
suggestionsCallback: (pattern) async {
|
||||
@@ -71,4 +94,75 @@ class _IngredientTypeaheadState extends State<IngredientTypeahead> {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget scanButton() {
|
||||
return IconButton(
|
||||
key: const Key('scan-button'),
|
||||
onPressed: () async {
|
||||
try {
|
||||
if (!widget._test!) {
|
||||
widget._barcode = await scanBarcode(context);
|
||||
}
|
||||
|
||||
if (widget._barcode!.isNotEmpty) {
|
||||
final result = await Provider.of<NutritionPlansProvider>(context, listen: false)
|
||||
.searchIngredientWithCode(widget._barcode!);
|
||||
|
||||
if (result != null) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
key: const Key('found-dialog'),
|
||||
title: Text(AppLocalizations.of(context).productFound),
|
||||
content:
|
||||
Text(AppLocalizations.of(context).productFoundDescription(result.name)),
|
||||
actions: [
|
||||
TextButton(
|
||||
key: const Key('found-dialog-confirm-button'),
|
||||
child: Text(MaterialLocalizations.of(context).continueButtonLabel),
|
||||
onPressed: () {
|
||||
widget._ingredientController.text = result.name;
|
||||
widget._ingredientIdController.text = result.id.toString();
|
||||
Navigator.of(ctx).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
key: const Key('found-dialog-close-button'),
|
||||
child: Text(MaterialLocalizations.of(context).closeButtonLabel),
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
//nothing is matching barcode
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
key: const Key('notFound-dialog'),
|
||||
title: Text(AppLocalizations.of(context).productNotFound),
|
||||
content: Text(
|
||||
AppLocalizations.of(context).productNotFoundDescription(widget._barcode!),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
key: const Key('notFound-dialog-close-button'),
|
||||
child: Text(MaterialLocalizations.of(context).closeButtonLabel),
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorDialog(e, context);
|
||||
}
|
||||
},
|
||||
icon: Image.asset('assets/images/barcode_scanner_icon.png'));
|
||||
}
|
||||
}
|
||||
|
||||
101
pubspec.lock
101
pubspec.lock
@@ -7,14 +7,14 @@ packages:
|
||||
name: _fe_analyzer_shared
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "31.0.0"
|
||||
version: "33.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.0"
|
||||
version: "3.1.0"
|
||||
android_metadata:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -28,7 +28,7 @@ packages:
|
||||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.6"
|
||||
version: "3.1.8"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -42,7 +42,7 @@ packages:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
version: "2.8.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -56,7 +56,7 @@ packages:
|
||||
name: build
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.2.1"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -77,21 +77,21 @@ packages:
|
||||
name: build_resolvers
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.0.6"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.1.7"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "7.2.2"
|
||||
version: "7.2.3"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -105,7 +105,7 @@ packages:
|
||||
name: built_value
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "8.1.3"
|
||||
version: "8.1.4"
|
||||
camera:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -119,7 +119,7 @@ packages:
|
||||
name: camera_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.4"
|
||||
camera_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -140,7 +140,7 @@ packages:
|
||||
name: characters
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.1.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -182,7 +182,7 @@ packages:
|
||||
name: chewie_audio
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
cider:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@@ -259,7 +259,7 @@ packages:
|
||||
name: dart_style
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.1"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -300,6 +300,13 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_barcode_scanner:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_barcode_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
flutter_calendar_carousel:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -320,7 +327,7 @@ packages:
|
||||
name: flutter_keyboard_visibility
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.1.0"
|
||||
version: "5.1.1"
|
||||
flutter_keyboard_visibility_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -461,7 +468,7 @@ packages:
|
||||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.1"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -475,14 +482,14 @@ packages:
|
||||
name: image_picker_for_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.5"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.3"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -517,7 +524,7 @@ packages:
|
||||
name: json_serializable
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.1.1"
|
||||
version: "6.1.4"
|
||||
klizma:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -559,7 +566,7 @@ packages:
|
||||
name: matcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
version: "0.12.10"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -580,7 +587,7 @@ packages:
|
||||
name: mockito
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.16"
|
||||
version: "5.0.17"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -643,21 +650,21 @@ packages:
|
||||
name: path_provider_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.5"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
version: "2.0.3"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
version: "2.0.5"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -685,7 +692,7 @@ packages:
|
||||
name: plugin_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "2.1.2"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -706,7 +713,7 @@ packages:
|
||||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.1"
|
||||
version: "6.0.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -741,35 +748,35 @@ packages:
|
||||
name: rive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.7.33"
|
||||
version: "0.8.1"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.11"
|
||||
version: "2.0.12"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.9"
|
||||
version: "2.0.10"
|
||||
shared_preferences_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.8"
|
||||
version: "2.0.9"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "2.0.4"
|
||||
shared_preferences_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -790,14 +797,14 @@ packages:
|
||||
name: shared_preferences_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
version: "2.0.3"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "2.0.4"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -830,14 +837,14 @@ packages:
|
||||
name: source_gen
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.3.1"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -893,7 +900,7 @@ packages:
|
||||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.3"
|
||||
version: "0.4.2"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -921,21 +928,21 @@ packages:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.17"
|
||||
version: "6.0.18"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.13"
|
||||
version: "6.0.14"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.13"
|
||||
version: "6.0.14"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -956,14 +963,14 @@ packages:
|
||||
name: url_launcher_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
version: "2.0.5"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.0.6"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -977,7 +984,7 @@ packages:
|
||||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.0"
|
||||
version:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -998,21 +1005,21 @@ packages:
|
||||
name: video_player
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.7"
|
||||
version: "2.2.11"
|
||||
video_player_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.2.0"
|
||||
version: "5.0.1"
|
||||
video_player_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: video_player_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
version: "2.0.6"
|
||||
wakelock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1075,14 +1082,14 @@ packages:
|
||||
name: webview_flutter_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.8.0"
|
||||
version: "2.8.2"
|
||||
webview_flutter_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webview_flutter_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.8.1"
|
||||
webview_flutter_wkwebview:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1096,7 +1103,7 @@ packages:
|
||||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
version: "2.3.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -20,7 +20,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# github action, the current versions are ignored.
|
||||
# - the version number is taken from the git branch release/x.y.z
|
||||
# - the build number is computed by reading the last one from the play store and increased by one
|
||||
version: 1.4.0+24
|
||||
version: 1.4.1+25
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
@@ -48,10 +48,11 @@ dependencies:
|
||||
version: ^2.0.0
|
||||
package_info: ^2.0.2
|
||||
provider: ^6.0.1
|
||||
rive: ^0.7.33
|
||||
rive: ^0.8.1
|
||||
shared_preferences: ^2.0.7
|
||||
table_calendar: ^3.0.2
|
||||
url_launcher: ^6.0.10
|
||||
flutter_barcode_scanner: ^2.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
15
test/fixtures/ingredient_suggestions.json
vendored
Normal file
15
test/fixtures/ingredient_suggestions.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{"suggestions":[
|
||||
{
|
||||
"value": "'n Dry 100% Rapeseed Oil 1 Litre",
|
||||
"data": {
|
||||
"id": 61810,
|
||||
"name": "'n Dry 100% Rapeseed Oil 1 Litre"
|
||||
}},
|
||||
{
|
||||
"value": "100% Apple & Mango",
|
||||
"data": {
|
||||
"id": 61972,
|
||||
"name": "100% Apple & Mango"
|
||||
}
|
||||
}]
|
||||
}
|
||||
25
test/fixtures/search_ingredient_right_code.json
vendored
Normal file
25
test/fixtures/search_ingredient_right_code.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"count":1,
|
||||
"next":null,
|
||||
"previous":null,
|
||||
"results":[
|
||||
{
|
||||
"id":9436,
|
||||
"code":"0013087245950",
|
||||
"name":" Gâteau double chocolat ",
|
||||
"creation_date":"2020-12-20",
|
||||
"update_date":"2020-12-20",
|
||||
"energy":360,
|
||||
"protein":"5.000",
|
||||
"carbohydrates":"45.000",
|
||||
"carbohydrates_sugar":"27.000",
|
||||
"fat":"18.000",
|
||||
"fat_saturated":"4.500",
|
||||
"fibres":"2.000",
|
||||
"sodium":"0.356",
|
||||
"license":5,
|
||||
"license_author":"Open Food Facts",
|
||||
"language":12
|
||||
}
|
||||
]
|
||||
}
|
||||
6
test/fixtures/search_ingredient_wrong_code.json
vendored
Normal file
6
test/fixtures/search_ingredient_wrong_code.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"count":0,
|
||||
"next":null,
|
||||
"previous":null,
|
||||
"results":[]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Mocks generated by Mockito 5.0.16 from annotations
|
||||
// Mocks generated by Mockito 5.0.17 from annotations
|
||||
// in wger/test/gallery/gallery_screen_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
@@ -109,8 +109,6 @@ class MockGalleryProvider extends _i1.Mock implements _i4.GalleryProvider {
|
||||
(super.noSuchMethod(Invocation.method(#deleteRequest, [url, id]),
|
||||
returnValue: Future<_i3.Response>.value(_FakeResponse_3())) as _i6.Future<_i3.Response>);
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
@override
|
||||
void addListener(_i8.VoidCallback? listener) => super
|
||||
.noSuchMethod(Invocation.method(#addListener, [listener]), returnValueForMissingStub: null);
|
||||
@override
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Mocks generated by Mockito 5.0.16 from annotations
|
||||
// Mocks generated by Mockito 5.0.17 from annotations
|
||||
// in wger/test/measurements/measurement_categories_screen_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
@@ -98,8 +98,6 @@ class MockMeasurementProvider extends _i1.Mock implements _i4.MeasurementProvide
|
||||
returnValue: Future<void>.value(),
|
||||
returnValueForMissingStub: Future<void>.value()) as _i5.Future<void>);
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
@override
|
||||
void addListener(_i7.VoidCallback? listener) => super
|
||||
.noSuchMethod(Invocation.method(#addListener, [listener]), returnValueForMissingStub: null);
|
||||
@override
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Mocks generated by Mockito 5.0.16 from annotations
|
||||
// Mocks generated by Mockito 5.0.17 from annotations
|
||||
// in wger/test/measurements/measurement_provider_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
@@ -72,6 +72,4 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider {
|
||||
_i5.Future<_i3.Response> deleteRequest(String? url, int? id) =>
|
||||
(super.noSuchMethod(Invocation.method(#deleteRequest, [url, id]),
|
||||
returnValue: Future<_i3.Response>.value(_FakeResponse_3())) as _i5.Future<_i3.Response>);
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
}
|
||||
|
||||
304
test/nutrition/nutritional_meal_item_form_test.dart
Normal file
304
test/nutrition/nutritional_meal_item_form_test.dart
Normal file
@@ -0,0 +1,304 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/helpers/consts.dart';
|
||||
import 'package:wger/models/nutrition/ingredient.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/nutrition.dart';
|
||||
import 'package:wger/screens/nutritional_plan_screen.dart';
|
||||
import 'package:wger/widgets/nutrition/forms.dart';
|
||||
import '../../test_data/nutritional_plans.dart';
|
||||
|
||||
import '../fixtures/fixture_reader.dart';
|
||||
import '../other/base_provider_test.mocks.dart';
|
||||
import '../utils.dart';
|
||||
import 'nutritional_plan_form_test.mocks.dart';
|
||||
|
||||
void main() {
|
||||
Ingredient ingr = Ingredient(
|
||||
id: 1,
|
||||
code: '123456787',
|
||||
name: 'Water',
|
||||
creationDate: DateTime(2021, 5, 1),
|
||||
energy: 500,
|
||||
carbohydrates: 10,
|
||||
carbohydratesSugar: 2,
|
||||
protein: 5,
|
||||
fat: 20,
|
||||
fatSaturated: 7,
|
||||
fibres: 12,
|
||||
sodium: 0.5,
|
||||
);
|
||||
|
||||
var mockNutrition = MockNutritionPlansProvider();
|
||||
final client = MockClient();
|
||||
final mockNutritionWithClient = NutritionPlansProvider(testAuthProvider, [], client);
|
||||
|
||||
var plan1 = NutritionalPlan.empty();
|
||||
var meal1 = Meal();
|
||||
|
||||
final Uri tUriRightCode = Uri.parse('https://localhost/api/v2/ingredient/?code=123');
|
||||
final Uri tUriEmptyCode = Uri.parse('https://localhost/api/v2/ingredient/?code=\"%20\"');
|
||||
final Uri tUriBadCode = Uri.parse('https://localhost/api/v2/ingredient/?code=222');
|
||||
|
||||
when(client
|
||||
.get(tUriRightCode, headers: {'authorization': 'Token FooBar', 'user-agent': 'wger App'}))
|
||||
.thenAnswer(
|
||||
(_) => Future.value(http.Response(fixture('search_ingredient_right_code.json'), 200)));
|
||||
|
||||
when(client
|
||||
.get(tUriEmptyCode, headers: {'authorization': 'Token FooBar', 'user-agent': 'wger App'}))
|
||||
.thenAnswer(
|
||||
(_) => Future.value(http.Response(fixture('search_ingredient_wrong_code.json'), 200)));
|
||||
|
||||
when(client
|
||||
.get(tUriBadCode, headers: {'authorization': 'Token FooBar', 'user-agent': 'wger App'}))
|
||||
.thenAnswer(
|
||||
(_) => Future.value(http.Response(fixture('search_ingredient_wrong_code.json'), 200)));
|
||||
|
||||
setUp(() {
|
||||
plan1 = getNutritionalPlan();
|
||||
meal1 = plan1.meals.first;
|
||||
final MealItem mealItem = MealItem(ingredientId: ingr.id, amount: 2);
|
||||
mockNutrition = MockNutritionPlansProvider();
|
||||
|
||||
when(mockNutrition.searchIngredientWithCode('123')).thenAnswer((_) => Future.value(ingr));
|
||||
when(mockNutrition.searchIngredientWithCode('')).thenAnswer((_) => Future.value(null));
|
||||
when(mockNutrition.searchIngredientWithCode('222')).thenAnswer((_) => Future.value(null));
|
||||
when(mockNutrition.searchIngredient(any)).thenAnswer(
|
||||
(_) => Future.value(json.decode(fixture('ingredient_suggestions')) as List<dynamic>));
|
||||
|
||||
when(mockNutrition.addMealItem(any, meal1)).thenAnswer((_) => Future.value(mealItem));
|
||||
});
|
||||
|
||||
Widget createMealItemFormScreen(Meal meal, String code, bool test, {locale = 'en'}) {
|
||||
final key = GlobalKey<NavigatorState>();
|
||||
|
||||
return ChangeNotifierProvider<NutritionPlansProvider>(
|
||||
create: (context) => mockNutrition,
|
||||
child: MaterialApp(
|
||||
locale: Locale(locale),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
navigatorKey: key,
|
||||
home: Scaffold(
|
||||
body: MealItemForm(meal, const [], null, code, test),
|
||||
),
|
||||
routes: {
|
||||
NutritionalPlanScreen.routeName: (ctx) => NutritionalPlanScreen(),
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('Test the widgets on the meal item form', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '', true));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TypeAheadFormField), findsOneWidget);
|
||||
expect(find.byType(TextFormField), findsOneWidget);
|
||||
expect(find.byKey(const Key('scan-button')), findsOneWidget);
|
||||
expect(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)), findsOneWidget);
|
||||
|
||||
expect(meal1.mealItems.length, 2);
|
||||
});
|
||||
|
||||
group('Test the AlertDialogs for scanning result', () {
|
||||
testWidgets('with empty code', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '', true));
|
||||
|
||||
await tester.tap(find.byKey(const Key('scan-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(AlertDialog), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('with correct code', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
await tester.tap(find.byKey(const Key('scan-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('found-dialog')), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('with incorrect code', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '222', true));
|
||||
|
||||
await tester.tap(find.byKey(const Key('scan-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('notFound-dialog')), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
group('Test searchIngredientWithCode() function', () {
|
||||
test('with correct code', () async {
|
||||
final Ingredient? ingredient = await mockNutritionWithClient.searchIngredientWithCode('123');
|
||||
expect(ingredient!.id, 9436);
|
||||
});
|
||||
|
||||
test('with incorrect code', () async {
|
||||
final Ingredient? ingredient = await mockNutritionWithClient.searchIngredientWithCode('222');
|
||||
expect(ingredient, null);
|
||||
});
|
||||
|
||||
test('with empty code', () async {
|
||||
final Ingredient? ingredient = await mockNutritionWithClient.searchIngredientWithCode('');
|
||||
expect(ingredient, null);
|
||||
});
|
||||
});
|
||||
|
||||
group('Test weight formfield', () {
|
||||
testWidgets('add empty weight', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
await tester.enterText(find.byKey(const Key('field-weight')), '');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please enter a valid number'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('add correct weight type', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
await tester.enterText(find.byKey(const Key('field-weight')), '2');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please enter a valid number'), findsNothing);
|
||||
});
|
||||
testWidgets('add incorrect weight type', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
await tester.enterText(find.byKey(const Key('field-weight')), 'test');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please enter a valid number'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
group('Test ingredient found dialog', () {
|
||||
testWidgets('confirm found ingredient dialog', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
final MealItemForm formScreen = tester.widget(find.byType(MealItemForm));
|
||||
|
||||
await tester.tap(find.byKey(const Key('scan-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('found-dialog')), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byKey(const Key('found-dialog-confirm-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(formScreen.ingredientIdController.text, '1');
|
||||
});
|
||||
|
||||
testWidgets('close found ingredient dialog', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
await tester.tap(find.byKey(const Key('scan-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('found-dialog')), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byKey(const Key('found-dialog-close-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('found-dialog')), findsNothing);
|
||||
});
|
||||
});
|
||||
|
||||
group('Test the adding a new item to meal', () {
|
||||
testWidgets('save empty ingredient', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please select an ingredient'), findsOneWidget);
|
||||
|
||||
expect(find.text('Please enter a valid number'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('save ingredient without weight', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
await tester.tap(find.byKey(const Key('scan-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('found-dialog')), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byKey(const Key('found-dialog-confirm-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please enter a valid number'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('save ingredient with incorrect weight input type', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
await tester.tap(find.byKey(const Key('scan-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('found-dialog')), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byKey(const Key('found-dialog-confirm-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Please enter a valid number'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('save complete ingredient with correct weight input type',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
|
||||
|
||||
final MealItemForm formScreen = tester.widget(find.byType(MealItemForm));
|
||||
|
||||
await tester.tap(find.byKey(const Key('scan-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('found-dialog')), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byKey(const Key('found-dialog-confirm-button')));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(formScreen.ingredientIdController.text, '1');
|
||||
|
||||
await tester.enterText(find.byKey(const Key('field-weight')), '2');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byKey(const Key('found-dialog')), findsNothing);
|
||||
|
||||
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(formScreen.mealItem.amount, 2);
|
||||
|
||||
verify(mockNutrition.addMealItem(any, meal1));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Mocks generated by Mockito 5.0.16 from annotations
|
||||
// Mocks generated by Mockito 5.0.17 from annotations
|
||||
// in wger/test/nutrition/nutritional_plan_form_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
@@ -193,8 +193,6 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP
|
||||
(super.noSuchMethod(Invocation.method(#deleteRequest, [url, id]),
|
||||
returnValue: Future<_i3.Response>.value(_FakeResponse_7())) as _i9.Future<_i3.Response>);
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
@override
|
||||
void addListener(_i10.VoidCallback? listener) => super
|
||||
.noSuchMethod(Invocation.method(#addListener, [listener]), returnValueForMissingStub: null);
|
||||
@override
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Mocks generated by Mockito 5.0.16 from annotations
|
||||
// Mocks generated by Mockito 5.0.17 from annotations
|
||||
// in wger/test/other/base_provider_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
@@ -81,6 +81,4 @@ class MockClient extends _i1.Mock implements _i4.Client {
|
||||
@override
|
||||
void close() =>
|
||||
super.noSuchMethod(Invocation.method(#close, []), returnValueForMissingStub: null);
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Mocks generated by Mockito 5.0.16 from annotations
|
||||
// Mocks generated by Mockito 5.0.17 from annotations
|
||||
// in wger/test/workout/workout_form_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
@@ -256,8 +256,6 @@ class MockWorkoutPlansProvider extends _i1.Mock implements _i12.WorkoutPlansProv
|
||||
Invocation.method(#deleteRequest, [url, id]),
|
||||
returnValue: Future<_i5.Response>.value(_FakeResponse_11())) as _i13.Future<_i5.Response>);
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
@override
|
||||
void addListener(_i15.VoidCallback? listener) => super
|
||||
.noSuchMethod(Invocation.method(#addListener, [listener]), returnValueForMissingStub: null);
|
||||
@override
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Mocks generated by Mockito 5.0.16 from annotations
|
||||
// Mocks generated by Mockito 5.0.17 from annotations
|
||||
// in wger/test/workout/workout_set_form_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
@@ -116,8 +116,6 @@ class MockExercisesProvider extends _i1.Mock implements _i5.ExercisesProvider {
|
||||
(super.noSuchMethod(Invocation.method(#deleteRequest, [url, id]),
|
||||
returnValue: Future<_i3.Response>.value(_FakeResponse_4())) as _i6.Future<_i3.Response>);
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
@override
|
||||
void addListener(_i7.VoidCallback? listener) => super
|
||||
.noSuchMethod(Invocation.method(#addListener, [listener]), returnValueForMissingStub: null);
|
||||
@override
|
||||
|
||||
@@ -25,6 +25,7 @@ import 'package:wger/models/nutrition/nutritional_plan.dart';
|
||||
|
||||
final ingredient1 = Ingredient(
|
||||
id: 1,
|
||||
code: '123456787',
|
||||
name: 'Water',
|
||||
creationDate: DateTime(2021, 5, 1),
|
||||
energy: 500,
|
||||
@@ -38,6 +39,7 @@ final ingredient1 = Ingredient(
|
||||
);
|
||||
final ingredient2 = Ingredient(
|
||||
id: 2,
|
||||
code: '123456788',
|
||||
name: 'Burger soup',
|
||||
creationDate: DateTime(2021, 5, 10),
|
||||
energy: 25,
|
||||
@@ -51,6 +53,7 @@ final ingredient2 = Ingredient(
|
||||
);
|
||||
final ingredient3 = Ingredient(
|
||||
id: 3,
|
||||
code: '123456789',
|
||||
name: 'Broccoli cake',
|
||||
creationDate: DateTime(2021, 5, 2),
|
||||
energy: 1200,
|
||||
|
||||
Reference in New Issue
Block a user