Fix import for localization strings

This commit is contained in:
Roland Geider
2025-10-19 14:23:58 +02:00
parent 5c44678557
commit 64dc10cdb2
94 changed files with 1446 additions and 1828 deletions

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
@@ -42,8 +42,9 @@ Widget createDashboardScreen({locale = 'en'}) {
final mockNutritionProvider = MockNutritionPlansProvider(); final mockNutritionProvider = MockNutritionPlansProvider();
when(mockNutritionProvider.currentPlan) when(
.thenAnswer((realInvocation) => getNutritionalPlanScreenshot()); mockNutritionProvider.currentPlan,
).thenAnswer((realInvocation) => getNutritionalPlanScreenshot());
when(mockNutritionProvider.items).thenReturn([getNutritionalPlanScreenshot()]); when(mockNutritionProvider.items).thenReturn([getNutritionalPlanScreenshot()]);
final mockWeightProvider = MockBodyWeightProvider(); final mockWeightProvider = MockBodyWeightProvider();
@@ -57,21 +58,11 @@ Widget createDashboardScreen({locale = 'en'}) {
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider<UserProvider>( ChangeNotifierProvider<UserProvider>(create: (context) => mockUserProvider),
create: (context) => mockUserProvider, ChangeNotifierProvider<WorkoutPlansProvider>(create: (context) => mockWorkoutProvider),
), ChangeNotifierProvider<NutritionPlansProvider>(create: (context) => mockNutritionProvider),
ChangeNotifierProvider<WorkoutPlansProvider>( ChangeNotifierProvider<BodyWeightProvider>(create: (context) => mockWeightProvider),
create: (context) => mockWorkoutProvider, ChangeNotifierProvider<MeasurementProvider>(create: (context) => mockMeasurementProvider),
),
ChangeNotifierProvider<NutritionPlansProvider>(
create: (context) => mockNutritionProvider,
),
ChangeNotifierProvider<BodyWeightProvider>(
create: (context) => mockWeightProvider,
),
ChangeNotifierProvider<MeasurementProvider>(
create: (context) => mockMeasurementProvider,
),
], ],
child: MaterialApp( child: MaterialApp(
locale: Locale(locale), locale: Locale(locale),

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/workout_plan_screen.dart'; import 'package:wger/screens/workout_plan_screen.dart';
import 'package:wger/theme/theme.dart'; import 'package:wger/theme/theme.dart';
@@ -20,9 +20,7 @@ Widget createWorkoutDetailScreen({locale = 'en'}) {
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider<WorkoutPlansProvider>( ChangeNotifierProvider<WorkoutPlansProvider>(create: (context) => mockWorkoutProvider),
create: (context) => mockWorkoutProvider,
),
], ],
child: MaterialApp( child: MaterialApp(
locale: Locale(locale), locale: Locale(locale),

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/gym_mode.dart'; import 'package:wger/screens/gym_mode.dart';
@@ -26,11 +26,7 @@ Widget createGymModeScreen({locale = 'en'}) {
//when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(bases[2]); // dead lift //when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(bases[2]); // dead lift
return ChangeNotifierProvider<WorkoutPlansProvider>( return ChangeNotifierProvider<WorkoutPlansProvider>(
create: (context) => WorkoutPlansProvider( create: (context) => WorkoutPlansProvider(mockBaseProvider, mockExerciseProvider, [workout]),
mockBaseProvider,
mockExerciseProvider,
[workout],
),
child: ChangeNotifierProvider<ExercisesProvider>( child: ChangeNotifierProvider<ExercisesProvider>(
create: (context) => mockExerciseProvider, create: (context) => mockExerciseProvider,
child: MaterialApp( child: MaterialApp(
@@ -49,9 +45,7 @@ Widget createGymModeScreen({locale = 'en'}) {
), ),
child: const SizedBox(), child: const SizedBox(),
), ),
routes: { routes: {WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen()},
WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen(),
},
), ),
), ),
); );

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
import 'package:wger/screens/measurement_categories_screen.dart'; import 'package:wger/screens/measurement_categories_screen.dart';
import 'package:wger/theme/theme.dart'; import 'package:wger/theme/theme.dart';
@@ -15,9 +15,7 @@ Widget createMeasurementScreen({locale = 'en'}) {
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider<MeasurementProvider>( ChangeNotifierProvider<MeasurementProvider>(create: (context) => mockMeasurementProvider),
create: (context) => mockMeasurementProvider,
),
], ],
child: MaterialApp( child: MaterialApp(
locale: Locale(locale), locale: Locale(locale),

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/screens/nutritional_plan_screen.dart';

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/providers/user.dart'; import 'package:wger/providers/user.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
@@ -22,12 +22,8 @@ Widget createWeightScreen({locale = 'en'}) {
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider<UserProvider>( ChangeNotifierProvider<UserProvider>(create: (context) => mockUserProvider),
create: (context) => mockUserProvider, ChangeNotifierProvider<BodyWeightProvider>(create: (context) => mockWeightProvider),
),
ChangeNotifierProvider<BodyWeightProvider>(
create: (context) => mockWeightProvider,
),
], ],
child: MaterialApp( child: MaterialApp(
locale: Locale(locale), locale: Locale(locale),

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
/// The amount of characters an exercise description needs to have /// The amount of characters an exercise description needs to have
const MIN_CHARS_DESCRIPTION = 40; const MIN_CHARS_DESCRIPTION = 40;

View File

@@ -7,7 +7,7 @@ library;
/// probably better ways to do this, but that's the way it is right now). /// probably better ways to do this, but that's the way it is right now).
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
String getTranslation(String value, BuildContext context) { String getTranslation(String value, BuildContext context) {
switch (value) { switch (value) {

View File

@@ -19,9 +19,9 @@
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/exercises/translation.dart'; import 'package:wger/models/exercises/translation.dart';
import 'package:wger/models/workouts/log.dart'; import 'package:wger/models/workouts/log.dart';
@@ -50,10 +50,7 @@ void showErrorDialog(dynamic exception, BuildContext context) {
); );
} }
void showHttpExceptionErrorDialog( void showHttpExceptionErrorDialog(WgerHttpException exception, BuildContext context) {
WgerHttpException exception,
BuildContext context,
) {
log('showHttpExceptionErrorDialog: '); log('showHttpExceptionErrorDialog: ');
log(exception.toString()); log(exception.toString());
log('-------------------'); log('-------------------');
@@ -119,9 +116,7 @@ dynamic showDeleteDialog(
context: context, context: context,
builder: (BuildContext contextDialog) { builder: (BuildContext contextDialog) {
return AlertDialog( return AlertDialog(
content: Text( content: Text(AppLocalizations.of(context).confirmDelete(confirmDeleteName)),
AppLocalizations.of(context).confirmDelete(confirmDeleteName),
),
actions: [ actions: [
TextButton( TextButton(
child: Text(MaterialLocalizations.of(context).cancelButtonLabel), child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
@@ -134,9 +129,7 @@ dynamic showDeleteDialog(
), ),
onPressed: () { onPressed: () {
exerciseData[exercise]!.removeWhere((el) => el.id == log.id); exerciseData[exercise]!.removeWhere((el) => el.id == log.id);
Provider.of<WorkoutPlansProvider>(context, listen: false).deleteLog( Provider.of<WorkoutPlansProvider>(context, listen: false).deleteLog(log);
log,
);
Navigator.of(contextDialog).pop(); Navigator.of(contextDialog).pop();

View File

@@ -19,6 +19,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/core/locator.dart'; import 'package:wger/core/locator.dart';
import 'package:wger/powersync.dart'; import 'package:wger/powersync.dart';
@@ -53,8 +54,7 @@ import 'package:wger/screens/workout_plan_screen.dart';
import 'package:wger/screens/workout_plans_screen.dart'; import 'package:wger/screens/workout_plans_screen.dart';
import 'package:wger/theme/theme.dart'; import 'package:wger/theme/theme.dart';
import 'package:wger/widgets/core/about.dart'; import 'package:wger/widgets/core/about.dart';
import 'package:wger/widgets/core/settings.dart'; import 'package:wger/widgets/core/settingsdart';
import 'package:logging/logging.dart';
import 'providers/auth.dart'; import 'providers/auth.dart';
@@ -92,9 +92,8 @@ class MyApp extends StatelessWidget {
providers: [ providers: [
ChangeNotifierProvider(create: (ctx) => AuthProvider()), ChangeNotifierProvider(create: (ctx) => AuthProvider()),
ChangeNotifierProxyProvider<AuthProvider, ExercisesProvider>( ChangeNotifierProxyProvider<AuthProvider, ExercisesProvider>(
create: (context) => ExercisesProvider( create: (context) =>
WgerBaseProvider(Provider.of(context, listen: false)), ExercisesProvider(WgerBaseProvider(Provider.of(context, listen: false))),
),
update: (context, base, previous) => update: (context, base, previous) =>
previous ?? ExercisesProvider(WgerBaseProvider(base)), previous ?? ExercisesProvider(WgerBaseProvider(base)),
), ),
@@ -108,44 +107,34 @@ class MyApp extends StatelessWidget {
previous ?? WorkoutPlansProvider(WgerBaseProvider(auth), exercises, []), previous ?? WorkoutPlansProvider(WgerBaseProvider(auth), exercises, []),
), ),
ChangeNotifierProxyProvider<AuthProvider, NutritionPlansProvider>( ChangeNotifierProxyProvider<AuthProvider, NutritionPlansProvider>(
create: (context) => NutritionPlansProvider( create: (context) =>
WgerBaseProvider(Provider.of(context, listen: false)), NutritionPlansProvider(WgerBaseProvider(Provider.of(context, listen: false)), []),
[],
),
update: (context, auth, previous) => update: (context, auth, previous) =>
previous ?? NutritionPlansProvider(WgerBaseProvider(auth), []), previous ?? NutritionPlansProvider(WgerBaseProvider(auth), []),
), ),
ChangeNotifierProxyProvider<AuthProvider, MeasurementProvider>( ChangeNotifierProxyProvider<AuthProvider, MeasurementProvider>(
create: (context) => MeasurementProvider( create: (context) =>
WgerBaseProvider(Provider.of(context, listen: false)), MeasurementProvider(WgerBaseProvider(Provider.of(context, listen: false))),
),
update: (context, base, previous) => update: (context, base, previous) =>
previous ?? MeasurementProvider(WgerBaseProvider(base)), previous ?? MeasurementProvider(WgerBaseProvider(base)),
), ),
ChangeNotifierProxyProvider<AuthProvider, UserProvider>( ChangeNotifierProxyProvider<AuthProvider, UserProvider>(
create: (context) => UserProvider( create: (context) => UserProvider(WgerBaseProvider(Provider.of(context, listen: false))),
WgerBaseProvider(Provider.of(context, listen: false)),
),
update: (context, base, previous) => previous ?? UserProvider(WgerBaseProvider(base)), update: (context, base, previous) => previous ?? UserProvider(WgerBaseProvider(base)),
), ),
ChangeNotifierProxyProvider<AuthProvider, BodyWeightProvider>( ChangeNotifierProxyProvider<AuthProvider, BodyWeightProvider>(
create: (context) => BodyWeightProvider( create: (context) =>
WgerBaseProvider(Provider.of(context, listen: false)), BodyWeightProvider(WgerBaseProvider(Provider.of(context, listen: false))),
),
update: (context, base, previous) => update: (context, base, previous) =>
previous ?? BodyWeightProvider(WgerBaseProvider(base)), previous ?? BodyWeightProvider(WgerBaseProvider(base)),
), ),
ChangeNotifierProxyProvider<AuthProvider, GalleryProvider>( ChangeNotifierProxyProvider<AuthProvider, GalleryProvider>(
create: (context) => GalleryProvider( create: (context) => GalleryProvider(Provider.of(context, listen: false), []),
Provider.of(context, listen: false),
[],
),
update: (context, auth, previous) => previous ?? GalleryProvider(auth, []), update: (context, auth, previous) => previous ?? GalleryProvider(auth, []),
), ),
ChangeNotifierProxyProvider<AuthProvider, AddExerciseProvider>( ChangeNotifierProxyProvider<AuthProvider, AddExerciseProvider>(
create: (context) => AddExerciseProvider( create: (context) =>
WgerBaseProvider(Provider.of(context, listen: false)), AddExerciseProvider(WgerBaseProvider(Provider.of(context, listen: false))),
),
update: (context, base, previous) => update: (context, base, previous) =>
previous ?? AddExerciseProvider(WgerBaseProvider(base)), previous ?? AddExerciseProvider(WgerBaseProvider(base)),
), ),
@@ -164,8 +153,8 @@ class MyApp extends StatelessWidget {
future: auth.tryAutoLogin(), future: auth.tryAutoLogin(),
builder: (ctx, authResultSnapshot) => builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState == ConnectionState.waiting authResultSnapshot.connectionState == ConnectionState.waiting
? const SplashScreen() ? const SplashScreen()
: const AuthScreen(), : const AuthScreen(),
), ),
routes: { routes: {
DashboardScreen.routeName: (ctx) => const DashboardScreen(), DashboardScreen.routeName: (ctx) => const DashboardScreen(),

View File

@@ -18,11 +18,11 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:powersync/sqlite3.dart' as sqlite; import 'package:powersync/sqlite3.dart' as sqlite;
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/json.dart'; import 'package:wger/helpers/json.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/log.dart'; import 'package:wger/models/nutrition/log.dart';
import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal.dart';
import 'package:wger/models/nutrition/meal_item.dart'; import 'package:wger/models/nutrition/meal_item.dart';
@@ -128,10 +128,7 @@ class NutritionalPlan {
} }
Future<NutritionalPlan> loadChildren() async { Future<NutritionalPlan> loadChildren() async {
return copyWith( return copyWith(diaryEntries: await Log.readByPlanId(id!), meals: await Meal.readByPlanId(id!));
diaryEntries: await Log.readByPlanId(id!),
meals: await Meal.readByPlanId(id!),
);
} }
NutritionalPlan.empty() { NutritionalPlan.empty() {
@@ -186,10 +183,7 @@ class NutritionalPlan {
return NutritionalGoals(); return NutritionalGoals();
} }
// otherwise, add up all the nutritional values of the meals and use that as goals // otherwise, add up all the nutritional values of the meals and use that as goals
final sumValues = meals.fold( final sumValues = meals.fold(NutritionalValues(), (a, b) => a + b.plannedNutritionalValues);
NutritionalValues(),
(a, b) => a + b.plannedNutritionalValues,
);
return NutritionalGoals( return NutritionalGoals(
energy: sumValues.energy, energy: sumValues.energy,
fat: sumValues.fat, fat: sumValues.fat,
@@ -304,21 +298,21 @@ class NutritionalPlan {
return NutritionalPlan.fromRow(row).loadChildren(); return NutritionalPlan.fromRow(row).loadChildren();
} }
// this is a bit complicated. // this is a bit complicated.
// what we need at the end of the day, is a stream of List<NutritionPlan>, where // what we need at the end of the day, is a stream of List<NutritionPlan>, where
// a new value is emitted any time a plan is changed. But the plan is not just the plan record // a new value is emitted any time a plan is changed. But the plan is not just the plan record
// we need to load data for Logs and Meals corresponding to the plan also. // we need to load data for Logs and Meals corresponding to the plan also.
// so our options are: // so our options are:
// 1) db.watch with a select query on plans; and extra dart code to load the logs/meals stuff, // 1) db.watch with a select query on plans; and extra dart code to load the logs/meals stuff,
// but this only triggers for updates on the plans table, and misses logs/meals updates // but this only triggers for updates on the plans table, and misses logs/meals updates
// 2) db.watch with a huge join query across all tables from which we need info, // 2) db.watch with a huge join query across all tables from which we need info,
// so we have all the data in our resultset to create the datastructures with, but: // so we have all the data in our resultset to create the datastructures with, but:
// - this creates long rows with lots of duplicated data (e.g. all the plan data) for every row // - this creates long rows with lots of duplicated data (e.g. all the plan data) for every row
// which would only differ for e.g. the meal or the log item // which would only differ for e.g. the meal or the log item
// - it would probably get a bit messy to parse the resultset into the datastructures // - it would probably get a bit messy to parse the resultset into the datastructures
// 3) the best of both worlds: load the data we need in dart at runtime, but explicitly // 3) the best of both worlds: load the data we need in dart at runtime, but explicitly
// trigger our code execution when *any* of the relevant tables changes // trigger our code execution when *any* of the relevant tables changes
// //
static Stream<List<NutritionalPlan>> watchNutritionPlans() { static Stream<List<NutritionalPlan>> watchNutritionPlans() {
return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async { return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async {
final data = await db.getAll('SELECT * FROM $tableNutritionPlans ORDER BY creation_date'); final data = await db.getAll('SELECT * FROM $tableNutritionPlans ORDER BY creation_date');
@@ -336,15 +330,16 @@ class NutritionalPlan {
static Stream<NutritionalPlan?> watchNutritionPlanLast() { static Stream<NutritionalPlan?> watchNutritionPlanLast() {
return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async { return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async {
final res = final res = await db.getAll(
await db.getAll('SELECT * FROM $tableNutritionPlans ORDER BY creation_date DESC LIMIT 1'); 'SELECT * FROM $tableNutritionPlans ORDER BY creation_date DESC LIMIT 1',
);
if (res.isEmpty) { if (res.isEmpty) {
return null; return null;
} }
return NutritionalPlan.fromRow(res.first).loadChildren(); return NutritionalPlan.fromRow(res.first).loadChildren();
}); });
} }
/* /*
static Stream<List<NutritionalPlan>> watchNutritionPlan(int id) { static Stream<List<NutritionalPlan>> watchNutritionPlan(int id) {
return db return db
.watch('SELECT * FROM $tableNutritionPlans WHERE id = ?', parameters: [id]).map((results) { .watch('SELECT * FROM $tableNutritionPlans WHERE id = ?', parameters: [id]).map((results) {

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/add_exercise.dart'; import 'package:wger/providers/add_exercise.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/user.dart'; import 'package:wger/providers/user.dart';
@@ -76,9 +76,7 @@ class _AddExerciseStepperState extends State<AddExerciseStepper> {
final baseId = await addExerciseProvider.addExercise(); final baseId = await addExerciseProvider.addExercise();
final base = await exerciseProvider.fetchAndSetExercise(baseId); final base = await exerciseProvider.fetchAndSetExercise(baseId);
final name = base final name = base
.getExercise( .getExercise(Localizations.localeOf(context).languageCode)
Localizations.localeOf(context).languageCode,
)
.name; .name;
setState(() { setState(() {
@@ -91,9 +89,7 @@ class _AddExerciseStepperState extends State<AddExerciseStepper> {
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return AlertDialog(
title: Text(AppLocalizations.of(context).success), title: Text(AppLocalizations.of(context).success),
content: Text( content: Text(AppLocalizations.of(context).cacheWarning),
AppLocalizations.of(context).cacheWarning,
),
actions: [ actions: [
TextButton( TextButton(
child: Text(name), child: Text(name),
@@ -112,11 +108,7 @@ class _AddExerciseStepperState extends State<AddExerciseStepper> {
); );
}, },
child: _isLoading child: _isLoading
? const SizedBox( ? const SizedBox(height: 20, width: 20, child: CircularProgressIndicator())
height: 20,
width: 20,
child: CircularProgressIndicator(),
)
: Text(AppLocalizations.of(context).save), : Text(AppLocalizations.of(context).save),
) )
else else
@@ -207,8 +199,11 @@ class EmailNotVerified extends StatelessWidget {
ListTile( ListTile(
leading: const Icon(Icons.warning), leading: const Icon(Icons.warning),
title: Text(AppLocalizations.of(context).unVerifiedEmail), title: Text(AppLocalizations.of(context).unVerifiedEmail),
subtitle: Text(AppLocalizations.of(context) subtitle: Text(
.contributeExerciseWarning(MIN_ACCOUNT_AGE.toString())), AppLocalizations.of(
context,
).contributeExerciseWarning(MIN_ACCOUNT_AGE.toString()),
),
), ),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,

View File

@@ -19,21 +19,18 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/misc.dart'; import 'package:wger/helpers/misc.dart';
import 'package:wger/helpers/ui.dart'; import 'package:wger/helpers/ui.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/screens/update_app_screen.dart'; import 'package:wger/screens/update_app_screen.dart';
import 'package:wger/theme/theme.dart'; import 'package:wger/theme/theme.dart';
import '../providers/auth.dart'; import '../providers/auth.dart';
enum AuthMode { enum AuthMode { Signup, Login }
Signup,
Login,
}
class AuthScreen extends StatelessWidget { class AuthScreen extends StatelessWidget {
const AuthScreen(); const AuthScreen();
@@ -50,10 +47,7 @@ class AuthScreen extends StatelessWidget {
top: 0, top: 0,
right: 0, right: 0,
left: 0, left: 0,
child: Container( child: Container(height: 0.55 * deviceSize.height, color: wgerPrimaryColor),
height: 0.55 * deviceSize.height,
color: wgerPrimaryColor,
),
), ),
SingleChildScrollView( SingleChildScrollView(
child: SizedBox( child: SizedBox(
@@ -64,16 +58,10 @@ class AuthScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
SizedBox(height: 0.15 * deviceSize.height), SizedBox(height: 0.15 * deviceSize.height),
const Image( const Image(image: AssetImage('assets/images/logo-white.png'), width: 85),
image: AssetImage('assets/images/logo-white.png'),
width: 85,
),
Container( Container(
margin: const EdgeInsets.only(bottom: 20.0), margin: const EdgeInsets.only(bottom: 20.0),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 94.0),
vertical: 8.0,
horizontal: 94.0,
),
child: const Text( child: const Text(
'wger', 'wger',
style: TextStyle( style: TextStyle(
@@ -190,11 +178,10 @@ class _AuthCardState extends State<AuthCard> {
// Login existing user // Login existing user
late Map<String, LoginActions> res; late Map<String, LoginActions> res;
if (_authMode == AuthMode.Login) { if (_authMode == AuthMode.Login) {
res = await Provider.of<AuthProvider>(context, listen: false).login( res = await Provider.of<AuthProvider>(
_authData['username']!, context,
_authData['password']!, listen: false,
_authData['serverUrl']!, ).login(_authData['username']!, _authData['password']!, _authData['serverUrl']!);
);
// Register new user // Register new user
} else { } else {
@@ -210,9 +197,9 @@ class _AuthCardState extends State<AuthCard> {
// Check if update is required else continue normally // Check if update is required else continue normally
if (res.containsKey('action')) { if (res.containsKey('action')) {
if (res['action'] == LoginActions.update && mounted) { if (res['action'] == LoginActions.update && mounted) {
Navigator.of(context).push( Navigator.of(
MaterialPageRoute(builder: (context) => const UpdateAppScreen()), context,
); ).push(MaterialPageRoute(builder: (context) => const UpdateAppScreen()));
return; return;
} }
} }
@@ -260,16 +247,11 @@ class _AuthCardState extends State<AuthCard> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size; final deviceSize = MediaQuery.of(context).size;
return Card( return Card(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
borderRadius: BorderRadius.circular(15.0),
),
elevation: 8.0, elevation: 8.0,
child: Container( child: Container(
width: deviceSize.width * 0.9, width: deviceSize.width * 0.9,
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 0.025 * deviceSize.height),
horizontal: 15.0,
vertical: 0.025 * deviceSize.height,
),
child: Form( child: Form(
key: _formKey, key: _formKey,
child: SingleChildScrollView( child: SingleChildScrollView(
@@ -297,9 +279,7 @@ class _AuthCardState extends State<AuthCard> {
return null; return null;
}, },
inputFormatters: [ inputFormatters: [FilteringTextInputFormatter.deny(RegExp(r'\s\b|\b\s'))],
FilteringTextInputFormatter.deny(RegExp(r'\s\b|\b\s')),
],
onSaved: (value) { onSaved: (value) {
_authData['username'] = value!; _authData['username'] = value!;
}, },
@@ -327,63 +307,69 @@ class _AuthCardState extends State<AuthCard> {
_authData['email'] = value!; _authData['email'] = value!;
}, },
), ),
StatefulBuilder(builder: (context, updateState) { StatefulBuilder(
return TextFormField( builder: (context, updateState) {
key: const Key('inputPassword'),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).password,
prefixIcon: const Icon(Icons.password),
suffixIcon: IconButton(
icon: Icon(isObscure ? Icons.visibility_off : Icons.visibility),
onPressed: () {
isObscure = !isObscure;
updateState(() {});
},
),
),
autofillHints: const [AutofillHints.password],
obscureText: isObscure,
controller: _passwordController,
textInputAction: TextInputAction.next,
validator: (value) {
if (value!.isEmpty || value.length < 8) {
return AppLocalizations.of(context).passwordTooShort;
}
return null;
},
onSaved: (value) {
_authData['password'] = value!;
},
);
}),
if (_authMode == AuthMode.Signup)
StatefulBuilder(builder: (context, updateState) {
return TextFormField( return TextFormField(
key: const Key('inputPassword2'), key: const Key('inputPassword'),
decoration: InputDecoration( decoration: InputDecoration(
labelText: AppLocalizations.of(context).confirmPassword, labelText: AppLocalizations.of(context).password,
prefixIcon: const Icon(Icons.password), prefixIcon: const Icon(Icons.password),
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon(confirmIsObscure ? Icons.visibility_off : Icons.visibility), icon: Icon(isObscure ? Icons.visibility_off : Icons.visibility),
onPressed: () { onPressed: () {
confirmIsObscure = !confirmIsObscure; isObscure = !isObscure;
updateState(() {}); updateState(() {});
}, },
), ),
), ),
controller: _password2Controller, autofillHints: const [AutofillHints.password],
enabled: _authMode == AuthMode.Signup, obscureText: isObscure,
obscureText: confirmIsObscure, controller: _passwordController,
validator: _authMode == AuthMode.Signup textInputAction: TextInputAction.next,
? (value) { validator: (value) {
if (value != _passwordController.text) { if (value!.isEmpty || value.length < 8) {
return AppLocalizations.of(context).passwordsDontMatch; return AppLocalizations.of(context).passwordTooShort;
} }
return null; return null;
} },
: null, onSaved: (value) {
_authData['password'] = value!;
},
); );
}), },
),
if (_authMode == AuthMode.Signup)
StatefulBuilder(
builder: (context, updateState) {
return TextFormField(
key: const Key('inputPassword2'),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).confirmPassword,
prefixIcon: const Icon(Icons.password),
suffixIcon: IconButton(
icon: Icon(
confirmIsObscure ? Icons.visibility_off : Icons.visibility,
),
onPressed: () {
confirmIsObscure = !confirmIsObscure;
updateState(() {});
},
),
),
controller: _password2Controller,
enabled: _authMode == AuthMode.Signup,
obscureText: confirmIsObscure,
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return AppLocalizations.of(context).passwordsDontMatch;
}
return null;
}
: null,
);
},
),
// Off-stage widgets are kept in the tree, otherwise the server URL // Off-stage widgets are kept in the tree, otherwise the server URL
// would not be saved to _authData // would not be saved to _authData
Offstage( Offstage(
@@ -426,8 +412,9 @@ class _AuthCardState extends State<AuthCard> {
IconButton( IconButton(
icon: const Icon(Icons.undo), icon: const Icon(Icons.undo),
onPressed: () { onPressed: () {
_serverUrlController.text = _serverUrlController.text = kDebugMode
kDebugMode ? DEFAULT_SERVER_TEST : DEFAULT_SERVER_PROD; ? DEFAULT_SERVER_TEST
: DEFAULT_SERVER_PROD;
}, },
), ),
Text(AppLocalizations.of(context).reset), Text(AppLocalizations.of(context).reset),
@@ -485,14 +472,9 @@ class _AuthCardState extends State<AuthCard> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text(text.substring(0, text.lastIndexOf('?') + 1)),
Text( Text(
text.substring(0, text.lastIndexOf('?') + 1), text.substring(text.lastIndexOf('?') + 1, text.length),
),
Text(
text.substring(
text.lastIndexOf('?') + 1,
text.length,
),
style: const TextStyle( style: const TextStyle(
//color: wgerPrimaryColor, //color: wgerPrimaryColor,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,

View File

@@ -20,6 +20,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:wger/l10n/generatedapp_localizations.dart';
import 'package:wger/models/muscle.dart'; import 'package:wger/models/muscle.dart';
import 'package:wger/widgets/core/app_bar.dart'; import 'package:wger/widgets/core/app_bar.dart';
import 'package:wger/widgets/dashboard/calendar.dart'; import 'package:wger/widgets/dashboard/calendar.dart';
@@ -90,9 +91,8 @@ class _DashboardMuscleWidgetState extends State<DashboardMuscleWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
color: Colors.brown, color: Colors.brown,
child: Column( child: Column(children: [Text('muscles'), ..._data.map((e) => Text(e.name)).toList()]),
children: [Text('muscles'), ..._data.map((e) => Text(e.name)).toList()], );
));
} }
} }

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/widgets/core/app_bar.dart'; import 'package:wger/widgets/core/app_bar.dart';
@@ -43,11 +43,7 @@ class _ExercisesScreenState extends State<ExercisesScreen> {
Expanded( Expanded(
child: exercisesList.isEmpty child: exercisesList.isEmpty
? const Center( ? const Center(
child: SizedBox( child: SizedBox(height: 100, width: 100, child: CircularProgressIndicator()),
height: 100,
width: 100,
child: CircularProgressIndicator(),
),
) )
: _ExercisesList(exerciseBaseList: exercisesList), : _ExercisesList(exerciseBaseList: exercisesList),
), ),

View File

@@ -17,9 +17,9 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/platform.dart'; import 'package:wger/helpers/platform.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/gallery.dart'; import 'package:wger/providers/gallery.dart';
import 'package:wger/widgets/core/app_bar.dart'; import 'package:wger/widgets/core/app_bar.dart';
import 'package:wger/widgets/gallery/forms.dart'; import 'package:wger/widgets/gallery/forms.dart';

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:rive/rive.dart'; import 'package:rive/rive.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/powersync.dart'; import 'package:wger/powersync.dart';
import 'package:wger/providers/auth.dart'; import 'package:wger/providers/auth.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/widgets/nutrition/meal.dart'; import 'package:wger/widgets/nutrition/meal.dart';
@@ -59,10 +59,7 @@ class _LogMealScreenState extends State<LogMealScreen> {
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
child: Column( child: Column(
children: [ children: [
Text( Text(meal.name, style: Theme.of(context).textTheme.headlineSmall),
meal.name,
style: Theme.of(context).textTheme.headlineSmall,
),
if (meal.mealItems.isEmpty) if (meal.mealItems.isEmpty)
ListTile(title: Text(AppLocalizations.of(context).noIngredientsDefined)) ListTile(title: Text(AppLocalizations.of(context).noIngredientsDefined))
else else
@@ -114,9 +111,7 @@ class _LogMealScreenState extends State<LogMealScreen> {
}, },
), ),
TextButton( TextButton(
child: Text( child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
MaterialLocalizations.of(context).cancelButtonLabel,
),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
], ],

View File

@@ -17,7 +17,7 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/widgets/nutrition/meal.dart'; import 'package:wger/widgets/nutrition/meal.dart';
@@ -37,17 +37,11 @@ class _LogMealsScreenState extends State<LogMealsScreen> {
final nutritionalPlan = ModalRoute.of(context)!.settings.arguments as NutritionalPlan; final nutritionalPlan = ModalRoute.of(context)!.settings.arguments as NutritionalPlan;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: Text(AppLocalizations.of(context).selectMealToLog)),
title: Text(AppLocalizations.of(context).selectMealToLog),
),
body: ListView.builder( body: ListView.builder(
itemCount: nutritionalPlan.meals.length, itemCount: nutritionalPlan.meals.length,
itemBuilder: (context, index) => MealWidget( itemBuilder: (context, index) =>
nutritionalPlan.meals[index], MealWidget(nutritionalPlan.meals[index], nutritionalPlan.dedupMealItems, true, true),
nutritionalPlan.dedupMealItems,
true,
true,
),
), ),
); );
} }

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
import 'package:wger/widgets/measurements/categories.dart'; import 'package:wger/widgets/measurements/categories.dart';

View File

@@ -17,17 +17,14 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
import 'package:wger/widgets/measurements/entries.dart'; import 'package:wger/widgets/measurements/entries.dart';
import 'package:wger/widgets/measurements/forms.dart'; import 'package:wger/widgets/measurements/forms.dart';
enum MeasurementOptions { enum MeasurementOptions { edit, delete }
edit,
delete,
}
class MeasurementEntriesScreen extends StatelessWidget { class MeasurementEntriesScreen extends StatelessWidget {
const MeasurementEntriesScreen(); const MeasurementEntriesScreen();
@@ -62,9 +59,7 @@ class MeasurementEntriesScreen extends StatelessWidget {
context: context, context: context,
builder: (BuildContext contextDialog) { builder: (BuildContext contextDialog) {
return AlertDialog( return AlertDialog(
content: Text( content: Text(AppLocalizations.of(context).confirmDelete(category.name)),
AppLocalizations.of(context).confirmDelete(category.name),
),
actions: [ actions: [
TextButton( TextButton(
child: Text(MaterialLocalizations.of(context).cancelButtonLabel), child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
@@ -73,9 +68,7 @@ class MeasurementEntriesScreen extends StatelessWidget {
TextButton( TextButton(
child: Text( child: Text(
AppLocalizations.of(context).delete, AppLocalizations.of(context).delete,
style: TextStyle( style: TextStyle(color: Theme.of(context).colorScheme.error),
color: Theme.of(context).colorScheme.error,
),
), ),
onPressed: () { onPressed: () {
// Confirmed, delete the workout // Confirmed, delete the workout

View File

@@ -19,9 +19,9 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_svg_icons/flutter_svg_icons.dart'; import 'package:flutter_svg_icons/flutter_svg_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
@@ -29,10 +29,7 @@ import 'package:wger/screens/log_meals_screen.dart';
import 'package:wger/widgets/nutrition/forms.dart'; import 'package:wger/widgets/nutrition/forms.dart';
import 'package:wger/widgets/nutrition/nutritional_plan_detail.dart'; import 'package:wger/widgets/nutrition/nutritional_plan_detail.dart';
enum NutritionalPlanOptions { enum NutritionalPlanOptions { edit, delete }
edit,
delete,
}
class NutritionalPlanScreen extends StatefulWidget { class NutritionalPlanScreen extends StatefulWidget {
const NutritionalPlanScreen(); const NutritionalPlanScreen();
@@ -52,8 +49,10 @@ class _NutritionalPlanScreenState extends State<NutritionalPlanScreen> {
final id = ModalRoute.of(context)!.settings.arguments as String; final id = ModalRoute.of(context)!.settings.arguments as String;
//final id = 111; //final id = 111;
final stream = final stream = Provider.of<NutritionPlansProvider>(
Provider.of<NutritionPlansProvider>(context, listen: false).watchNutritionPlan(id); context,
listen: false,
).watchNutritionPlan(id);
_subscription = stream.listen((plan) { _subscription = stream.listen((plan) {
if (!context.mounted) { if (!context.mounted) {
return; return;
@@ -105,10 +104,7 @@ class _NutritionalPlanScreenState extends State<NutritionalPlanScreen> {
heroTag: null, heroTag: null,
tooltip: AppLocalizations.of(context).logMeal, tooltip: AppLocalizations.of(context).logMeal,
onPressed: () { onPressed: () {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(LogMealsScreen.routeName, arguments: _plan);
LogMealsScreen.routeName,
arguments: _plan,
);
}, },
child: const SvgIcon( child: const SvgIcon(
icon: SvgIconData('assets/icons/meal-diary.svg'), icon: SvgIconData('assets/icons/meal-diary.svg'),
@@ -128,9 +124,7 @@ class _NutritionalPlanScreenState extends State<NutritionalPlanScreen> {
actions: [ actions: [
if (!_plan!.onlyLogging) if (!_plan!.onlyLogging)
IconButton( IconButton(
icon: const SvgIcon( icon: const SvgIcon(icon: SvgIconData('assets/icons/meal-add.svg')),
icon: SvgIconData('assets/icons/meal-add.svg'),
),
onPressed: () { onPressed: () {
Navigator.pushNamed( Navigator.pushNamed(
context, context,
@@ -158,8 +152,10 @@ class _NutritionalPlanScreenState extends State<NutritionalPlanScreen> {
); );
break; break;
case NutritionalPlanOptions.delete: case NutritionalPlanOptions.delete:
Provider.of<NutritionPlansProvider>(context, listen: false) Provider.of<NutritionPlansProvider>(
.deletePlan(_plan!.id!); context,
listen: false,
).deletePlan(_plan!.id!);
Navigator.of(context).pop(); Navigator.of(context).pop();
break; break;
} }
@@ -189,8 +185,9 @@ class _NutritionalPlanScreenState extends State<NutritionalPlanScreen> {
titlePadding: const EdgeInsets.fromLTRB(56, 0, 56, 16), titlePadding: const EdgeInsets.fromLTRB(56, 0, 56, 16),
title: Text( title: Text(
_plan!.getLabel(context), _plan!.getLabel(context),
style: style: Theme.of(
Theme.of(context).textTheme.titleLarge?.copyWith(color: appBarForeground), context,
).textTheme.titleLarge?.copyWith(color: appBarForeground),
), ),
), ),
), ),
@@ -198,22 +195,17 @@ class _NutritionalPlanScreenState extends State<NutritionalPlanScreen> {
future: NutritionalPlan.read(_plan!.id!), future: NutritionalPlan.read(_plan!.id!),
builder: (context, AsyncSnapshot<NutritionalPlan> snapshot) => builder: (context, AsyncSnapshot<NutritionalPlan> snapshot) =>
snapshot.connectionState == ConnectionState.waiting snapshot.connectionState == ConnectionState.waiting
? SliverList( ? SliverList(
delegate: SliverChildListDelegate( delegate: SliverChildListDelegate([
[ const SizedBox(
const SizedBox( height: 200,
height: 200, child: Center(child: CircularProgressIndicator()),
child: Center(
child: CircularProgressIndicator(),
),
),
],
),
)
: Consumer<NutritionPlansProvider>(
builder: (context, value, child) =>
NutritionalPlanDetailWidget(_plan!),
), ),
]),
)
: Consumer<NutritionPlansProvider>(
builder: (context, value, child) => NutritionalPlanDetailWidget(_plan!),
),
), ),
], ],
), ),

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
import 'package:wger/widgets/core/app_bar.dart'; import 'package:wger/widgets/core/app_bar.dart';

View File

@@ -17,7 +17,7 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
class UpdateAppScreen extends StatelessWidget { class UpdateAppScreen extends StatelessWidget {
const UpdateAppScreen(); const UpdateAppScreen();

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
import 'package:wger/widgets/core/app_bar.dart'; import 'package:wger/widgets/core/app_bar.dart';

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/workout_plan.dart'; import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
@@ -27,15 +27,9 @@ import 'package:wger/widgets/workouts/forms.dart';
import 'package:wger/widgets/workouts/workout_logs.dart'; import 'package:wger/widgets/workouts/workout_logs.dart';
import 'package:wger/widgets/workouts/workout_plan_detail.dart'; import 'package:wger/widgets/workouts/workout_plan_detail.dart';
enum WorkoutScreenMode { enum WorkoutScreenMode { workout, log }
workout,
log,
}
enum WorkoutOptions { enum WorkoutOptions { edit, delete }
edit,
delete,
}
class WorkoutPlanScreen extends StatefulWidget { class WorkoutPlanScreen extends StatefulWidget {
const WorkoutPlanScreen(); const WorkoutPlanScreen();
@@ -55,8 +49,10 @@ class _WorkoutPlanScreenState extends State<WorkoutPlanScreen> {
} }
Future<WorkoutPlan> _loadFullWorkout(BuildContext context, int planId) { Future<WorkoutPlan> _loadFullWorkout(BuildContext context, int planId) {
return Provider.of<WorkoutPlansProvider>(context, listen: false) return Provider.of<WorkoutPlansProvider>(
.fetchAndSetWorkoutPlanFull(planId); context,
listen: false,
).fetchAndSetWorkoutPlanFull(planId);
} }
Widget getBody(WorkoutPlan plan) { Widget getBody(WorkoutPlan plan) {
@@ -105,8 +101,10 @@ class _WorkoutPlanScreenState extends State<WorkoutPlanScreen> {
// Delete // Delete
} else if (value == WorkoutOptions.delete) { } else if (value == WorkoutOptions.delete) {
Provider.of<WorkoutPlansProvider>(context, listen: false) Provider.of<WorkoutPlansProvider>(
.deleteWorkout(workoutPlan.id!); context,
listen: false,
).deleteWorkout(workoutPlan.id!);
Navigator.of(context).pop(); Navigator.of(context).pop();
// Toggle Mode // Toggle Mode
@@ -131,19 +129,14 @@ class _WorkoutPlanScreenState extends State<WorkoutPlanScreen> {
FutureBuilder( FutureBuilder(
future: _loadFullWorkout(context, workoutPlan.id!), future: _loadFullWorkout(context, workoutPlan.id!),
builder: (context, AsyncSnapshot<WorkoutPlan> snapshot) => SliverList( builder: (context, AsyncSnapshot<WorkoutPlan> snapshot) => SliverList(
delegate: SliverChildListDelegate( delegate: SliverChildListDelegate([
[ if (snapshot.connectionState == ConnectionState.waiting)
if (snapshot.connectionState == ConnectionState.waiting) const SizedBox(height: 200, child: Center(child: CircularProgressIndicator()))
const SizedBox( else
height: 200, Consumer<WorkoutPlansProvider>(
child: Center(child: CircularProgressIndicator()), builder: (context, value, child) => getBody(workoutPlan),
) ),
else ]),
Consumer<WorkoutPlansProvider>(
builder: (context, value, child) => getBody(workoutPlan),
),
],
),
), ),
), ),
], ],

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/workout_plan.dart'; import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';

View File

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/exercises/forms.dart'; import 'package:wger/helpers/exercises/forms.dart';
import 'package:wger/helpers/i18n.dart'; import 'package:wger/helpers/i18n.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/category.dart'; import 'package:wger/models/exercises/category.dart';
import 'package:wger/models/exercises/equipment.dart'; import 'package:wger/models/exercises/equipment.dart';
import 'package:wger/models/exercises/muscle.dart'; import 'package:wger/models/exercises/muscle.dart';

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/add_exercise.dart'; import 'package:wger/providers/add_exercise.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
@@ -40,9 +40,7 @@ class Step2Variations extends StatelessWidget {
...exerciseProvider.exerciseBasesByVariation[key]!.map( ...exerciseProvider.exerciseBasesByVariation[key]!.map(
(base) => Text( (base) => Text(
base base
.getExercise( .getExercise(Localizations.localeOf(context).languageCode)
Localizations.localeOf(context).languageCode,
)
.name, .name,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@@ -61,7 +59,9 @@ class Step2Variations extends StatelessWidget {
), ),
), ),
// Exercise bases without variations // Exercise bases without variations
...exerciseProvider.exercises.where((b) => b.variationId == null).map( ...exerciseProvider.exercises
.where((b) => b.variationId == null)
.map(
(base) => Row( (base) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@@ -72,9 +72,7 @@ class Step2Variations extends StatelessWidget {
children: [ children: [
Text( Text(
base base
.getExercise( .getExercise(Localizations.localeOf(context).languageCode)
Localizations.localeOf(context).languageCode,
)
.name, .name,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/exercises/forms.dart'; import 'package:wger/helpers/exercises/forms.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/add_exercise.dart'; import 'package:wger/providers/add_exercise.dart';
import 'package:wger/widgets/add_exercise/add_exercise_text_area.dart'; import 'package:wger/widgets/add_exercise/add_exercise_text_area.dart';

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/exercises/forms.dart'; import 'package:wger/helpers/exercises/forms.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/language.dart'; import 'package:wger/models/exercises/language.dart';
import 'package:wger/providers/add_exercise.dart'; import 'package:wger/providers/add_exercise.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
@@ -74,10 +74,9 @@ class _Step4TranslationState extends State<Step4Translation> {
final names = alternateNames!.split('\n'); final names = alternateNames!.split('\n');
for (final name in names) { for (final name in names) {
if (name.length < MIN_CHARS_NAME || name.length > MAX_CHARS_NAME) { if (name.length < MIN_CHARS_NAME || name.length > MAX_CHARS_NAME) {
return AppLocalizations.of(context).enterCharacters( return AppLocalizations.of(
MIN_CHARS_NAME, context,
MAX_CHARS_NAME, ).enterCharacters(MIN_CHARS_NAME, MAX_CHARS_NAME);
);
} }
} }
} }

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/add_exercise.dart'; import 'package:wger/providers/add_exercise.dart';
import 'package:wger/widgets/add_exercise/mixins/image_picker_mixin.dart'; import 'package:wger/widgets/add_exercise/mixins/image_picker_mixin.dart';
import 'package:wger/widgets/add_exercise/preview_images.dart'; import 'package:wger/widgets/add_exercise/preview_images.dart';
@@ -26,9 +26,7 @@ class _Step5ImagesState extends State<Step5Images> with ExerciseImagePickerMixin
), ),
Consumer<AddExerciseProvider>( Consumer<AddExerciseProvider>(
builder: (ctx, provider, __) => provider.exerciseImages.isNotEmpty builder: (ctx, provider, __) => provider.exerciseImages.isNotEmpty
? PreviewExerciseImages( ? PreviewExerciseImages(selectedImages: provider.exerciseImages)
selectedImages: provider.exerciseImages,
)
: Row( : Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [

View File

@@ -17,10 +17,10 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/misc.dart'; import 'package:wger/helpers/misc.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/auth.dart'; import 'package:wger/providers/auth.dart';
class AboutEntry extends StatelessWidget { class AboutEntry extends StatelessWidget {
@@ -66,9 +66,7 @@ class AboutPage extends StatelessWidget {
final today = DateTime.now(); final today = DateTime.now();
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: Text(AppLocalizations.of(context).aboutPageTitle)),
title: Text(AppLocalizations.of(context).aboutPageTitle),
),
body: SingleChildScrollView( body: SingleChildScrollView(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),
child: Column( child: Column(
@@ -89,13 +87,12 @@ class AboutPage extends StatelessWidget {
children: [ children: [
const Text( const Text(
'Wger', 'Wger',
style: TextStyle( style: TextStyle(fontSize: 23, fontWeight: FontWeight.w600),
fontSize: 23, ),
fontWeight: FontWeight.w600, Text(
), 'App: ${authProvider.applicationVersion!.version}\n'
'Server: ${authProvider.serverVersion}',
), ),
Text('App: ${authProvider.applicationVersion!.version}\n'
'Server: ${authProvider.serverVersion}'),
], ],
), ),
], ],
@@ -163,7 +160,8 @@ class AboutPage extends StatelessWidget {
showLicensePage( showLicensePage(
context: context, context: context,
applicationName: 'wger', applicationName: 'wger',
applicationVersion: 'App: ${authProvider.applicationVersion!.version}\n' applicationVersion:
'App: ${authProvider.applicationVersion!.version}\n'
'Server: ${authProvider.serverVersion}', 'Server: ${authProvider.serverVersion}',
applicationLegalese: '\u{a9} 2020 - 2021 contributors', applicationLegalese: '\u{a9} 2020 - 2021 contributors',
applicationIcon: Padding( applicationIcon: Padding(

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/auth.dart'; import 'package:wger/providers/auth.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/providers/gallery.dart'; import 'package:wger/providers/gallery.dart';
@@ -50,9 +50,7 @@ class MainAppBar extends StatelessWidget implements PreferredSizeWidget {
title: Text(AppLocalizations.of(context).optionsLabel), title: Text(AppLocalizations.of(context).optionsLabel),
actions: [ actions: [
TextButton( TextButton(
child: Text( child: Text(MaterialLocalizations.of(context).closeButtonLabel),
MaterialLocalizations.of(context).closeButtonLabel,
),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
), ),
], ],
@@ -69,9 +67,7 @@ class MainAppBar extends StatelessWidget implements PreferredSizeWidget {
FormScreen.routeName, FormScreen.routeName,
arguments: FormScreenArguments( arguments: FormScreenArguments(
AppLocalizations.of(context).userProfile, AppLocalizations.of(context).userProfile,
UserProfileForm( UserProfileForm(context.read<UserProvider>().profile!),
context.read<UserProvider>().profile!,
),
), ),
), ),
), ),

View File

@@ -18,8 +18,8 @@
//import 'package:drift/drift.dart'; //import 'package:drift/drift.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
@@ -34,9 +34,7 @@ class SettingsPage extends StatelessWidget {
final nutritionProvider = Provider.of<NutritionPlansProvider>(context, listen: false); final nutritionProvider = Provider.of<NutritionPlansProvider>(context, listen: false);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(title: Text(AppLocalizations.of(context).settingsTitle)),
title: Text(AppLocalizations.of(context).settingsTitle),
),
body: ListView( body: ListView(
children: [ children: [
ListTile( ListTile(

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
class TextPrompt extends StatelessWidget { class TextPrompt extends StatelessWidget {
const TextPrompt(); const TextPrompt();

View File

@@ -17,12 +17,12 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart'; import 'package:table_calendar/table_calendar.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/json.dart'; import 'package:wger/helpers/json.dart';
import 'package:wger/helpers/misc.dart'; import 'package:wger/helpers/misc.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/session.dart'; import 'package:wger/models/workouts/session.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
@@ -31,12 +31,7 @@ import 'package:wger/providers/workout_plans.dart';
import 'package:wger/theme/theme.dart'; import 'package:wger/theme/theme.dart';
/// Types of events /// Types of events
enum EventType { enum EventType { weight, measurement, session, caloriesDiary }
weight,
measurement,
session,
caloriesDiary,
}
/// An event in the dashboard calendar /// An event in the dashboard calendar
class Event { class Event {
@@ -84,8 +79,10 @@ class _DashboardCalendarWidgetState extends State<DashboardCalendarWidget>
void loadEvents() async { void loadEvents() async {
// Process weight entries // Process weight entries
final BodyWeightProvider weightProvider = final BodyWeightProvider weightProvider = Provider.of<BodyWeightProvider>(
Provider.of<BodyWeightProvider>(context, listen: false); context,
listen: false,
);
for (final entry in weightProvider.items) { for (final entry in weightProvider.items) {
final date = DateFormatLists.format(entry.date); final date = DateFormatLists.format(entry.date);
@@ -98,8 +95,10 @@ class _DashboardCalendarWidgetState extends State<DashboardCalendarWidget>
} }
// Process measurements // Process measurements
final MeasurementProvider measurementProvider = final MeasurementProvider measurementProvider = Provider.of<MeasurementProvider>(
Provider.of<MeasurementProvider>(context, listen: false); context,
listen: false,
);
for (final category in measurementProvider.categories) { for (final category in measurementProvider.categories) {
for (final entry in category.entries) { for (final entry in category.entries) {
final date = DateFormatLists.format(entry.date); final date = DateFormatLists.format(entry.date);
@@ -108,10 +107,9 @@ class _DashboardCalendarWidgetState extends State<DashboardCalendarWidget>
_events[date] = []; _events[date] = [];
} }
_events[date]!.add(Event( _events[date]!.add(
EventType.measurement, Event(EventType.measurement, '${category.name}: ${entry.value} ${category.unit}'),
'${category.name}: ${entry.value} ${category.unit}', );
));
} }
} }
@@ -128,16 +126,20 @@ class _DashboardCalendarWidgetState extends State<DashboardCalendarWidget>
time = '(${timeToString(session.timeStart)} - ${timeToString(session.timeEnd)})'; time = '(${timeToString(session.timeStart)} - ${timeToString(session.timeEnd)})';
// Add events to lists // Add events to lists
_events[date]!.add(Event( _events[date]!.add(
EventType.session, Event(
'${AppLocalizations.of(context).impression}: ${session.impressionAsString} $time', EventType.session,
)); '${AppLocalizations.of(context).impression}: ${session.impressionAsString} $time',
),
);
} }
}); });
// Process nutritional plans // Process nutritional plans
final NutritionPlansProvider nutritionProvider = final NutritionPlansProvider nutritionProvider = Provider.of<NutritionPlansProvider>(
Provider.of<NutritionPlansProvider>(context, listen: false); context,
listen: false,
);
for (final plan in nutritionProvider.items) { for (final plan in nutritionProvider.items) {
for (final entry in plan.logEntriesValues.entries) { for (final entry in plan.logEntriesValues.entries) {
final date = DateFormatLists.format(entry.key); final date = DateFormatLists.format(entry.key);
@@ -146,10 +148,9 @@ class _DashboardCalendarWidgetState extends State<DashboardCalendarWidget>
} }
// Add events to lists // Add events to lists
_events[date]!.add(Event( _events[date]!.add(
EventType.caloriesDiary, Event(EventType.caloriesDiary, '${entry.value.energy.toStringAsFixed(0)} kcal'),
'${entry.value.energy.toStringAsFixed(0)} kcal', );
));
} }
} }
@@ -247,8 +248,10 @@ class _DashboardCalendarWidgetState extends State<DashboardCalendarWidget>
valueListenable: _selectedEvents, valueListenable: _selectedEvents,
builder: (context, value, _) => Column( builder: (context, value, _) => Column(
children: [ children: [
...value.map((event) => ListTile( ...value.map(
title: Text((() { (event) => ListTile(
title: Text(
(() {
switch (event.type) { switch (event.type) {
case EventType.caloriesDiary: case EventType.caloriesDiary:
return AppLocalizations.of(context).nutritionalDiary; return AppLocalizations.of(context).nutritionalDiary;
@@ -262,10 +265,12 @@ class _DashboardCalendarWidgetState extends State<DashboardCalendarWidget>
case EventType.measurement: case EventType.measurement:
return AppLocalizations.of(context).measurement; return AppLocalizations.of(context).measurement;
} }
})()), })(),
subtitle: Text(event.description), ),
//onTap: () => print('$event tapped!'), subtitle: Text(event.description),
)), //onTap: () => print('$event tapped!'),
),
),
], ],
), ),
), ),

View File

@@ -20,11 +20,11 @@ import 'dart:async';
import 'package:carousel_slider/carousel_slider.dart'; import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_svg_icons/flutter_svg_icons.dart'; import 'package:flutter_svg_icons/flutter_svg_icons.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/models/workouts/workout_plan.dart'; import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
@@ -66,8 +66,10 @@ class _DashboardNutritionWidgetState extends State<DashboardNutritionWidget> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final stream = final stream = Provider.of<NutritionPlansProvider>(
Provider.of<NutritionPlansProvider>(context, listen: false).watchNutritionPlanLast(); context,
listen: false,
).watchNutritionPlanLast();
_subscription = stream.listen((plan) { _subscription = stream.listen((plan) {
if (!context.mounted) { if (!context.mounted) {
return; return;
@@ -97,8 +99,9 @@ class _DashboardNutritionWidgetState extends State<DashboardNutritionWidget> {
), ),
subtitle: Text( subtitle: Text(
_hasContent _hasContent
? DateFormat.yMd(Localizations.localeOf(context).languageCode) ? DateFormat.yMd(
.format(_plan!.creationDate) Localizations.localeOf(context).languageCode,
).format(_plan!.creationDate)
: '', : '',
), ),
leading: Icon( leading: Icon(
@@ -127,17 +130,14 @@ class _DashboardNutritionWidgetState extends State<DashboardNutritionWidget> {
TextButton( TextButton(
child: Text(AppLocalizations.of(context).goToDetailPage), child: Text(AppLocalizations.of(context).goToDetailPage),
onPressed: () { onPressed: () {
Navigator.of(context).pushNamed( Navigator.of(
NutritionalPlanScreen.routeName, context,
arguments: _plan!.id, ).pushNamed(NutritionalPlanScreen.routeName, arguments: _plan!.id);
);
}, },
), ),
Expanded(child: Container()), Expanded(child: Container()),
IconButton( IconButton(
icon: const SvgIcon( icon: const SvgIcon(icon: SvgIconData('assets/icons/ingredient-diary.svg')),
icon: SvgIconData('assets/icons/ingredient-diary.svg'),
),
tooltip: AppLocalizations.of(context).logIngredient, tooltip: AppLocalizations.of(context).logIngredient,
onPressed: () { onPressed: () {
Navigator.pushNamed( Navigator.pushNamed(
@@ -152,9 +152,7 @@ class _DashboardNutritionWidgetState extends State<DashboardNutritionWidget> {
}, },
), ),
IconButton( IconButton(
icon: const SvgIcon( icon: const SvgIcon(icon: SvgIconData('assets/icons/meal-diary.svg')),
icon: SvgIconData('assets/icons/meal-diary.svg'),
),
tooltip: AppLocalizations.of(context).logMeal, tooltip: AppLocalizations.of(context).logMeal,
onPressed: () { onPressed: () {
Navigator.of(context).pushNamed(LogMealsScreen.routeName, arguments: _plan); Navigator.of(context).pushNamed(LogMealsScreen.routeName, arguments: _plan);
@@ -223,9 +221,7 @@ class _DashboardWeightWidgetState extends State<DashboardWeightWidget> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
TextButton( TextButton(
child: Text( child: Text(AppLocalizations.of(context).goToDetailPage),
AppLocalizations.of(context).goToDetailPage,
),
onPressed: () { onPressed: () {
Navigator.of(context).pushNamed(WeightScreen.routeName); Navigator.of(context).pushNamed(WeightScreen.routeName);
}, },
@@ -238,9 +234,12 @@ class _DashboardWeightWidgetState extends State<DashboardWeightWidget> {
FormScreen.routeName, FormScreen.routeName,
arguments: FormScreenArguments( arguments: FormScreenArguments(
AppLocalizations.of(context).newEntry, AppLocalizations.of(context).newEntry,
WeightForm(weightProvider WeightForm(
.getNewestEntry() weightProvider.getNewestEntry()?.copyWith(
?.copyWith(id: null, date: DateTime.now())), id: null,
date: DateTime.now(),
),
),
), ),
); );
}, },
@@ -279,8 +278,9 @@ class _DashboardMeasurementWidgetState extends State<DashboardMeasurementWidget>
Widget build(BuildContext context) { Widget build(BuildContext context) {
final provider = Provider.of<MeasurementProvider>(context, listen: false); final provider = Provider.of<MeasurementProvider>(context, listen: false);
final items = final items = provider.categories
provider.categories.map<Widget>((item) => CategoriesCard(item, elevation: 0)).toList(); .map<Widget>((item) => CategoriesCard(item, elevation: 0))
.toList();
if (items.isNotEmpty) { if (items.isNotEmpty) {
items.add( items.add(
NothingFound( NothingFound(
@@ -309,10 +309,8 @@ class _DashboardMeasurementWidgetState extends State<DashboardMeasurementWidget>
// maybe we should just add a "Go to all" at the bottom of the widget // maybe we should just add a "Go to all" at the bottom of the widget
trailing: IconButton( trailing: IconButton(
icon: const Icon(Icons.arrow_forward), icon: const Icon(Icons.arrow_forward),
onPressed: () => Navigator.pushNamed( onPressed: () =>
context, Navigator.pushNamed(context, MeasurementCategoriesScreen.routeName),
MeasurementCategoriesScreen.routeName,
),
), ),
), ),
Column( Column(
@@ -346,16 +344,11 @@ class _DashboardMeasurementWidgetState extends State<DashboardMeasurementWidget>
child: Container( child: Container(
width: 12.0, width: 12.0,
height: 12.0, height: 12.0,
margin: const EdgeInsets.symmetric( margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
vertical: 8.0,
horizontal: 4.0,
),
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: color: Theme.of(context).textTheme.headlineSmall!.color!
Theme.of(context).textTheme.headlineSmall!.color!.withOpacity( .withOpacity(_current == entry.key ? 0.9 : 0.4),
_current == entry.key ? 0.9 : 0.4,
),
), ),
), ),
); );
@@ -407,61 +400,63 @@ class _DashboardWorkoutWidgetState extends State<DashboardWorkoutWidget> {
} }
for (final day in _workoutPlan!.days) { for (final day in _workoutPlan!.days) {
out.add(SizedBox( out.add(
width: double.infinity, SizedBox(
child: Row(
children: [
Expanded(
child: Text(
day.description,
style: const TextStyle(fontWeight: FontWeight.bold),
overflow: TextOverflow.ellipsis,
),
),
Expanded(
child: MutedText(day.getDaysText, textAlign: TextAlign.right),
),
IconButton(
icon: const Icon(Icons.play_arrow),
color: wgerPrimaryButtonColor,
onPressed: () {
Navigator.of(context).pushNamed(GymModeScreen.routeName, arguments: day);
},
),
],
),
));
for (final set in day.sets) {
out.add(SizedBox(
width: double.infinity, width: double.infinity,
child: Column( child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
...set.settingsFiltered.map((s) { Expanded(
return _showDetail child: Text(
? Column( day.description,
children: [ style: const TextStyle(fontWeight: FontWeight.bold),
Row( overflow: TextOverflow.ellipsis,
crossAxisAlignment: CrossAxisAlignment.start, ),
children: [ ),
Text(s.exerciseObj Expanded(child: MutedText(day.getDaysText, textAlign: TextAlign.right)),
.getExercise(Localizations.localeOf(context).languageCode) IconButton(
.name), icon: const Icon(Icons.play_arrow),
const SizedBox(width: 10), color: wgerPrimaryButtonColor,
MutedText( onPressed: () {
set.getSmartRepr(s.exerciseObj).join('\n'), Navigator.of(context).pushNamed(GymModeScreen.routeName, arguments: day);
), },
], ),
),
const SizedBox(height: 10),
],
)
: Container();
}),
], ],
), ),
)); ),
);
for (final set in day.sets) {
out.add(
SizedBox(
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...set.settingsFiltered.map((s) {
return _showDetail
? Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
s.exerciseObj
.getExercise(Localizations.localeOf(context).languageCode)
.name,
),
const SizedBox(width: 10),
MutedText(set.getSmartRepr(s.exerciseObj).join('\n')),
],
),
const SizedBox(height: 10),
],
)
: Container();
}),
],
),
),
);
} }
out.add(const Divider()); out.add(const Divider());
} }
@@ -481,8 +476,9 @@ class _DashboardWorkoutWidgetState extends State<DashboardWorkoutWidget> {
), ),
subtitle: Text( subtitle: Text(
_hasContent _hasContent
? DateFormat.yMd(Localizations.localeOf(context).languageCode) ? DateFormat.yMd(
.format(_workoutPlan!.creationDate) Localizations.localeOf(context).languageCode,
).format(_workoutPlan!.creationDate)
: '', : '',
), ),
leading: Icon( leading: Icon(
@@ -519,10 +515,9 @@ class _DashboardWorkoutWidgetState extends State<DashboardWorkoutWidget> {
TextButton( TextButton(
child: Text(AppLocalizations.of(context).goToDetailPage), child: Text(AppLocalizations.of(context).goToDetailPage),
onPressed: () { onPressed: () {
Navigator.of(context).pushNamed( Navigator.of(
WorkoutPlanScreen.routeName, context,
arguments: _workoutPlan, ).pushNamed(WorkoutPlanScreen.routeName, arguments: _workoutPlan);
);
}, },
), ),
], ],
@@ -555,11 +550,7 @@ class NothingFound extends StatelessWidget {
Navigator.pushNamed( Navigator.pushNamed(
context, context,
FormScreen.routeName, FormScreen.routeName,
arguments: FormScreenArguments( arguments: FormScreenArguments(_titleForm, hasListView: true, _form),
_titleForm,
hasListView: true,
_form,
),
); );
}, },
), ),

View File

@@ -17,13 +17,13 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/i18n.dart'; import 'package:wger/helpers/i18n.dart';
import 'package:wger/helpers/platform.dart'; import 'package:wger/helpers/platform.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/exercises/muscle.dart'; import 'package:wger/models/exercises/muscle.dart';
import 'package:wger/models/exercises/translation.dart'; import 'package:wger/models/exercises/translation.dart';
@@ -83,18 +83,20 @@ class ExerciseDetail extends StatelessWidget {
return out; return out;
} }
out.add(Text( out.add(
AppLocalizations.of(context).variations, Text(
style: Theme.of(context).textTheme.headlineSmall, AppLocalizations.of(context).variations,
)); style: Theme.of(context).textTheme.headlineSmall,
),
);
Provider.of<ExercisesProvider>(context, listen: false) Provider.of<ExercisesProvider>(context, listen: false)
.findExercisesByVariationId( .findExercisesByVariationId(
_exerciseBase.variationId!, _exerciseBase.variationId!,
exerciseBaseIdToExclude: _exerciseBase.id, exerciseBaseIdToExclude: _exerciseBase.id,
) )
.forEach((element) { .forEach((element) {
out.add(ExerciseListTile(exerciseBase: element)); out.add(ExerciseListTile(exerciseBase: element));
}); });
out.add(const SizedBox(height: PADDING)); out.add(const SizedBox(height: PADDING));
return out; return out;
@@ -103,10 +105,9 @@ class ExerciseDetail extends StatelessWidget {
List<Widget> getNotes(BuildContext context) { List<Widget> getNotes(BuildContext context) {
final List<Widget> out = []; final List<Widget> out = [];
if (_exercise.notes.isNotEmpty) { if (_exercise.notes.isNotEmpty) {
out.add(Text( out.add(
AppLocalizations.of(context).notes, Text(AppLocalizations.of(context).notes, style: Theme.of(context).textTheme.headlineSmall),
style: Theme.of(context).textTheme.headlineSmall, );
));
for (final e in _exercise.notes) { for (final e in _exercise.notes) {
out.add(Text(e.comment)); out.add(Text(e.comment));
} }
@@ -118,36 +119,37 @@ class ExerciseDetail extends StatelessWidget {
List<Widget> getMuscles(BuildContext context) { List<Widget> getMuscles(BuildContext context) {
final List<Widget> out = []; final List<Widget> out = [];
out.add(Text( out.add(
AppLocalizations.of(context).muscles, Text(AppLocalizations.of(context).muscles, style: Theme.of(context).textTheme.headlineSmall),
style: Theme.of(context).textTheme.headlineSmall, );
)); out.add(
out.add(Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: PADDING), padding: const EdgeInsets.symmetric(horizontal: PADDING),
child: MuscleWidget( child: MuscleWidget(
muscles: _exerciseBase.muscles, muscles: _exerciseBase.muscles,
musclesSecondary: _exerciseBase.musclesSecondary, musclesSecondary: _exerciseBase.musclesSecondary,
isFront: true, isFront: true,
),
), ),
), ),
), Expanded(
Expanded( child: Padding(
child: Padding( padding: const EdgeInsets.symmetric(horizontal: PADDING),
padding: const EdgeInsets.symmetric(horizontal: PADDING), child: MuscleWidget(
child: MuscleWidget( muscles: _exerciseBase.muscles,
muscles: _exerciseBase.muscles, musclesSecondary: _exerciseBase.musclesSecondary,
musclesSecondary: _exerciseBase.musclesSecondary, isFront: false,
isFront: false, ),
), ),
), ),
), ],
], ),
)); );
out.add( out.add(
Column( Column(
@@ -176,10 +178,12 @@ class ExerciseDetail extends StatelessWidget {
List<Widget> getDescription(BuildContext context) { List<Widget> getDescription(BuildContext context) {
final List<Widget> out = []; final List<Widget> out = [];
out.add(Text( out.add(
AppLocalizations.of(context).description, Text(
style: Theme.of(context).textTheme.headlineSmall, AppLocalizations.of(context).description,
)); style: Theme.of(context).textTheme.headlineSmall,
),
);
out.add(Html(data: _exercise.description)); out.add(Html(data: _exercise.description));
return out; return out;
@@ -212,14 +216,16 @@ class ExerciseDetail extends StatelessWidget {
); );
if (_exerciseBase.equipment.isNotEmpty) { if (_exerciseBase.equipment.isNotEmpty) {
_exerciseBase.equipment _exerciseBase.equipment
.map((e) => Padding( .map(
padding: const EdgeInsets.symmetric(horizontal: 4), (e) => Padding(
child: Chip( padding: const EdgeInsets.symmetric(horizontal: 4),
label: Text(getTranslation(e.name, context)), child: Chip(
padding: EdgeInsets.zero, label: Text(getTranslation(e.name, context)),
backgroundColor: theme.splashColor, padding: EdgeInsets.zero,
), backgroundColor: theme.splashColor,
)) ),
),
)
.forEach((element) => out.add(element)); .forEach((element) => out.add(element));
} }
out.add(const SizedBox(height: PADDING)); out.add(const SizedBox(height: PADDING));
@@ -242,11 +248,13 @@ class ExerciseDetail extends StatelessWidget {
List<Widget> getAliases(BuildContext context) { List<Widget> getAliases(BuildContext context) {
final List<Widget> out = []; final List<Widget> out = [];
if (_exercise.aliases.isNotEmpty) { if (_exercise.aliases.isNotEmpty) {
out.add(MutedText( out.add(
AppLocalizations.of(context).alsoKnownAs( MutedText(
_exercise.aliases.map((e) => e.alias).toList().join(', '), AppLocalizations.of(
context,
).alsoKnownAs(_exercise.aliases.map((e) => e.alias).toList().join(', ')),
), ),
)); );
out.add(const SizedBox(height: PADDING)); out.add(const SizedBox(height: PADDING));
} }
@@ -284,10 +292,7 @@ class MuscleRowWidget extends StatelessWidget {
final List<Muscle> muscles; final List<Muscle> muscles;
final List<Muscle> musclesSecondary; final List<Muscle> musclesSecondary;
const MuscleRowWidget({ const MuscleRowWidget({required this.muscles, required this.musclesSecondary});
required this.muscles,
required this.musclesSecondary,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -342,9 +347,9 @@ class MuscleWidget extends StatelessWidget {
children: [ children: [
SvgPicture.asset('assets/images/muscles/$background.svg'), SvgPicture.asset('assets/images/muscles/$background.svg'),
...muscles.map((m) => SvgPicture.asset('assets/images/muscles/main/muscle-${m.id}.svg')), ...muscles.map((m) => SvgPicture.asset('assets/images/muscles/main/muscle-${m.id}.svg')),
...musclesSecondary.map((m) => SvgPicture.asset( ...musclesSecondary.map(
'assets/images/muscles/secondary/muscle-${m.id}.svg', (m) => SvgPicture.asset('assets/images/muscles/secondary/muscle-${m.id}.svg'),
)), ),
], ],
); );
} }

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/screens/add_exercise_screen.dart'; import 'package:wger/screens/add_exercise_screen.dart';
@@ -59,9 +59,7 @@ class _FilterRowState extends State<FilterRow> {
decoration: InputDecoration( decoration: InputDecoration(
hintText: '${AppLocalizations.of(context).exerciseName}...', hintText: '${AppLocalizations.of(context).exerciseName}...',
contentPadding: const EdgeInsets.symmetric(horizontal: 10), contentPadding: const EdgeInsets.symmetric(horizontal: 10),
border: const OutlineInputBorder( border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.black)),
borderSide: BorderSide(color: Colors.black),
),
), ),
), ),
), ),

View File

@@ -19,11 +19,11 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/json.dart'; import 'package:wger/helpers/json.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/gallery/image.dart' as gallery; import 'package:wger/models/gallery/image.dart' as gallery;
import 'package:wger/providers/gallery.dart'; import 'package:wger/providers/gallery.dart';
@@ -126,9 +126,7 @@ class _ImageFormState extends State<ImageForm> {
_showPicker(ImageSource.gallery); _showPicker(ImageSource.gallery);
}, },
leading: const Icon(Icons.photo_library), leading: const Icon(Icons.photo_library),
title: Text( title: Text(AppLocalizations.of(context).chooseFromLibrary),
AppLocalizations.of(context).chooseFromLibrary,
),
), ),
], ],
), ),
@@ -174,9 +172,7 @@ class _ImageFormState extends State<ImageForm> {
), ),
TextFormField( TextFormField(
key: const Key('field-description'), key: const Key('field-description'),
decoration: InputDecoration( decoration: InputDecoration(labelText: AppLocalizations.of(context).description),
labelText: AppLocalizations.of(context).description,
),
minLines: 3, minLines: 3,
maxLines: 10, maxLines: 10,
controller: descriptionController, controller: descriptionController,
@@ -196,12 +192,16 @@ class _ImageFormState extends State<ImageForm> {
_form.currentState!.save(); _form.currentState!.save();
if (widget._image.id == null) { if (widget._image.id == null) {
Provider.of<GalleryProvider>(context, listen: false) Provider.of<GalleryProvider>(
.addImage(widget._image, _file!); context,
listen: false,
).addImage(widget._image, _file!);
Navigator.of(context).pop(); Navigator.of(context).pop();
} else { } else {
Provider.of<GalleryProvider>(context, listen: false) Provider.of<GalleryProvider>(
.editImage(widget._image, _file); context,
listen: false,
).editImage(widget._image, _file);
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
}, },

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/platform.dart'; import 'package:wger/helpers/platform.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/gallery.dart'; import 'package:wger/providers/gallery.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
import 'package:wger/widgets/core/text_prompt.dart'; import 'package:wger/widgets/core/text_prompt.dart';
@@ -58,13 +58,12 @@ class Gallery extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
Text( Text(
DateFormat.yMd(Localizations.localeOf(context).languageCode) DateFormat.yMd(
.format(currentImage.date), Localizations.localeOf(context).languageCode,
).format(currentImage.date),
style: Theme.of(context).textTheme.headlineSmall, style: Theme.of(context).textTheme.headlineSmall,
), ),
Expanded( Expanded(child: Image.network(currentImage.url!)),
child: Image.network(currentImage.url!),
),
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: Text(currentImage.description), child: Text(currentImage.description),

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:wger/models/measurements/measurement_category.dart'; import 'package:wger/models/measurements/measurement_category.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
import 'package:wger/screens/measurement_entries_screen.dart'; import 'package:wger/screens/measurement_entries_screen.dart';
import 'package:wger/widgets/measurements/helpers.dart'; import 'package:wger/widgets/measurements/helpers.dart';
import 'charts.dart'; import 'charts.dart';
import 'forms.dart'; import 'forms.dart';
@@ -26,19 +26,12 @@ class CategoriesCard extends StatelessWidget {
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(top: 5), padding: const EdgeInsets.only(top: 5),
child: Text( child: Text(currentCategory.name, style: Theme.of(context).textTheme.titleLarge),
currentCategory.name,
style: Theme.of(context).textTheme.titleLarge,
),
), ),
Container( Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
height: 220, height: 220,
child: MeasurementChartWidgetFl( child: MeasurementChartWidgetFl(entriesAll, currentCategory.unit, avgs: entries7dAvg),
entriesAll,
currentCategory.unit,
avgs: entries7dAvg,
),
), ),
if (entries7dAvg.isNotEmpty) if (entries7dAvg.isNotEmpty)
MeasurementOverallChangeWidget( MeasurementOverallChangeWidget(

View File

@@ -18,9 +18,9 @@
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:wger/helpers/charts.dart'; import 'package:wger/helpers/charts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
class MeasurementOverallChangeWidget extends StatelessWidget { class MeasurementOverallChangeWidget extends StatelessWidget {
final MeasurementChartEntry _first; final MeasurementChartEntry _first;
@@ -34,8 +34,8 @@ class MeasurementOverallChangeWidget extends StatelessWidget {
final prefix = delta > 0 final prefix = delta > 0
? '+' ? '+'
: delta < 0 : delta < 0
? '-' ? '-'
: ''; : '';
return Text('overall change $prefix ${delta.abs().toStringAsFixed(1)} $_unit'); return Text('overall change $prefix ${delta.abs().toStringAsFixed(1)} $_unit');
} }
@@ -61,10 +61,7 @@ class _MeasurementChartWidgetFlState extends State<MeasurementChartWidgetFl> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AspectRatio( return AspectRatio(
aspectRatio: 1.70, aspectRatio: 1.70,
child: Padding( child: Padding(padding: const EdgeInsets.all(4), child: LineChart(mainData())),
padding: const EdgeInsets.all(4),
child: LineChart(mainData()),
),
); );
} }
@@ -75,15 +72,13 @@ class _MeasurementChartWidgetFlState extends State<MeasurementChartWidgetFl> {
getTooltipItems: (touchedSpots) { getTooltipItems: (touchedSpots) {
return touchedSpots.map((touchedSpot) { return touchedSpots.map((touchedSpot) {
final DateTime date = DateTime.fromMillisecondsSinceEpoch(touchedSpot.x.toInt()); final DateTime date = DateTime.fromMillisecondsSinceEpoch(touchedSpot.x.toInt());
final dateStr = final dateStr = DateFormat.Md(
DateFormat.Md(Localizations.localeOf(context).languageCode).format(date); Localizations.localeOf(context).languageCode,
).format(date);
return LineTooltipItem( return LineTooltipItem(
'$dateStr: ${touchedSpot.y.toStringAsFixed(1)} ${widget._unit}', '$dateStr: ${touchedSpot.y.toStringAsFixed(1)} ${widget._unit}',
TextStyle( TextStyle(color: touchedSpot.bar.color, fontWeight: FontWeight.bold),
color: touchedSpot.bar.color,
fontWeight: FontWeight.bold,
),
); );
}).toList(); }).toList();
}, },
@@ -108,12 +103,8 @@ class _MeasurementChartWidgetFlState extends State<MeasurementChartWidgetFl> {
), ),
titlesData: FlTitlesData( titlesData: FlTitlesData(
show: true, show: true,
rightTitles: const AxisTitles( rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
sideTitles: SideTitles(showTitles: false), topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles( bottomTitles: AxisTitles(
sideTitles: SideTitles( sideTitles: SideTitles(
showTitles: true, showTitles: true,
@@ -132,15 +123,10 @@ class _MeasurementChartWidgetFlState extends State<MeasurementChartWidgetFl> {
DateFormat.yMd(Localizations.localeOf(context).languageCode).format(date), DateFormat.yMd(Localizations.localeOf(context).languageCode).format(date),
); );
} }
return Text( return Text(DateFormat.Md(Localizations.localeOf(context).languageCode).format(date));
DateFormat.Md(Localizations.localeOf(context).languageCode).format(date),
);
}, },
interval: widget._entries.isNotEmpty interval: widget._entries.isNotEmpty
? chartGetInterval( ? chartGetInterval(widget._entries.last.date, widget._entries.first.date)
widget._entries.last.date,
widget._entries.first.date,
)
: 1000, : 1000,
), ),
), ),
@@ -168,10 +154,7 @@ class _MeasurementChartWidgetFlState extends State<MeasurementChartWidgetFl> {
lineBarsData: [ lineBarsData: [
LineChartBarData( LineChartBarData(
spots: widget._entries spots: widget._entries
.map((e) => FlSpot( .map((e) => FlSpot(e.date.millisecondsSinceEpoch.toDouble(), e.value.toDouble()))
e.date.millisecondsSinceEpoch.toDouble(),
e.value.toDouble(),
))
.toList(), .toList(),
isCurved: false, isCurved: false,
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
@@ -182,10 +165,7 @@ class _MeasurementChartWidgetFlState extends State<MeasurementChartWidgetFl> {
if (widget.avgs != null) if (widget.avgs != null)
LineChartBarData( LineChartBarData(
spots: widget.avgs! spots: widget.avgs!
.map((e) => FlSpot( .map((e) => FlSpot(e.date.millisecondsSinceEpoch.toDouble(), e.value.toDouble()))
e.date.millisecondsSinceEpoch.toDouble(),
e.value.toDouble(),
))
.toList(), .toList(),
isCurved: false, isCurved: false,
color: Theme.of(context).colorScheme.tertiary, color: Theme.of(context).colorScheme.tertiary,

View File

@@ -17,9 +17,9 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/measurements/measurement_category.dart'; import 'package:wger/models/measurements/measurement_category.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
@@ -38,82 +38,80 @@ class EntriesList extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final plan = Provider.of<NutritionPlansProvider>(context, listen: false).currentPlan; final plan = Provider.of<NutritionPlansProvider>(context, listen: false).currentPlan;
final entriesAll = final entriesAll = _category.entries
_category.entries.map((e) => MeasurementChartEntry(e.value, e.date)).toList(); .map((e) => MeasurementChartEntry(e.value, e.date))
.toList();
final entries7dAvg = moving7dAverage(entriesAll); final entries7dAvg = moving7dAverage(entriesAll);
return Column(children: [ return Column(
...getOverviewWidgetsSeries( children: [
_category.name, ...getOverviewWidgetsSeries(
entriesAll, _category.name,
entries7dAvg, entriesAll,
plan, entries7dAvg,
_category.unit, plan,
context, _category.unit,
), context,
SizedBox( ),
height: 300, SizedBox(
child: ListView.builder( height: 300,
padding: const EdgeInsets.all(10.0), child: ListView.builder(
itemCount: _category.entries.length, padding: const EdgeInsets.all(10.0),
itemBuilder: (context, index) { itemCount: _category.entries.length,
final currentEntry = _category.entries[index]; itemBuilder: (context, index) {
final provider = Provider.of<MeasurementProvider>(context, listen: false); final currentEntry = _category.entries[index];
final provider = Provider.of<MeasurementProvider>(context, listen: false);
return Card( return Card(
child: ListTile( child: ListTile(
title: Text('${currentEntry.value} ${_category.unit}'), title: Text('${currentEntry.value} ${_category.unit}'),
subtitle: Text( subtitle: Text(
DateFormat.yMd(Localizations.localeOf(context).languageCode) DateFormat.yMd(
.format(currentEntry.date), Localizations.localeOf(context).languageCode,
), ).format(currentEntry.date),
trailing: PopupMenuButton( ),
itemBuilder: (BuildContext context) { trailing: PopupMenuButton(
return [ itemBuilder: (BuildContext context) {
PopupMenuItem( return [
child: Text(AppLocalizations.of(context).edit), PopupMenuItem(
onTap: () => Navigator.pushNamed( child: Text(AppLocalizations.of(context).edit),
context, onTap: () => Navigator.pushNamed(
FormScreen.routeName, context,
arguments: FormScreenArguments( FormScreen.routeName,
AppLocalizations.of(context).edit, arguments: FormScreenArguments(
MeasurementEntryForm( AppLocalizations.of(context).edit,
currentEntry.category, MeasurementEntryForm(currentEntry.category, currentEntry),
currentEntry,
), ),
), ),
), ),
), PopupMenuItem(
PopupMenuItem( child: Text(AppLocalizations.of(context).delete),
child: Text(AppLocalizations.of(context).delete), onTap: () async {
onTap: () async { // Delete entry from DB
// Delete entry from DB await provider.deleteEntry(currentEntry.id!, currentEntry.category);
await provider.deleteEntry(
currentEntry.id!,
currentEntry.category,
);
// and inform the user // and inform the user
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text( content: Text(
AppLocalizations.of(context).successfullyDeleted, AppLocalizations.of(context).successfullyDeleted,
textAlign: TextAlign.center, textAlign: TextAlign.center,
),
), ),
), );
); }
} },
}, ),
), ];
]; },
}, ),
), ),
), );
); },
}, ),
), ),
), ],
]); );
} }
} }

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/helpers/json.dart'; import 'package:wger/helpers/json.dart';
import 'package:wger/helpers/ui.dart'; import 'package:wger/helpers/ui.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/measurements/measurement_category.dart'; import 'package:wger/models/measurements/measurement_category.dart';
import 'package:wger/models/measurements/measurement_entry.dart'; import 'package:wger/models/measurements/measurement_entry.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
@@ -31,11 +31,7 @@ class MeasurementCategoryForm extends StatelessWidget {
final nameController = TextEditingController(); final nameController = TextEditingController();
final unitController = TextEditingController(); final unitController = TextEditingController();
final Map<String, dynamic> categoryData = { final Map<String, dynamic> categoryData = {'id': null, 'name': '', 'unit': ''};
'id': null,
'name': '',
'unit': '',
};
MeasurementCategoryForm([MeasurementCategory? category]) { MeasurementCategoryForm([MeasurementCategory? category]) {
//this._category = category ?? MeasurementCategory(); //this._category = category ?? MeasurementCategory();
@@ -103,20 +99,14 @@ class MeasurementCategoryForm extends StatelessWidget {
// Save the entry on the server // Save the entry on the server
try { try {
categoryData['id'] == null categoryData['id'] == null
? await Provider.of<MeasurementProvider>( ? await Provider.of<MeasurementProvider>(context, listen: false).addCategory(
context,
listen: false,
).addCategory(
MeasurementCategory( MeasurementCategory(
id: categoryData['id'], id: categoryData['id'],
name: categoryData['name'], name: categoryData['name'],
unit: categoryData['unit'], unit: categoryData['unit'],
), ),
) )
: await Provider.of<MeasurementProvider>( : await Provider.of<MeasurementProvider>(context, listen: false).editCategory(
context,
listen: false,
).editCategory(
categoryData['id'], categoryData['id'],
categoryData['name'], categoryData['name'],
categoryData['unit'], categoryData['unit'],
@@ -274,20 +264,16 @@ class MeasurementEntryForm extends StatelessWidget {
// Save the entry on the server // Save the entry on the server
try { try {
_entryData['id'] == null _entryData['id'] == null
? await Provider.of<MeasurementProvider>( ? await Provider.of<MeasurementProvider>(context, listen: false).addEntry(
context, MeasurementEntry(
listen: false, id: _entryData['id'],
).addEntry(MeasurementEntry( category: _entryData['category'],
id: _entryData['id'], date: _entryData['date'],
category: _entryData['category'], value: _entryData['value'],
date: _entryData['date'], notes: _entryData['notes'],
value: _entryData['value'], ),
notes: _entryData['notes'], )
)) : await Provider.of<MeasurementProvider>(context, listen: false).editEntry(
: await Provider.of<MeasurementProvider>(
context,
listen: false,
).editEntry(
_entryData['id'], _entryData['id'],
_entryData['category'], _entryData['category'],
_entryData['value'], _entryData['value'],

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/widgets/measurements/charts.dart'; import 'package:wger/widgets/measurements/charts.dart';
@@ -11,11 +11,7 @@ List<Widget> getOverviewWidgets(
BuildContext context, BuildContext context,
) { ) {
return [ return [
Text( Text(title, textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleLarge),
title,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleLarge,
),
Container( Container(
padding: const EdgeInsets.all(15), padding: const EdgeInsets.all(15),
height: 220, height: 220,

View File

@@ -20,8 +20,8 @@ import 'dart:math';
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:wger/helpers/colors.dart'; import 'package:wger/helpers/colors.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/models/nutrition/nutritional_values.dart'; import 'package:wger/models/nutrition/nutritional_values.dart';
import 'package:wger/widgets/measurements/charts.dart'; import 'package:wger/widgets/measurements/charts.dart';
@@ -34,10 +34,8 @@ import 'package:wger/widgets/measurements/charts.dart';
// * here we draw our own simple gauges that can go beyond 100%, // * here we draw our own simple gauges that can go beyond 100%,
// and support multiple segments // and support multiple segments
class FlNutritionalPlanGoalWidget extends StatelessWidget { class FlNutritionalPlanGoalWidget extends StatelessWidget {
const FlNutritionalPlanGoalWidget({ const FlNutritionalPlanGoalWidget({super.key, required NutritionalPlan nutritionalPlan})
super.key, : _nutritionalPlan = nutritionalPlan;
required NutritionalPlan nutritionalPlan,
}) : _nutritionalPlan = nutritionalPlan;
final NutritionalPlan _nutritionalPlan; final NutritionalPlan _nutritionalPlan;
@@ -47,20 +45,12 @@ class FlNutritionalPlanGoalWidget extends StatelessWidget {
// why don't we just handle this inside this function? because it might be // why don't we just handle this inside this function? because it might be
// *another* gauge that's in surplus and we want to have consistent widths // *another* gauge that's in surplus and we want to have consistent widths
// between all gauges // between all gauges
Widget _diyGauge( Widget _diyGauge(BuildContext context, double normWidth, double? plan, double val) {
BuildContext context,
double normWidth,
double? plan,
double val,
) {
Container segment(double width, Color color) { Container segment(double width, Color color) {
return Container( return Container(
height: 16, height: 16,
width: width, width: width,
decoration: BoxDecoration( decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(15.0)),
color: color,
borderRadius: BorderRadius.circular(15.0),
),
); );
} }
@@ -71,17 +61,21 @@ class FlNutritionalPlanGoalWidget extends StatelessWidget {
// paint a surplus // paint a surplus
if (val > plan) { if (val > plan) {
return Stack(children: [ return Stack(
segment(normWidth * val / plan, COLOR_SURPLUS), children: [
segment(normWidth, LIST_OF_COLORS8[0]), segment(normWidth * val / plan, COLOR_SURPLUS),
]); segment(normWidth, LIST_OF_COLORS8[0]),
],
);
} }
// paint a deficit // paint a deficit
return Stack(children: [ return Stack(
segment(normWidth, Theme.of(context).colorScheme.surface), children: [
segment(normWidth * val / plan, LIST_OF_COLORS8[0]), segment(normWidth, Theme.of(context).colorScheme.surface),
]); segment(normWidth * val / plan, LIST_OF_COLORS8[0]),
],
);
} }
@override @override
@@ -90,87 +84,97 @@ class FlNutritionalPlanGoalWidget extends StatelessWidget {
final goals = plan.nutritionalGoals; final goals = plan.nutritionalGoals;
final today = plan.loggedNutritionalValuesToday; final today = plan.loggedNutritionalValuesToday;
return LayoutBuilder(builder: (context, constraints) { return LayoutBuilder(
// if any of the bars goes over 100%, find the one that goes over the most builder: (context, constraints) {
// that one needs the most horizontal space to show how much it goes over, // if any of the bars goes over 100%, find the one that goes over the most
// and therefore reduces the width of "100%" the most, and this width we want // that one needs the most horizontal space to show how much it goes over,
// to be consistent for all other bars. // and therefore reduces the width of "100%" the most, and this width we want
// if none goes over, 100% means fill all available space // to be consistent for all other bars.
final maxVal = [ // if none goes over, 100% means fill all available space
1.0, final maxVal = [
if (goals.energy != null && goals.energy! > 0) today.energy / goals.energy!, 1.0,
if (goals.protein != null && goals.protein! > 0) today.protein / goals.protein!, if (goals.energy != null && goals.energy! > 0) today.energy / goals.energy!,
if (goals.carbohydrates != null && goals.carbohydrates! > 0) if (goals.protein != null && goals.protein! > 0) today.protein / goals.protein!,
today.carbohydrates / goals.carbohydrates!, if (goals.carbohydrates != null && goals.carbohydrates! > 0)
if (goals.fat != null && goals.fat! > 0) today.fat / goals.fat!, today.carbohydrates / goals.carbohydrates!,
if (goals.fiber != null && goals.fiber! > 0) today.fiber / goals.fiber!, if (goals.fat != null && goals.fat! > 0) today.fat / goals.fat!,
].reduce(max); if (goals.fiber != null && goals.fiber! > 0) today.fiber / goals.fiber!,
].reduce(max);
final normWidth = constraints.maxWidth / maxVal; final normWidth = constraints.maxWidth / maxVal;
String fmtMacro(String name, double today, double? goal, String unit) { String fmtMacro(String name, double today, double? goal, String unit) {
return '$name: ${today.toStringAsFixed(0)}${goal == null ? '' : ' / ${goal.toStringAsFixed(0)}'} $unit'; return '$name: ${today.toStringAsFixed(0)}${goal == null ? '' : ' / ${goal.toStringAsFixed(0)}'} $unit';
} }
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(fmtMacro( Text(
AppLocalizations.of(context).energy, fmtMacro(
today.energy, AppLocalizations.of(context).energy,
goals.energy, today.energy,
AppLocalizations.of(context).kcal, goals.energy,
)), AppLocalizations.of(context).kcal,
const SizedBox(height: 2), ),
_diyGauge(context, normWidth, goals.energy, today.energy), ),
const SizedBox(height: 8), const SizedBox(height: 2),
Text(fmtMacro( _diyGauge(context, normWidth, goals.energy, today.energy),
AppLocalizations.of(context).protein, const SizedBox(height: 8),
today.protein, Text(
goals.protein, fmtMacro(
AppLocalizations.of(context).g, AppLocalizations.of(context).protein,
)), today.protein,
const SizedBox(height: 2), goals.protein,
_diyGauge(context, normWidth, goals.protein, today.protein),
const SizedBox(height: 8),
Text(fmtMacro(
AppLocalizations.of(context).carbohydrates,
today.carbohydrates,
goals.carbohydrates,
AppLocalizations.of(context).g,
)),
const SizedBox(height: 2),
_diyGauge(
context,
normWidth,
goals.carbohydrates,
today.carbohydrates,
),
const SizedBox(height: 8),
Text(fmtMacro(
AppLocalizations.of(context).fat,
today.fat,
goals.fat,
AppLocalizations.of(context).g,
)),
const SizedBox(height: 2),
_diyGauge(context, normWidth, goals.fat, today.fat),
// optionally display the advanced macro goals:
if (goals.fiber != null)
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
const SizedBox(height: 8),
Text(fmtMacro(
AppLocalizations.of(context).fiber,
today.fiber,
goals.fiber,
AppLocalizations.of(context).g, AppLocalizations.of(context).g,
)), ),
const SizedBox(height: 2), ),
_diyGauge(context, normWidth, goals.fiber, today.fiber), const SizedBox(height: 2),
]), _diyGauge(context, normWidth, goals.protein, today.protein),
], const SizedBox(height: 8),
); Text(
}); fmtMacro(
AppLocalizations.of(context).carbohydrates,
today.carbohydrates,
goals.carbohydrates,
AppLocalizations.of(context).g,
),
),
const SizedBox(height: 2),
_diyGauge(context, normWidth, goals.carbohydrates, today.carbohydrates),
const SizedBox(height: 8),
Text(
fmtMacro(
AppLocalizations.of(context).fat,
today.fat,
goals.fat,
AppLocalizations.of(context).g,
),
),
const SizedBox(height: 2),
_diyGauge(context, normWidth, goals.fat, today.fat),
// optionally display the advanced macro goals:
if (goals.fiber != null)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
Text(
fmtMacro(
AppLocalizations.of(context).fiber,
today.fiber,
goals.fiber,
AppLocalizations.of(context).g,
),
),
const SizedBox(height: 2),
_diyGauge(context, normWidth, goals.fiber, today.fiber),
],
),
],
);
},
);
} }
} }
@@ -227,16 +231,19 @@ class FlNutritionalPlanPieChartState extends State<FlNutritionalPlanPieChartWidg
Column( Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children:
(AppLocalizations.of(context).protein, LIST_OF_COLORS3[1]), [
(AppLocalizations.of(context).carbohydrates, LIST_OF_COLORS3[0]), (AppLocalizations.of(context).protein, LIST_OF_COLORS3[1]),
(AppLocalizations.of(context).fat, LIST_OF_COLORS3[2]), (AppLocalizations.of(context).carbohydrates, LIST_OF_COLORS3[0]),
] (AppLocalizations.of(context).fat, LIST_OF_COLORS3[2]),
.map((e) => Padding( ]
padding: const EdgeInsets.symmetric(vertical: 2), .map(
child: Indicator(color: e.$2, text: e.$1, isSquare: true), (e) => Padding(
)) padding: const EdgeInsets.symmetric(vertical: 2),
.toList(), child: Indicator(color: e.$2, text: e.$1, isSquare: true),
),
)
.toList(),
), ),
const SizedBox(width: 28), const SizedBox(width: 28),
], ],
@@ -265,10 +272,8 @@ class FlNutritionalPlanPieChartState extends State<FlNutritionalPlanPieChartWidg
/// Shows results vs plan of common macros, for today and last 7 days, as barchart /// Shows results vs plan of common macros, for today and last 7 days, as barchart
class NutritionalDiaryChartWidgetFl extends StatefulWidget { class NutritionalDiaryChartWidgetFl extends StatefulWidget {
const NutritionalDiaryChartWidgetFl({ const NutritionalDiaryChartWidgetFl({super.key, required NutritionalPlan nutritionalPlan})
super.key, : _nutritionalPlan = nutritionalPlan;
required NutritionalPlan nutritionalPlan,
}) : _nutritionalPlan = nutritionalPlan;
final NutritionalPlan _nutritionalPlan; final NutritionalPlan _nutritionalPlan;
@@ -315,12 +320,7 @@ class NutritionalDiaryChartWidgetFlState extends State<NutritionalDiaryChartWidg
final [colorPlanned, colorLoggedToday, colorLogged7Day] = LIST_OF_COLORS3; final [colorPlanned, colorLoggedToday, colorLogged7Day] = LIST_OF_COLORS3;
BarChartGroupData barchartGroup( BarChartGroupData barchartGroup(int x, double barsSpace, double barsWidth, String prop) {
int x,
double barsSpace,
double barsWidth,
String prop,
) {
final plan = planned.prop(prop); final plan = planned.prop(prop);
BarChartRodData barChartRodData(double? plan, double val, Color color) { BarChartRodData barChartRodData(double? plan, double val, Color color) {
@@ -391,20 +391,14 @@ class NutritionalDiaryChartWidgetFlState extends State<NutritionalDiaryChartWidg
getTitlesWidget: leftTitles, getTitlesWidget: leftTitles,
), ),
), ),
topTitles: const AxisTitles( topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
sideTitles: SideTitles(showTitles: false), rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
), ),
gridData: FlGridData( gridData: FlGridData(
show: true, show: true,
checkToShowHorizontalLine: (value) => value % 10 == 0, checkToShowHorizontalLine: (value) => value % 10 == 0,
getDrawingHorizontalLine: (value) => const FlLine( getDrawingHorizontalLine: (value) =>
color: Colors.black, const FlLine(color: Colors.black, strokeWidth: 1),
strokeWidth: 1,
),
drawVerticalLine: false, drawVerticalLine: false,
), ),
borderData: FlBorderData(show: false), borderData: FlBorderData(show: false),
@@ -412,12 +406,7 @@ class NutritionalDiaryChartWidgetFlState extends State<NutritionalDiaryChartWidg
barGroups: [ barGroups: [
barchartGroup(0, barsSpace, barsWidth, 'protein'), barchartGroup(0, barsSpace, barsWidth, 'protein'),
barchartGroup(1, barsSpace, barsWidth, 'carbohydrates'), barchartGroup(1, barsSpace, barsWidth, 'carbohydrates'),
barchartGroup( barchartGroup(2, barsSpace, barsWidth, 'carbohydratesSugar'),
2,
barsSpace,
barsWidth,
'carbohydratesSugar',
),
barchartGroup(3, barsSpace, barsWidth, 'fat'), barchartGroup(3, barsSpace, barsWidth, 'fat'),
barchartGroup(4, barsSpace, barsWidth, 'fatSaturated'), barchartGroup(4, barsSpace, barsWidth, 'fatSaturated'),
if (widget._nutritionalPlan.nutritionalGoals.fiber != null) if (widget._nutritionalPlan.nutritionalGoals.fiber != null)
@@ -430,21 +419,17 @@ class NutritionalDiaryChartWidgetFlState extends State<NutritionalDiaryChartWidg
padding: const EdgeInsets.only(bottom: 40, left: 25, right: 25), padding: const EdgeInsets.only(bottom: 40, left: 25, right: 25),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children:
(AppLocalizations.of(context).deficit, colorPlanned), [
(AppLocalizations.of(context).surplus, COLOR_SURPLUS), (AppLocalizations.of(context).deficit, colorPlanned),
(AppLocalizations.of(context).today, colorLoggedToday), (AppLocalizations.of(context).surplus, COLOR_SURPLUS),
(AppLocalizations.of(context).weekAverage, colorLogged7Day), (AppLocalizations.of(context).today, colorLoggedToday),
] (AppLocalizations.of(context).weekAverage, colorLogged7Day),
.map( ]
(e) => Indicator( .map(
color: e.$2, (e) => Indicator(color: e.$2, text: e.$1, isSquare: true, marginRight: 0),
text: e.$1, )
isSquare: true, .toList(),
marginRight: 0,
),
)
.toList(),
), ),
), ),
], ],
@@ -460,8 +445,8 @@ class MealDiaryBarChartWidget extends StatefulWidget {
super.key, super.key,
required NutritionalValues logged, required NutritionalValues logged,
required NutritionalValues planned, required NutritionalValues planned,
}) : _logged = logged, }) : _logged = logged,
_planned = planned; _planned = planned;
final NutritionalValues _logged; final NutritionalValues _logged;
final NutritionalValues _planned; final NutritionalValues _planned;
@@ -486,12 +471,12 @@ class MealDiaryBarChartWidgetState extends State<MealDiaryBarChartWidget> {
} }
Widget leftTitles(double value, TitleMeta meta) => SideTitleWidget( Widget leftTitles(double value, TitleMeta meta) => SideTitleWidget(
axisSide: meta.axisSide, axisSide: meta.axisSide,
child: Text( child: Text(
AppLocalizations.of(context).percentValue(value.toStringAsFixed(0)), AppLocalizations.of(context).percentValue(value.toStringAsFixed(0)),
style: const TextStyle(fontSize: 10), style: const TextStyle(fontSize: 10),
), ),
); );
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -523,19 +508,13 @@ class MealDiaryBarChartWidgetState extends State<MealDiaryBarChartWidget> {
getTitlesWidget: leftTitles, getTitlesWidget: leftTitles,
), ),
), ),
topTitles: const AxisTitles( topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
sideTitles: SideTitles(showTitles: false), rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
), ),
gridData: FlGridData( gridData: FlGridData(
show: true, show: true,
getDrawingHorizontalLine: (value) => const FlLine( getDrawingHorizontalLine: (value) =>
color: Colors.black, const FlLine(color: Colors.black, strokeWidth: 1),
strokeWidth: 1,
),
drawVerticalLine: false, drawVerticalLine: false,
), ),
borderData: FlBorderData(show: false), borderData: FlBorderData(show: false),

View File

@@ -17,12 +17,12 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/json.dart'; import 'package:wger/helpers/json.dart';
import 'package:wger/helpers/ui.dart'; import 'package:wger/helpers/ui.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/ingredient.dart'; import 'package:wger/models/nutrition/ingredient.dart';
import 'package:wger/models/nutrition/log.dart'; import 'package:wger/models/nutrition/log.dart';
import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal.dart';
@@ -65,10 +65,7 @@ class MealForm extends StatelessWidget {
FocusScope.of(context).requestFocus(FocusNode()); FocusScope.of(context).requestFocus(FocusNode());
// Open time picker // Open time picker
final pickedTime = await showTimePicker( final pickedTime = await showTimePicker(context: context, initialTime: _meal.time!);
context: context,
initialTime: _meal.time!,
);
if (pickedTime != null) { if (pickedTime != null) {
_timeController.text = timeToString(pickedTime)!; _timeController.text = timeToString(pickedTime)!;
} }
@@ -101,10 +98,7 @@ class MealForm extends StatelessWidget {
context, context,
listen: false, listen: false,
).addMeal(_meal, _planId) ).addMeal(_meal, _planId)
: Provider.of<NutritionPlansProvider>( : Provider.of<NutritionPlansProvider>(context, listen: false).editMeal(_meal);
context,
listen: false,
).editMeal(_meal);
} on WgerHttpException catch (error) { } on WgerHttpException catch (error) {
showHttpExceptionErrorDialog(error, context); showHttpExceptionErrorDialog(error, context);
} catch (error) { } catch (error) {
@@ -120,12 +114,7 @@ class MealForm extends StatelessWidget {
} }
} }
Widget MealItemForm( Widget MealItemForm(Meal meal, List<MealItem> recent, [String? barcode, bool? test]) {
Meal meal,
List<MealItem> recent, [
String? barcode,
bool? test,
]) {
return IngredientForm( return IngredientForm(
// TODO we use planId 0 here cause we don't have one and we don't need it I think? // TODO we use planId 0 here cause we don't have one and we don't need it I think?
recent: recent.map((e) => Log.fromMealItem(e, "0", e.mealId)).toList(), recent: recent.map((e) => Log.fromMealItem(e, "0", e.mealId)).toList(),
@@ -143,14 +132,13 @@ Widget IngredientLogForm(NutritionalPlan plan) {
return IngredientForm( return IngredientForm(
recent: plan.dedupDiaryEntries, recent: plan.dedupDiaryEntries,
onSave: (BuildContext context, MealItem mealItem, DateTime? dt) { onSave: (BuildContext context, MealItem mealItem, DateTime? dt) {
Provider.of<NutritionPlansProvider>(context, listen: false) Provider.of<NutritionPlansProvider>(
.logIngredientToDiary(mealItem, plan.id!, dt); context,
listen: false,
).logIngredientToDiary(mealItem, plan.id!, dt);
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text( content: Text(AppLocalizations.of(context).ingredientLogged, textAlign: TextAlign.center),
AppLocalizations.of(context).ingredientLogged,
textAlign: TextAlign.center,
),
), ),
); );
}, },
@@ -241,8 +229,9 @@ class IngredientFormState extends State<IngredientForm> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final String unit = AppLocalizations.of(context).g; final String unit = AppLocalizations.of(context).g;
final queryLower = _searchQuery.toLowerCase(); final queryLower = _searchQuery.toLowerCase();
final suggestions = final suggestions = widget.recent
widget.recent.where((e) => e.ingredient.name.toLowerCase().contains(queryLower)).toList(); .where((e) => e.ingredient.name.toLowerCase().contains(queryLower))
.toList();
return Container( return Container(
margin: const EdgeInsets.all(20), margin: const EdgeInsets.all(20),
child: Form( child: Form(
@@ -263,9 +252,7 @@ class IngredientFormState extends State<IngredientForm> {
Expanded( Expanded(
child: TextFormField( child: TextFormField(
key: const Key('field-weight'), // needed ? key: const Key('field-weight'), // needed ?
decoration: InputDecoration( decoration: InputDecoration(labelText: AppLocalizations.of(context).weight),
labelText: AppLocalizations.of(context).weight,
),
controller: _amountController, controller: _amountController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
onChanged: (value) { onChanged: (value) {
@@ -361,10 +348,7 @@ class IngredientFormState extends State<IngredientForm> {
context, context,
listen: false, listen: false,
).fetchIngredient(_mealItem.ingredientId), ).fetchIngredient(_mealItem.ingredientId),
builder: ( builder: (BuildContext context, AsyncSnapshot<Ingredient> snapshot) {
BuildContext context,
AsyncSnapshot<Ingredient> snapshot,
) {
if (snapshot.hasData) { if (snapshot.hasData) {
_mealItem.ingredient = snapshot.data!; _mealItem.ingredient = snapshot.data!;
return MealItemValuesTile( return MealItemValuesTile(
@@ -403,13 +387,7 @@ class IngredientFormState extends State<IngredientForm> {
try { try {
var date = DateTime.parse(_dateController.text); var date = DateTime.parse(_dateController.text);
final tod = stringToTime(_timeController.text); final tod = stringToTime(_timeController.text);
date = DateTime( date = DateTime(date.year, date.month, date.day, tod.hour, tod.minute);
date.year,
date.month,
date.day,
tod.hour,
tod.minute,
);
widget.onSave(context, _mealItem, date); widget.onSave(context, _mealItem, date);
} on WgerHttpException catch (error) { } on WgerHttpException catch (error) {
showHttpExceptionErrorDialog(error, context); showHttpExceptionErrorDialog(error, context);
@@ -431,11 +409,7 @@ class IngredientFormState extends State<IngredientForm> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
void select() { void select() {
final ingredient = suggestions[index].ingredient; final ingredient = suggestions[index].ingredient;
selectIngredient( selectIngredient(ingredient.id, ingredient.name, suggestions[index].amount);
ingredient.id,
ingredient.name,
suggestions[index].amount,
);
} }
return Card( return Card(
@@ -444,10 +418,12 @@ class IngredientFormState extends State<IngredientForm> {
title: Text( title: Text(
'${suggestions[index].ingredient.name} (${suggestions[index].amount.toStringAsFixed(0)}$unit)', '${suggestions[index].ingredient.name} (${suggestions[index].amount.toStringAsFixed(0)}$unit)',
), ),
subtitle: Text(getShortNutritionValues( subtitle: Text(
suggestions[index].ingredient.nutritionalValues, getShortNutritionValues(
context, suggestions[index].ingredient.nutritionalValues,
)), context,
),
),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -539,9 +515,7 @@ class _PlanFormState extends State<PlanForm> {
// Description // Description
TextFormField( TextFormField(
key: const Key('field-description'), key: const Key('field-description'),
decoration: InputDecoration( decoration: InputDecoration(labelText: AppLocalizations.of(context).description),
labelText: AppLocalizations.of(context).description,
),
controller: _descriptionController, controller: _descriptionController,
onSaved: (newValue) { onSaved: (newValue) {
widget._plan.description = newValue!; widget._plan.description = newValue!;
@@ -569,12 +543,7 @@ class _PlanFormState extends State<PlanForm> {
child: DropdownButtonFormField<GoalType>( child: DropdownButtonFormField<GoalType>(
value: _goalType, value: _goalType,
items: GoalType.values items: GoalType.values
.map( .map((e) => DropdownMenuItem<GoalType>(value: e, child: Text(e.label)))
(e) => DropdownMenuItem<GoalType>(
value: e,
child: Text(e.label),
),
)
.toList(), .toList(),
onChanged: (GoalType? g) { onChanged: (GoalType? g) {
setState(() { setState(() {

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/ingredient.dart'; import 'package:wger/models/nutrition/ingredient.dart';
import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal.dart';
import 'package:wger/models/nutrition/nutritional_values.dart'; import 'package:wger/models/nutrition/nutritional_values.dart';
@@ -27,18 +27,18 @@ import 'package:wger/widgets/core/core.dart';
import 'package:wger/widgets/nutrition/ingredient_dialogs.dart'; import 'package:wger/widgets/nutrition/ingredient_dialogs.dart';
List<String> getNutritionColumnNames(BuildContext context) => [ List<String> getNutritionColumnNames(BuildContext context) => [
AppLocalizations.of(context).energy, AppLocalizations.of(context).energy,
AppLocalizations.of(context).protein, AppLocalizations.of(context).protein,
AppLocalizations.of(context).carbohydrates, AppLocalizations.of(context).carbohydrates,
AppLocalizations.of(context).fat, AppLocalizations.of(context).fat,
]; ];
List<String> getNutritionalValues(NutritionalValues values, BuildContext context) => [ List<String> getNutritionalValues(NutritionalValues values, BuildContext context) => [
AppLocalizations.of(context).kcalValue(values.energy.toStringAsFixed(0)), AppLocalizations.of(context).kcalValue(values.energy.toStringAsFixed(0)),
AppLocalizations.of(context).gValue(values.protein.toStringAsFixed(0)), AppLocalizations.of(context).gValue(values.protein.toStringAsFixed(0)),
AppLocalizations.of(context).gValue(values.carbohydrates.toStringAsFixed(0)), AppLocalizations.of(context).gValue(values.carbohydrates.toStringAsFixed(0)),
AppLocalizations.of(context).gValue(values.fat.toStringAsFixed(0)), AppLocalizations.of(context).gValue(values.fat.toStringAsFixed(0)),
]; ];
List<int> getNutritionColumnFlexes(BuildContext context) { List<int> getNutritionColumnFlexes(BuildContext context) {
return getNutritionColumnNames(context).map((e) { return getNutritionColumnNames(context).map((e) {
@@ -51,11 +51,7 @@ List<int> getNutritionColumnFlexes(BuildContext context) {
} }
List<Widget> muted(List<String> children) => children List<Widget> muted(List<String> children) => children
.map((e) => MutedText( .map((e) => MutedText(e, textAlign: TextAlign.right, overflow: TextOverflow.ellipsis))
e,
textAlign: TextAlign.right,
overflow: TextOverflow.ellipsis,
))
.toList(); .toList();
// return a row of elements in the standard macros spacing // return a row of elements in the standard macros spacing
@@ -85,15 +81,17 @@ String getShortNutritionValues(NutritionalValues values, BuildContext context) {
} }
String getKcalConsumed(Meal meal, BuildContext context) { String getKcalConsumed(Meal meal, BuildContext context) {
final consumed = final consumed = meal.diaryEntriesToday
meal.diaryEntriesToday.map((e) => e.nutritionalValues.energy).fold(0.0, (a, b) => a + b); .map((e) => e.nutritionalValues.energy)
.fold(0.0, (a, b) => a + b);
return AppLocalizations.of(context).kcalValue(consumed.toStringAsFixed(0)); return AppLocalizations.of(context).kcalValue(consumed.toStringAsFixed(0));
} }
String getKcalConsumedVsPlanned(Meal meal, BuildContext context) { String getKcalConsumedVsPlanned(Meal meal, BuildContext context) {
final planned = meal.plannedNutritionalValues.energy; final planned = meal.plannedNutritionalValues.energy;
final consumed = final consumed = meal.diaryEntriesToday
meal.diaryEntriesToday.map((e) => e.nutritionalValues.energy).fold(0.0, (a, b) => a + b); .map((e) => e.nutritionalValues.energy)
.fold(0.0, (a, b) => a + b);
final loc = AppLocalizations.of(context); final loc = AppLocalizations.of(context);
return '${consumed.toStringAsFixed(0)} / ${planned.toStringAsFixed(0)} ${loc.kcal}'; return '${consumed.toStringAsFixed(0)} / ${planned.toStringAsFixed(0)} ${loc.kcal}';

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:wger/helpers/misc.dart'; import 'package:wger/helpers/misc.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/ingredient.dart'; import 'package:wger/models/nutrition/ingredient.dart';
import 'package:wger/models/nutrition/nutritional_goals.dart'; import 'package:wger/models/nutrition/nutritional_goals.dart';
import 'package:wger/widgets/nutrition/macro_nutrients_table.dart'; import 'package:wger/widgets/nutrition/macro_nutrients_table.dart';
@@ -143,15 +143,14 @@ class IngredientScanResultDialog extends StatelessWidget {
if (snapshot.connectionState == ConnectionState.done && ingredient == null) if (snapshot.connectionState == ConnectionState.done && ingredient == null)
Padding( Padding(
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: Text( child: Text(AppLocalizations.of(context).productNotFoundDescription(barcode)),
AppLocalizations.of(context).productNotFoundDescription(barcode),
),
), ),
if (ingredient != null) if (ingredient != null)
Padding( Padding(
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: child: Text(
Text(AppLocalizations.of(context).productFoundDescription(ingredient.name)), AppLocalizations.of(context).productFoundDescription(ingredient.name),
),
), ),
if (ingredient?.image?.image != null) if (ingredient?.image?.image != null)
ingredientImage(ingredient!.image!.image, context), ingredientImage(ingredient!.image!.image, context),

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_goals.dart'; import 'package:wger/models/nutrition/nutritional_goals.dart';
class MacronutrientsTable extends StatelessWidget { class MacronutrientsTable extends StatelessWidget {
@@ -22,13 +22,13 @@ class MacronutrientsTable extends StatelessWidget {
final loc = AppLocalizations.of(context); final loc = AppLocalizations.of(context);
Widget columnHeader(bool left, String title) => Padding( Widget columnHeader(bool left, String title) => Padding(
padding: const EdgeInsets.symmetric(vertical: tablePadding), padding: const EdgeInsets.symmetric(vertical: tablePadding),
child: Text( child: Text(
title, title,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
textAlign: left ? TextAlign.left : TextAlign.right, textAlign: left ? TextAlign.left : TextAlign.right,
), ),
); );
TableRow macroRow(int indent, bool g, String title, double? Function(NutritionalGoals ng) get) { TableRow macroRow(int indent, bool g, String title, double? Function(NutritionalGoals ng) get) {
final goal = get(nutritionalGoals); final goal = get(nutritionalGoals);
@@ -53,10 +53,7 @@ class MacronutrientsTable extends StatelessWidget {
return Table( return Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle, defaultVerticalAlignment: TableCellVerticalAlignment.middle,
border: TableBorder( border: TableBorder(
horizontalInside: BorderSide( horizontalInside: BorderSide(width: 1, color: Theme.of(context).colorScheme.outline),
width: 1,
color: Theme.of(context).colorScheme.outline,
),
), ),
columnWidths: const {0: FractionColumnWidth(0.4)}, columnWidths: const {0: FractionColumnWidth(0.4)},
children: [ children: [

View File

@@ -17,10 +17,10 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_svg_icons/flutter_svg_icons.dart'; import 'package:flutter_svg_icons/flutter_svg_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal.dart';
import 'package:wger/models/nutrition/meal_item.dart'; import 'package:wger/models/nutrition/meal_item.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
@@ -36,7 +36,7 @@ import 'package:wger/widgets/nutrition/widgets.dart';
enum viewMode { enum viewMode {
base, // just highlevel meal info (name, time) base, // just highlevel meal info (name, time)
withIngredients, // + ingredients withIngredients, // + ingredients
withAllDetails // + nutritional breakdown of ingredients, + logged today withAllDetails, // + nutritional breakdown of ingredients, + logged today
} }
class MealWidget extends StatefulWidget { class MealWidget extends StatefulWidget {
@@ -45,12 +45,7 @@ class MealWidget extends StatefulWidget {
final bool popTwice; final bool popTwice;
final bool readOnly; final bool readOnly;
const MealWidget( const MealWidget(this._meal, this._recentMealItems, this.popTwice, this.readOnly);
this._meal,
this._recentMealItems,
this.popTwice,
this.readOnly,
);
@override @override
_MealWidgetState createState() => _MealWidgetState(); _MealWidgetState createState() => _MealWidgetState();
@@ -173,8 +168,9 @@ class _MealWidgetState extends State<MealWidget> {
), ),
) )
else else
...widget._meal.mealItems ...widget._meal.mealItems.map(
.map((item) => MealItemEditableFullTile(item, _viewMode, _editing)), (item) => MealItemEditableFullTile(item, _viewMode, _editing),
),
if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails) if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails)
const Divider(), const Divider(),
if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails) if (_viewMode == viewMode.withIngredients || _viewMode == viewMode.withAllDetails)
@@ -201,12 +197,12 @@ class _MealWidgetState extends State<MealWidget> {
planned: widget._meal.plannedNutritionalValues, planned: widget._meal.plannedNutritionalValues,
logged: widget._meal.loggedNutritionalValuesToday, logged: widget._meal.loggedNutritionalValuesToday,
), ),
...widget._meal.diaryEntriesToday.map((item) => Padding( ...widget._meal.diaryEntriesToday.map(
padding: const EdgeInsets.all(8.0), (item) => Padding(
child: Column( padding: const EdgeInsets.all(8.0),
children: [DiaryEntryTile(diaryEntry: item)], child: Column(children: [DiaryEntryTile(diaryEntry: item)]),
), ),
)), ),
], ],
), ),
], ],
@@ -293,11 +289,11 @@ class MealHeader extends StatelessWidget {
required viewMode viewMode, required viewMode viewMode,
required Function() toggleEditing, required Function() toggleEditing,
required Function() toggleViewMode, required Function() toggleViewMode,
}) : _meal = meal, }) : _meal = meal,
_editing = editing, _editing = editing,
_viewMode = viewMode, _viewMode = viewMode,
_toggleViewMode = toggleViewMode, _toggleViewMode = toggleViewMode,
_toggleEditing = toggleEditing; _toggleEditing = toggleEditing;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -306,35 +302,34 @@ class MealHeader extends StatelessWidget {
children: [ children: [
ListTile( ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
title: Row(children: [ title: Row(
Expanded( children: [
child: Column( Expanded(
crossAxisAlignment: CrossAxisAlignment.start, child: Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Text( children: [
_meal.name, Text(_meal.name, style: Theme.of(context).textTheme.titleLarge),
style: Theme.of(context).textTheme.titleLarge, Row(
), children: [
Row( if (_meal.time != null)
children: [ Text(
if (_meal.time != null) _meal.time!.format(context),
style: Theme.of(context).textTheme.titleSmall,
),
if (_meal.time != null) const SizedBox(width: 12),
Text( Text(
_meal.time!.format(context), _meal.isRealMeal
? getKcalConsumedVsPlanned(_meal, context)
: getKcalConsumed(_meal, context),
style: Theme.of(context).textTheme.titleSmall, style: Theme.of(context).textTheme.titleSmall,
), ),
if (_meal.time != null) const SizedBox(width: 12), ],
Text( ),
_meal.isRealMeal ],
? getKcalConsumedVsPlanned(_meal, context) ),
: getKcalConsumed(_meal, context),
style: Theme.of(context).textTheme.titleSmall,
),
],
),
],
), ),
), ],
]), ),
trailing: Row( trailing: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

View File

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/ingredient.dart'; import 'package:wger/models/nutrition/ingredient.dart';
import 'package:wger/models/nutrition/log.dart'; import 'package:wger/models/nutrition/log.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
@@ -18,11 +18,7 @@ class MealItemValuesTile extends StatelessWidget {
final Ingredient ingredient; final Ingredient ingredient;
final NutritionalValues nutritionalValues; final NutritionalValues nutritionalValues;
const MealItemValuesTile({ const MealItemValuesTile({super.key, required this.ingredient, required this.nutritionalValues});
super.key,
required this.ingredient,
required this.nutritionalValues,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -53,11 +49,7 @@ class DiaryheaderTile extends StatelessWidget {
/// a NutritionTitle showing diary entries /// a NutritionTitle showing diary entries
class DiaryEntryTile extends StatelessWidget { class DiaryEntryTile extends StatelessWidget {
const DiaryEntryTile({ const DiaryEntryTile({super.key, required this.diaryEntry, this.nutritionalPlan});
super.key,
required this.diaryEntry,
this.nutritionalPlan,
});
final Log diaryEntry; final Log diaryEntry;
final NutritionalPlan? nutritionalPlan; final NutritionalPlan? nutritionalPlan;
@@ -82,8 +74,10 @@ class DiaryEntryTile extends StatelessWidget {
: IconButton( : IconButton(
tooltip: AppLocalizations.of(context).delete, tooltip: AppLocalizations.of(context).delete,
onPressed: () { onPressed: () {
Provider.of<NutritionPlansProvider>(context, listen: false) Provider.of<NutritionPlansProvider>(
.deleteLog(diaryEntry.id!, nutritionalPlan!.id!); context,
listen: false,
).deleteLog(diaryEntry.id!, nutritionalPlan!.id!);
}, },
icon: const Icon(Icons.delete_outline), icon: const Icon(Icons.delete_outline),
iconSize: ICON_SIZE_SMALL, iconSize: ICON_SIZE_SMALL,

View File

@@ -17,7 +17,7 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/models/nutrition/nutritional_values.dart'; import 'package:wger/models/nutrition/nutritional_values.dart';
import 'package:wger/widgets/nutrition/charts.dart'; import 'package:wger/widgets/nutrition/charts.dart';
@@ -61,20 +61,14 @@ class NutritionalDiaryDetailWidget extends StatelessWidget {
), ),
const SizedBox(height: 15), const SizedBox(height: 15),
const DiaryheaderTile(), const DiaryheaderTile(),
...logs.map( ...logs.map((e) => DiaryEntryTile(diaryEntry: e, nutritionalPlan: _nutritionalPlan)),
(e) => DiaryEntryTile(diaryEntry: e, nutritionalPlan: _nutritionalPlan),
),
], ],
); );
} }
} }
class NutritionDiaryTable extends StatelessWidget { class NutritionDiaryTable extends StatelessWidget {
const NutritionDiaryTable({ const NutritionDiaryTable({super.key, required this.planned, required this.logged});
super.key,
required this.planned,
required this.logged,
});
static const double tablePadding = 7; static const double tablePadding = 7;
final NutritionalValues planned; final NutritionalValues planned;
@@ -85,13 +79,13 @@ class NutritionDiaryTable extends StatelessWidget {
final loc = AppLocalizations.of(context); final loc = AppLocalizations.of(context);
Widget columnHeader(bool left, String title) => Padding( Widget columnHeader(bool left, String title) => Padding(
padding: const EdgeInsets.symmetric(vertical: tablePadding), padding: const EdgeInsets.symmetric(vertical: tablePadding),
child: Text( child: Text(
title, title,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
textAlign: left ? TextAlign.left : TextAlign.right, textAlign: left ? TextAlign.left : TextAlign.right,
), ),
); );
TableRow macroRow(int indent, bool g, String title, double Function(NutritionalValues nv) get) { TableRow macroRow(int indent, bool g, String title, double Function(NutritionalValues nv) get) {
final valFn = g ? loc.gValue : loc.kcalValue; final valFn = g ? loc.gValue : loc.kcalValue;
@@ -115,12 +109,14 @@ class NutritionDiaryTable extends StatelessWidget {
), ),
columnWidths: const {0: FractionColumnWidth(0.4)}, columnWidths: const {0: FractionColumnWidth(0.4)},
children: [ children: [
TableRow(children: [ TableRow(
columnHeader(true, loc.macronutrients), children: [
columnHeader(false, loc.planned), columnHeader(true, loc.macronutrients),
columnHeader(false, loc.logged), columnHeader(false, loc.planned),
columnHeader(false, loc.difference), columnHeader(false, loc.logged),
]), columnHeader(false, loc.difference),
],
),
macroRow(0, false, loc.energy, (NutritionalValues nv) => nv.energy), macroRow(0, false, loc.energy, (NutritionalValues nv) => nv.energy),
macroRow(0, true, loc.protein, (NutritionalValues nv) => nv.protein), macroRow(0, true, loc.protein, (NutritionalValues nv) => nv.protein),
macroRow(0, true, loc.carbohydrates, (NutritionalValues nv) => nv.carbohydrates), macroRow(0, true, loc.carbohydrates, (NutritionalValues nv) => nv.carbohydrates),

View File

@@ -1,17 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:wger/helpers/colors.dart'; import 'package:wger/helpers/colors.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_goals.dart'; import 'package:wger/models/nutrition/nutritional_goals.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/models/nutrition/nutritional_values.dart'; import 'package:wger/models/nutrition/nutritional_values.dart';
import 'package:wger/screens/nutritional_diary_screen.dart'; import 'package:wger/screens/nutritional_diary_screen.dart';
class NutritionalDiaryTable extends StatelessWidget { class NutritionalDiaryTable extends StatelessWidget {
const NutritionalDiaryTable({ const NutritionalDiaryTable({super.key, required NutritionalPlan nutritionalPlan})
super.key, : plan = nutritionalPlan;
required NutritionalPlan nutritionalPlan,
}) : plan = nutritionalPlan;
final NutritionalPlan plan; final NutritionalPlan plan;
@@ -82,46 +80,49 @@ class NutritionalDiaryTable extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.grey[300]!)), border: Border(top: BorderSide(color: Colors.grey[300]!)),
), ),
children: [ children:
Text( [
style: Theme.of(context).textTheme.titleMedium?.copyWith(color: LIST_OF_COLORS3.first), Text(
DateFormat.Md(Localizations.localeOf(context).languageCode).format(date), style: Theme.of(
), context,
Text( ).textTheme.titleMedium?.copyWith(color: LIST_OF_COLORS3.first),
style: Theme.of(context).textTheme.titleMedium, DateFormat.Md(Localizations.localeOf(context).languageCode).format(date),
textAlign: TextAlign.end, ),
values.energy.toStringAsFixed(0), Text(
), style: Theme.of(context).textTheme.titleMedium,
if (goals.energy != null) textAlign: TextAlign.end,
Text( values.energy.toStringAsFixed(0),
style: Theme.of(context).textTheme.titleMedium, ),
textAlign: TextAlign.end, if (goals.energy != null)
(values.energy - goals.energy!).toStringAsFixed(0), Text(
), style: Theme.of(context).textTheme.titleMedium,
Text( textAlign: TextAlign.end,
style: Theme.of(context).textTheme.titleMedium, (values.energy - goals.energy!).toStringAsFixed(0),
textAlign: TextAlign.end, ),
values.protein.toStringAsFixed(0), Text(
), style: Theme.of(context).textTheme.titleMedium,
Text( textAlign: TextAlign.end,
style: Theme.of(context).textTheme.titleMedium, values.protein.toStringAsFixed(0),
textAlign: TextAlign.end, ),
values.carbohydrates.toStringAsFixed(0), Text(
), style: Theme.of(context).textTheme.titleMedium,
Text( textAlign: TextAlign.end,
style: Theme.of(context).textTheme.titleMedium, values.carbohydrates.toStringAsFixed(0),
textAlign: TextAlign.end, ),
values.fat.toStringAsFixed(0), Text(
), style: Theme.of(context).textTheme.titleMedium,
].map((element) { textAlign: TextAlign.end,
return GestureDetector( values.fat.toStringAsFixed(0),
onTap: () => Navigator.of(context).pushNamed( ),
NutritionalDiaryScreen.routeName, ].map((element) {
arguments: NutritionalDiaryArguments(plan.id!, date), return GestureDetector(
), onTap: () => Navigator.of(context).pushNamed(
child: element, NutritionalDiaryScreen.routeName,
); arguments: NutritionalDiaryArguments(plan.id!, date),
}).toList(), ),
child: element,
);
}).toList(),
); );
} }
} }

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/widgets/nutrition/charts.dart'; import 'package:wger/widgets/nutrition/charts.dart';
@@ -34,86 +34,78 @@ class NutritionalPlanDetailWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final nutritionalGoals = _nutritionalPlan.nutritionalGoals; final nutritionalGoals = _nutritionalPlan.nutritionalGoals;
final lastWeightEntry = final lastWeightEntry = Provider.of<BodyWeightProvider>(
Provider.of<BodyWeightProvider>(context, listen: false).getNewestEntry(); context,
final nutritionalGoalsGperKg = listen: false,
lastWeightEntry != null ? nutritionalGoals / lastWeightEntry.weight.toDouble() : null; ).getNewestEntry();
final nutritionalGoalsGperKg = lastWeightEntry != null
? nutritionalGoals / lastWeightEntry.weight.toDouble()
: null;
return SliverList( return SliverList(
delegate: SliverChildListDelegate( delegate: SliverChildListDelegate([
[ SizedBox(
SizedBox( width: 300,
width: 300, child: Padding(
child: Padding( padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(8.0), child: FlNutritionalPlanGoalWidget(nutritionalPlan: _nutritionalPlan),
child: FlNutritionalPlanGoalWidget(
nutritionalPlan: _nutritionalPlan,
),
),
),
const SizedBox(height: 10),
..._nutritionalPlan.meals.map((meal) => MealWidget(
meal,
_nutritionalPlan.dedupMealItems,
false,
false,
)),
MealWidget(
_nutritionalPlan.pseudoMealOthers('Other logs'),
_nutritionalPlan.dedupMealItems,
false,
true,
),
if (nutritionalGoals.isComplete())
Container(
padding: const EdgeInsets.all(15),
height: 220,
child: FlNutritionalPlanPieChartWidget(nutritionalGoals.toValues()),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: MacronutrientsTable(
nutritionalGoals: nutritionalGoals,
plannedValuesPercentage: nutritionalGoals.energyPercentage(),
nutritionalGoalsGperKg: nutritionalGoalsGperKg,
),
),
const Padding(padding: EdgeInsets.all(8.0)),
Text(
AppLocalizations.of(context).logged,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleLarge,
), ),
),
const SizedBox(height: 10),
..._nutritionalPlan.meals.map(
(meal) => MealWidget(meal, _nutritionalPlan.dedupMealItems, false, false),
),
MealWidget(
_nutritionalPlan.pseudoMealOthers('Other logs'),
_nutritionalPlan.dedupMealItems,
false,
true,
),
if (nutritionalGoals.isComplete())
Container( Container(
padding: const EdgeInsets.only(top: 16, left: 8, right: 8), padding: const EdgeInsets.all(15),
height: 300, height: 220,
child: NutritionalDiaryChartWidgetFl( child: FlNutritionalPlanPieChartWidget(nutritionalGoals.toValues()),
nutritionalPlan: _nutritionalPlan, ),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: MacronutrientsTable(
nutritionalGoals: nutritionalGoals,
plannedValuesPercentage: nutritionalGoals.energyPercentage(),
nutritionalGoalsGperKg: nutritionalGoalsGperKg,
),
),
const Padding(padding: EdgeInsets.all(8.0)),
Text(
AppLocalizations.of(context).logged,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleLarge,
),
Container(
padding: const EdgeInsets.only(top: 16, left: 8, right: 8),
height: 300,
child: NutritionalDiaryChartWidgetFl(nutritionalPlan: _nutritionalPlan),
),
if (_nutritionalPlan.logEntriesValues.isNotEmpty)
Padding(
padding: const EdgeInsets.only(bottom: 15, left: 15, right: 15),
child: Column(
children: [
Text(
AppLocalizations.of(context).nutritionalDiary,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(
height: 200,
child: SingleChildScrollView(
child: NutritionalDiaryTable(nutritionalPlan: _nutritionalPlan),
),
),
],
), ),
), ),
if (_nutritionalPlan.logEntriesValues.isNotEmpty) ]),
Padding(
padding: const EdgeInsets.only(bottom: 15, left: 15, right: 15),
child: Column(
children: [
Text(
AppLocalizations.of(context).nutritionalDiary,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(
height: 200,
child: SingleChildScrollView(
child: NutritionalDiaryTable(
nutritionalPlan: _nutritionalPlan,
),
),
),
],
),
),
],
),
); );
} }
} }

View File

@@ -19,9 +19,9 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/screens/nutritional_plan_screen.dart';
@@ -39,8 +39,10 @@ class _NutritionalPlansListState extends State<NutritionalPlansList> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final stream = final stream = Provider.of<NutritionPlansProvider>(
Provider.of<NutritionPlansProvider>(context, listen: false).watchNutritionPlans(); context,
listen: false,
).watchNutritionPlans();
_subscription = stream.listen((plans) { _subscription = stream.listen((plans) {
if (!context.mounted) { if (!context.mounted) {
return; return;
@@ -71,10 +73,9 @@ class _NutritionalPlansListState extends State<NutritionalPlansList> {
return Card( return Card(
child: ListTile( child: ListTile(
onTap: () { onTap: () {
Navigator.of(context).pushNamed( Navigator.of(
NutritionalPlanScreen.routeName, context,
arguments: currentPlan.id, ).pushNamed(NutritionalPlanScreen.routeName, arguments: currentPlan.id);
);
}, },
title: Text(currentPlan.getLabel(context)), title: Text(currentPlan.getLabel(context)),
subtitle: Text( subtitle: Text(
@@ -82,53 +83,56 @@ class _NutritionalPlansListState extends State<NutritionalPlansList> {
Localizations.localeOf(context).languageCode, Localizations.localeOf(context).languageCode,
).format(currentPlan.creationDate), ).format(currentPlan.creationDate),
), ),
trailing: Row(mainAxisSize: MainAxisSize.min, children: [ trailing: Row(
const VerticalDivider(), mainAxisSize: MainAxisSize.min,
IconButton( children: [
icon: const Icon(Icons.delete), const VerticalDivider(),
tooltip: AppLocalizations.of(context).delete, IconButton(
onPressed: () async { icon: const Icon(Icons.delete),
await showDialog( tooltip: AppLocalizations.of(context).delete,
context: context, onPressed: () async {
builder: (BuildContext contextDialog) { await showDialog(
return AlertDialog( context: context,
content: Text( builder: (BuildContext contextDialog) {
AppLocalizations.of(context).confirmDelete(currentPlan.description), return AlertDialog(
), content: Text(
actions: [ AppLocalizations.of(
TextButton( context,
child: Text( ).confirmDelete(currentPlan.description),
MaterialLocalizations.of(context).cancelButtonLabel,
),
onPressed: () => Navigator.of(contextDialog).pop(),
), ),
TextButton( actions: [
child: Text( TextButton(
AppLocalizations.of(context).delete, child: Text(
style: TextStyle( MaterialLocalizations.of(context).cancelButtonLabel,
color: Theme.of(context).colorScheme.error,
), ),
onPressed: () => Navigator.of(contextDialog).pop(),
), ),
onPressed: () { TextButton(
provider.deletePlan(currentPlan.id!); child: Text(
Navigator.of(contextDialog).pop(); AppLocalizations.of(context).delete,
ScaffoldMessenger.of(context).showSnackBar( style: TextStyle(color: Theme.of(context).colorScheme.error),
SnackBar( ),
content: Text( onPressed: () {
AppLocalizations.of(context).successfullyDeleted, provider.deletePlan(currentPlan.id!);
textAlign: TextAlign.center, Navigator.of(contextDialog).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
AppLocalizations.of(context).successfullyDeleted,
textAlign: TextAlign.center,
),
), ),
), );
); },
}, ),
), ],
], );
); },
}, );
); },
}, ),
), ],
]), ),
), ),
); );
}, },

View File

@@ -18,7 +18,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; //import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart'; import 'package:flutter/services.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:flutter_typeahead/flutter_typeahead.dart';
import 'package:flutter_zxing/flutter_zxing.dart'; import 'package:flutter_zxing/flutter_zxing.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
@@ -27,6 +26,7 @@ import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/misc.dart'; import 'package:wger/helpers/misc.dart';
import 'package:wger/helpers/platform.dart'; import 'package:wger/helpers/platform.dart';
import 'package:wger/helpers/ui.dart'; import 'package:wger/helpers/ui.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/ingredient_api.dart'; import 'package:wger/models/exercises/ingredient_api.dart';
import 'package:wger/models/nutrition/ingredient.dart'; import 'package:wger/models/nutrition/ingredient.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
@@ -38,19 +38,19 @@ class ScanReader extends StatelessWidget {
const ScanReader(); const ScanReader();
@override @override
Widget build(BuildContext context) => Scaffold( Widget build(BuildContext context) => Scaffold(
body: ReaderWidget( body: ReaderWidget(
onScan: (result) { onScan: (result) {
// notes: // notes:
// 1. even if result.isValid, result.error is always non-null (and set to "") // 1. even if result.isValid, result.error is always non-null (and set to "")
// 2. i've never encountered scan errors to see when they occur, and // 2. i've never encountered scan errors to see when they occur, and
// i wouldn't know what to do about them anyway, so we simply return // i wouldn't know what to do about them anyway, so we simply return
// result.text in such case (which presumably will be null, or "") // result.text in such case (which presumably will be null, or "")
// 3. when user cancels (swipe left / back button) this code is no longer // 3. when user cancels (swipe left / back button) this code is no longer
// run and the caller receives null // run and the caller receives null
Navigator.pop(context, result.text); Navigator.pop(context, result.text);
}, },
), ),
); );
} }
class IngredientTypeahead extends StatefulWidget { class IngredientTypeahead extends StatefulWidget {
@@ -92,8 +92,9 @@ class _IngredientTypeaheadState extends State<IngredientTypeahead> {
Future<String> readerscan(BuildContext context) async { Future<String> readerscan(BuildContext context) async {
try { try {
final code = await Navigator.of(context) final code = await Navigator.of(
.push<String?>(MaterialPageRoute(builder: (context) => const ScanReader())); context,
).push<String?>(MaterialPageRoute(builder: (context) => const ScanReader()));
if (code == null) { if (code == null) {
return ''; return '';
} }
@@ -152,12 +153,8 @@ class _IngredientTypeaheadState extends State<IngredientTypeahead> {
final url = context.read<NutritionPlansProvider>().baseProvider.auth.serverUrl; final url = context.read<NutritionPlansProvider>().baseProvider.auth.serverUrl;
return ListTile( return ListTile(
leading: suggestion.data.image != null leading: suggestion.data.image != null
? CircleAvatar( ? CircleAvatar(backgroundImage: NetworkImage(url! + suggestion.data.image!))
backgroundImage: NetworkImage(url! + suggestion.data.image!), : const CircleIconAvatar(Icon(Icons.image, color: Colors.grey)),
)
: const CircleIconAvatar(
Icon(Icons.image, color: Colors.grey),
),
title: Text(suggestion.value), title: Text(suggestion.value),
// subtitle: Text(suggestion.data.id.toString()), // subtitle: Text(suggestion.data.id.toString()),
trailing: IconButton( trailing: IconButton(
@@ -217,8 +214,10 @@ class _IngredientTypeaheadState extends State<IngredientTypeahead> {
showDialog( showDialog(
context: context, context: context,
builder: (context) => FutureBuilder<Ingredient?>( builder: (context) => FutureBuilder<Ingredient?>(
future: Provider.of<NutritionPlansProvider>(context, listen: false) future: Provider.of<NutritionPlansProvider>(
.searchIngredientWithCode(barcode), context,
listen: false,
).searchIngredientWithCode(barcode),
builder: (BuildContext context, AsyncSnapshot<Ingredient?> snapshot) { builder: (BuildContext context, AsyncSnapshot<Ingredient?> snapshot) {
return IngredientScanResultDialog(snapshot, barcode, widget.selectIngredient); return IngredientScanResultDialog(snapshot, barcode, widget.selectIngredient);
}, },
@@ -238,9 +237,7 @@ class IngredientAvatar extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ingredient.image != null return ingredient.image != null
? GestureDetector( ? GestureDetector(
child: CircleAvatar( child: CircleAvatar(backgroundImage: NetworkImage(ingredient.image!.image)),
backgroundImage: NetworkImage(ingredient.image!.image),
),
onTap: () async { onTap: () async {
if (ingredient.image!.objectUrl != '') { if (ingredient.image!.objectUrl != '') {
return launchURL(ingredient.image!.objectUrl, context); return launchURL(ingredient.image!.objectUrl, context);

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/user/profile.dart'; import 'package:wger/models/user/profile.dart';
import 'package:wger/providers/user.dart'; import 'package:wger/providers/user.dart';
import 'package:wger/theme/theme.dart'; import 'package:wger/theme/theme.dart';
@@ -132,9 +132,7 @@ class _UserProfileFormState extends State<UserProfileForm> {
context.read<UserProvider>().saveProfile(); context.read<UserProvider>().saveProfile();
Navigator.of(context).pop(); Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(content: Text(AppLocalizations.of(context).successfullySaved)),
content: Text(AppLocalizations.of(context).successfullySaved),
),
); );
}, },
child: Text(AppLocalizations.of(context).save), child: Text(AppLocalizations.of(context).save),

View File

@@ -17,12 +17,12 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/exceptions/http_exception.dart'; import 'package:wger/exceptions/http_exception.dart';
import 'package:wger/helpers/json.dart'; import 'package:wger/helpers/json.dart';
import 'package:wger/helpers/ui.dart'; import 'package:wger/helpers/ui.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/body_weight/weight_entry.dart'; import 'package:wger/models/body_weight/weight_entry.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
@@ -52,10 +52,7 @@ class WeightForm extends StatelessWidget {
// Stop keyboard from appearing // Stop keyboard from appearing
decoration: InputDecoration( decoration: InputDecoration(
labelText: AppLocalizations.of(context).date, labelText: AppLocalizations.of(context).date,
suffixIcon: const Icon( suffixIcon: const Icon(Icons.calendar_today, key: Key('calendarIcon')),
Icons.calendar_today,
key: Key('calendarIcon'),
),
), ),
enableInteractiveSelection: false, enableInteractiveSelection: false,
controller: dateController, controller: dateController,

View File

@@ -17,9 +17,9 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/providers/user.dart'; import 'package:wger/providers/user.dart';
@@ -38,8 +38,9 @@ class WeightOverview extends StatelessWidget {
final weightProvider = Provider.of<BodyWeightProvider>(context, listen: false); final weightProvider = Provider.of<BodyWeightProvider>(context, listen: false);
final plan = Provider.of<NutritionPlansProvider>(context, listen: false).currentPlan; final plan = Provider.of<NutritionPlansProvider>(context, listen: false).currentPlan;
final entriesAll = final entriesAll = weightProvider.items
weightProvider.items.map((e) => MeasurementChartEntry(e.weight, e.date)).toList(); .map((e) => MeasurementChartEntry(e.weight, e.date))
.toList();
final entries7dAvg = moving7dAverage(entriesAll); final entries7dAvg = moving7dAverage(entriesAll);
final unit = weightUnit(profile!.isMetric, context); final unit = weightUnit(profile!.isMetric, context);
@@ -55,10 +56,7 @@ class WeightOverview extends StatelessWidget {
context, context,
), ),
TextButton( TextButton(
onPressed: () => Navigator.pushNamed( onPressed: () => Navigator.pushNamed(context, MeasurementCategoriesScreen.routeName),
context,
MeasurementCategoriesScreen.routeName,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [

View File

@@ -17,14 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/screens/add_exercise_screen.dart'; import 'package:wger/screens/add_exercise_screen.dart';
import 'package:wger/screens/exercises_screen.dart'; import 'package:wger/screens/exercises_screen.dart';
enum _WorkoutAppBarOptions { enum _WorkoutAppBarOptions { list, contribute }
list,
contribute,
}
class WorkoutOverviewAppBar extends StatelessWidget implements PreferredSizeWidget { class WorkoutOverviewAppBar extends StatelessWidget implements PreferredSizeWidget {
const WorkoutOverviewAppBar(); const WorkoutOverviewAppBar();

View File

@@ -18,10 +18,10 @@
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:wger/helpers/charts.dart'; import 'package:wger/helpers/charts.dart';
import 'package:wger/helpers/colors.dart'; import 'package:wger/helpers/colors.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
class LogChartWidgetFl extends StatefulWidget { class LogChartWidgetFl extends StatefulWidget {
final Map _data; final Map _data;
@@ -79,12 +79,8 @@ class _LogChartWidgetFlState extends State<LogChartWidgetFl> {
), ),
titlesData: FlTitlesData( titlesData: FlTitlesData(
show: true, show: true,
rightTitles: const AxisTitles( rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
sideTitles: SideTitles(showTitles: false), topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles( bottomTitles: AxisTitles(
sideTitles: SideTitles( sideTitles: SideTitles(
showTitles: true, showTitles: true,
@@ -116,10 +112,7 @@ class _LogChartWidgetFlState extends State<LogChartWidgetFl> {
), ),
), ),
), ),
borderData: FlBorderData( borderData: FlBorderData(show: true, border: Border.all(color: const Color(0xff37434d))),
show: true,
border: Border.all(color: const Color(0xff37434d)),
),
lineBarsData: [ lineBarsData: [
...widget._data['chart_data'].map((e) { ...widget._data['chart_data'].map((e) {
colors.moveNext(); colors.moveNext();
@@ -138,11 +131,8 @@ class _LogChartWidgetFlState extends State<LogChartWidgetFl> {
isStrokeCapRound: true, isStrokeCapRound: true,
dotData: FlDotData( dotData: FlDotData(
show: true, show: true,
getDotPainter: (p0, p1, p2, p3) => FlDotCirclePainter( getDotPainter: (p0, p1, p2, p3) =>
radius: 2, FlDotCirclePainter(radius: 2, color: Colors.black, strokeWidth: 0),
color: Colors.black,
strokeWidth: 0,
),
), ),
); );
}), }),

View File

@@ -17,9 +17,9 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/day.dart'; import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/set.dart'; import 'package:wger/models/workouts/set.dart';
import 'package:wger/models/workouts/setting.dart'; import 'package:wger/models/workouts/setting.dart';
@@ -57,15 +57,15 @@ class SettingWidget extends StatelessWidget {
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return AlertDialog(
title: Text(setting.exerciseObj title: Text(
.getExercise(Localizations.localeOf(context).languageCode) setting.exerciseObj
.name), .getExercise(Localizations.localeOf(context).languageCode)
.name,
),
content: ExerciseDetail(setting.exerciseObj), content: ExerciseDetail(setting.exerciseObj),
actions: [ actions: [
TextButton( TextButton(
child: Text( child: Text(MaterialLocalizations.of(context).closeButtonLabel),
MaterialLocalizations.of(context).closeButtonLabel,
),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@@ -81,9 +81,7 @@ class SettingWidget extends StatelessWidget {
), ),
subtitle: Column( subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [...set.getSmartRepr(setting.exerciseObj).map((e) => Text(e))],
...set.getSmartRepr(setting.exerciseObj).map((e) => Text(e)),
],
), ),
); );
} }
@@ -149,10 +147,7 @@ class _WorkoutDayWidgetState extends State<WorkoutDayWidget> {
if (_editing) if (_editing)
ReorderableDragStartListener( ReorderableDragStartListener(
index: index, index: index,
child: const IconButton( child: const IconButton(icon: Icon(Icons.drag_handle), onPressed: null),
icon: Icon(Icons.drag_handle),
onPressed: null,
),
), ),
], ],
); );
@@ -167,11 +162,7 @@ class _WorkoutDayWidgetState extends State<WorkoutDayWidget> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
DayHeader( DayHeader(day: widget._day, expanded: _editing, toggle: _toggleExpanded),
day: widget._day,
expanded: _editing,
toggle: _toggleExpanded,
),
if (_editing) if (_editing)
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
@@ -265,13 +256,10 @@ class DayHeader extends StatelessWidget {
final bool _editing; final bool _editing;
final Function _toggle; final Function _toggle;
const DayHeader({ const DayHeader({required Day day, required bool expanded, required Function toggle})
required Day day, : _day = day,
required bool expanded, _editing = expanded,
required Function toggle, _toggle = toggle;
}) : _day = day,
_editing = expanded,
_toggle = toggle;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -285,22 +273,24 @@ class DayHeader extends StatelessWidget {
subtitle: Text(_day.getDaysTextTranslated(Localizations.localeOf(context).languageCode)), subtitle: Text(_day.getDaysTextTranslated(Localizations.localeOf(context).languageCode)),
leading: const Icon(Icons.play_arrow), leading: const Icon(Icons.play_arrow),
minLeadingWidth: 8, minLeadingWidth: 8,
trailing: Row(mainAxisSize: MainAxisSize.min, children: [ trailing: Row(
const SizedBox(height: 40, width: 1, child: VerticalDivider()), mainAxisSize: MainAxisSize.min,
const SizedBox(width: 10), children: [
IconButton( const SizedBox(height: 40, width: 1, child: VerticalDivider()),
icon: _editing ? const Icon(Icons.done) : const Icon(Icons.edit), const SizedBox(width: 10),
tooltip: _editing ? AppLocalizations.of(context).done : AppLocalizations.of(context).edit, IconButton(
onPressed: () { icon: _editing ? const Icon(Icons.done) : const Icon(Icons.edit),
_toggle(); tooltip: _editing
}, ? AppLocalizations.of(context).done
), : AppLocalizations.of(context).edit,
]), onPressed: () {
_toggle();
},
),
],
),
onTap: () { onTap: () {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(GymModeScreen.routeName, arguments: _day);
GymModeScreen.routeName,
arguments: _day,
);
}, },
); );
} }

View File

@@ -17,10 +17,10 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/workouts/day.dart'; import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/repetition_unit.dart'; import 'package:wger/models/workouts/repetition_unit.dart';
@@ -72,9 +72,7 @@ class WorkoutForm extends StatelessWidget {
), ),
TextFormField( TextFormField(
key: const Key('field-description'), key: const Key('field-description'),
decoration: InputDecoration( decoration: InputDecoration(labelText: AppLocalizations.of(context).description),
labelText: AppLocalizations.of(context).description,
),
minLines: 3, minLines: 3,
maxLines: 10, maxLines: 10,
controller: workoutDescriptionController, controller: workoutDescriptionController,
@@ -113,10 +111,9 @@ class WorkoutForm extends StatelessWidget {
listen: false, listen: false,
).addWorkout(_plan); ).addWorkout(_plan);
if (context.mounted) { if (context.mounted) {
Navigator.of(context).pushReplacementNamed( Navigator.of(
WorkoutPlanScreen.routeName, context,
arguments: newPlan, ).pushReplacementNamed(WorkoutPlanScreen.routeName, arguments: newPlan);
);
} }
} }
}, },
@@ -142,10 +139,9 @@ class _DayCheckboxState extends State<DayCheckbox> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return CheckboxListTile( return CheckboxListTile(
key: Key('field-checkbox-${widget._dayNr}'), key: Key('field-checkbox-${widget._dayNr}'),
title: Text(widget._day.getDayTranslated( title: Text(
widget._dayNr, widget._day.getDayTranslated(widget._dayNr, Localizations.localeOf(context).languageCode),
Localizations.localeOf(context).languageCode, ),
)),
value: widget._day.daysOfWeek.contains(widget._dayNr), value: widget._day.daysOfWeek.contains(widget._dayNr),
onChanged: (bool? newValue) { onChanged: (bool? newValue) {
setState(() { setState(() {
@@ -223,14 +219,12 @@ class _DayFormWidgetState extends State<DayFormWidget> {
try { try {
if (widget._day.id == null) { if (widget._day.id == null) {
Provider.of<WorkoutPlansProvider>(context, listen: false).addDay( Provider.of<WorkoutPlansProvider>(
widget._day, context,
widget.workout, listen: false,
); ).addDay(widget._day, widget.workout);
} else { } else {
Provider.of<WorkoutPlansProvider>(context, listen: false).editDay( Provider.of<WorkoutPlansProvider>(context, listen: false).editDay(widget._day);
widget._day,
);
} }
widget.dayController.clear(); widget.dayController.clear();
@@ -442,22 +436,16 @@ class _SetFormWidgetState extends State<SetFormWidget> {
return null; return null;
} }
return context.read<ExercisesProvider>().searchExercise( return context.read<ExercisesProvider>().searchExercise(
pattern, pattern,
languageCode: Localizations.localeOf(context).languageCode, languageCode: Localizations.localeOf(context).languageCode,
searchEnglish: _searchEnglish, searchEnglish: _searchEnglish,
); );
}, },
itemBuilder: ( itemBuilder: (BuildContext context, Exercise exerciseSuggestion) => ListTile(
BuildContext context,
Exercise exerciseSuggestion,
) =>
ListTile(
key: Key('exercise-${exerciseSuggestion.id}'), key: Key('exercise-${exerciseSuggestion.id}'),
leading: SizedBox( leading: SizedBox(
width: 45, width: 45,
child: ExerciseImageWidget( child: ExerciseImageWidget(image: exerciseSuggestion.getMainImage),
image: exerciseSuggestion.getMainImage,
),
), ),
title: Text( title: Text(
exerciseSuggestion exerciseSuggestion
@@ -487,10 +475,7 @@ class _SetFormWidgetState extends State<SetFormWidget> {
); );
}, },
transitionBuilder: (context, animation, child) => FadeTransition( transitionBuilder: (context, animation, child) => FadeTransition(
opacity: CurvedAnimation( opacity: CurvedAnimation(parent: animation, curve: Curves.fastOutSlowIn),
parent: animation,
curve: Curves.fastOutSlowIn,
),
child: child, child: child,
), ),
onSelected: (Exercise exerciseSuggestion) { onSelected: (Exercise exerciseSuggestion) {
@@ -538,8 +523,9 @@ class _SetFormWidgetState extends State<SetFormWidget> {
final index = entry.key; final index = entry.key;
final exercise = entry.value; final exercise = entry.value;
final showSupersetInfo = (index + 1) < widget._set.exerciseBasesObj.length; final showSupersetInfo = (index + 1) < widget._set.exerciseBasesObj.length;
final settings = final settings = widget._set.settings
widget._set.settings.where((e) => e.exerciseObj.id == exercise.id).toList(); .where((e) => e.exerciseObj.id == exercise.id)
.toList();
return Column( return Column(
children: [ children: [
@@ -551,16 +537,10 @@ class _SetFormWidgetState extends State<SetFormWidget> {
removeExerciseBase, removeExerciseBase,
), ),
if (showSupersetInfo) if (showSupersetInfo)
const Padding( const Padding(padding: EdgeInsets.all(3.0), child: Text('+')),
padding: EdgeInsets.all(3.0),
child: Text('+'),
),
if (showSupersetInfo) Text(AppLocalizations.of(context).supersetWith), if (showSupersetInfo) Text(AppLocalizations.of(context).supersetWith),
if (showSupersetInfo) if (showSupersetInfo)
const Padding( const Padding(padding: EdgeInsets.all(3.0), child: Text('+')),
padding: EdgeInsets.all(3.0),
child: Text('+'),
),
], ],
); );
}), }),
@@ -648,29 +628,17 @@ class ExerciseSetting extends StatelessWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Flexible( Flexible(flex: 2, child: RepsInputWidget(setting, _detailed)),
flex: 2,
child: RepsInputWidget(setting, _detailed),
),
const SizedBox(width: 4), const SizedBox(width: 4),
Flexible( Flexible(flex: 3, child: RepetitionUnitInputWidget(setting)),
flex: 3,
child: RepetitionUnitInputWidget(setting),
),
], ],
), ),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Flexible( Flexible(flex: 2, child: WeightInputWidget(setting, _detailed)),
flex: 2,
child: WeightInputWidget(setting, _detailed),
),
const SizedBox(width: 4), const SizedBox(width: 4),
Flexible( Flexible(flex: 3, child: WeightUnitInputWidget(setting, key: Key(i.toString()))),
flex: 3,
child: WeightUnitInputWidget(setting, key: Key(i.toString())),
),
], ],
), ),
Flexible(flex: 2, child: RiRInputWidget(setting)), Flexible(flex: 2, child: RiRInputWidget(setting)),
@@ -919,15 +887,15 @@ class _WeightUnitInputWidgetState extends State<WeightUnitInputWidget> {
widget._setting.weightUnit = newValue; widget._setting.weightUnit = newValue;
}); });
}, },
items: Provider.of<WorkoutPlansProvider>(context, listen: false) items: Provider.of<WorkoutPlansProvider>(context, listen: false).weightUnits
.weightUnits
.map<DropdownMenuItem<WeightUnit>>((WeightUnit value) { .map<DropdownMenuItem<WeightUnit>>((WeightUnit value) {
return DropdownMenuItem<WeightUnit>( return DropdownMenuItem<WeightUnit>(
key: Key(value.id.toString()), key: Key(value.id.toString()),
value: value, value: value,
child: Text(value.name), child: Text(value.name),
); );
}).toList(), })
.toList(),
); );
} }
} }
@@ -951,9 +919,7 @@ class _RepetitionUnitInputWidgetState extends State<RepetitionUnitInputWidget> {
return DropdownButtonFormField( return DropdownButtonFormField(
value: selectedWeightUnit, value: selectedWeightUnit,
decoration: InputDecoration( decoration: InputDecoration(labelText: AppLocalizations.of(context).repetitionUnit),
labelText: AppLocalizations.of(context).repetitionUnit,
),
isDense: true, isDense: true,
onChanged: (RepetitionUnit? newValue) { onChanged: (RepetitionUnit? newValue) {
setState(() { setState(() {
@@ -961,15 +927,15 @@ class _RepetitionUnitInputWidgetState extends State<RepetitionUnitInputWidget> {
widget._setting.repetitionUnit = newValue; widget._setting.repetitionUnit = newValue;
}); });
}, },
items: Provider.of<WorkoutPlansProvider>(context, listen: false) items: Provider.of<WorkoutPlansProvider>(context, listen: false).repetitionUnits
.repetitionUnits
.map<DropdownMenuItem<RepetitionUnit>>((RepetitionUnit value) { .map<DropdownMenuItem<RepetitionUnit>>((RepetitionUnit value) {
return DropdownMenuItem<RepetitionUnit>( return DropdownMenuItem<RepetitionUnit>(
key: Key(value.id.toString()), key: Key(value.id.toString()),
value: value, value: value,
child: Text(value.name), child: Text(value.name),
); );
}).toList(), })
.toList(),
); );
} }
} }

View File

@@ -18,7 +18,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_html/flutter_html.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -27,8 +26,8 @@ import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/gym_mode.dart'; import 'package:wger/helpers/gym_mode.dart';
import 'package:wger/helpers/i18n.dart'; import 'package:wger/helpers/i18n.dart';
import 'package:wger/helpers/json.dart'; import 'package:wger/helpers/json.dart';
import 'package:wger/helpers/misc.dart';
import 'package:wger/helpers/ui.dart'; import 'package:wger/helpers/ui.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/workouts/day.dart'; import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/log.dart'; import 'package:wger/models/workouts/log.dart';
@@ -83,8 +82,10 @@ class _GymModeState extends State<GymMode> {
for (final set in widget._workoutDay.sets) { for (final set in widget._workoutDay.sets) {
var firstPage = true; var firstPage = true;
for (final setting in set.settingsComputed) { for (final setting in set.settingsComputed) {
final exerciseBase = Provider.of<ExercisesProvider>(context, listen: false) final exerciseBase = Provider.of<ExercisesProvider>(
.findExerciseById(setting.exerciseId); context,
listen: false,
).findExerciseById(setting.exerciseId);
if (firstPage) { if (firstPage) {
_exercisePages[exerciseBase] = currentPage; _exercisePages[exerciseBase] = currentPage;
@@ -116,23 +117,20 @@ class _GymModeState extends State<GymMode> {
currentElement++; currentElement++;
if (firstPage) { if (firstPage) {
out.add(ExerciseOverview( out.add(ExerciseOverview(_controller, exerciseBase, ratioCompleted, _exercisePages));
_controller,
exerciseBase,
ratioCompleted,
_exercisePages,
));
} }
out.add(LogPage( out.add(
_controller, LogPage(
setting, _controller,
set, setting,
exerciseBase, set,
workoutProvider.findById(widget._workoutDay.workoutId), exerciseBase,
ratioCompleted, workoutProvider.findById(widget._workoutDay.workoutId),
_exercisePages, ratioCompleted,
)); _exercisePages,
),
);
out.add(TimerWidget(_controller, ratioCompleted, _exercisePages)); out.add(TimerWidget(_controller, ratioCompleted, _exercisePages));
firstPage = false; firstPage = false;
} }
@@ -149,8 +147,10 @@ class _GymModeState extends State<GymMode> {
StartPage(_controller, widget._workoutDay, _exercisePages), StartPage(_controller, widget._workoutDay, _exercisePages),
...getContent(), ...getContent(),
SessionPage( SessionPage(
Provider.of<WorkoutPlansProvider>(context, listen: false) Provider.of<WorkoutPlansProvider>(
.findById(widget._workoutDay.workoutId), context,
listen: false,
).findById(widget._workoutDay.workoutId),
_controller, _controller,
widget._start, widget._start,
_exercisePages, _exercisePages,
@@ -298,9 +298,7 @@ class _LogPageState extends State<LogPage> {
), ),
Expanded( Expanded(
child: TextFormField( child: TextFormField(
decoration: InputDecoration( decoration: InputDecoration(labelText: AppLocalizations.of(context).repetitions),
labelText: AppLocalizations.of(context).repetitions,
),
enabled: true, enabled: true,
controller: _repsController, controller: _repsController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
@@ -353,9 +351,7 @@ class _LogPageState extends State<LogPage> {
), ),
Expanded( Expanded(
child: TextFormField( child: TextFormField(
decoration: InputDecoration( decoration: InputDecoration(labelText: AppLocalizations.of(context).weight),
labelText: AppLocalizations.of(context).weight,
),
controller: _weightController, controller: _weightController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
onFieldSubmitted: (_) {}, onFieldSubmitted: (_) {},
@@ -512,9 +508,9 @@ class _LogPageState extends State<LogPage> {
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
...widget._workoutPlan ...widget._workoutPlan.filterLogsByExerciseBase(widget._exerciseBase, unique: true).map((
.filterLogsByExerciseBase(widget._exerciseBase, unique: true) log,
.map((log) { ) {
return ListTile( return ListTile(
title: Text(log.singleLogRepTextNoNl), title: Text(log.singleLogRepTextNoNl),
subtitle: Text( subtitle: Text(
@@ -533,9 +529,9 @@ class _LogPageState extends State<LogPage> {
widget._log.weightUnit = log.weightUnitObj; widget._log.weightUnit = log.weightUnitObj;
ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(
content: Text(AppLocalizations.of(context).dataCopied), context,
)); ).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).dataCopied)));
}); });
}, },
contentPadding: const EdgeInsets.symmetric(horizontal: 40), contentPadding: const EdgeInsets.symmetric(horizontal: 40),
@@ -584,9 +580,7 @@ class _LogPageState extends State<LogPage> {
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
key.toString(), key.toString(),
style: const TextStyle( style: const TextStyle(fontWeight: FontWeight.bold),
fontWeight: FontWeight.bold,
),
), ),
), ),
), ),
@@ -598,9 +592,7 @@ class _LogPageState extends State<LogPage> {
), ),
], ],
) )
: MutedText( : MutedText(AppLocalizations.of(context).plateCalculatorNotDivisible),
AppLocalizations.of(context).plateCalculatorNotDivisible,
),
), ),
const SizedBox(height: 3), const SizedBox(height: 3),
], ],
@@ -676,20 +668,20 @@ class ExerciseOverview extends StatelessWidget {
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
..._exerciseBase.equipment.map((e) => Text( ..._exerciseBase.equipment.map(
getTranslation(e.name, context), (e) => Text(
style: Theme.of(context).textTheme.titleLarge, getTranslation(e.name, context),
textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleLarge,
)), textAlign: TextAlign.center,
),
),
if (_exerciseBase.images.isNotEmpty) if (_exerciseBase.images.isNotEmpty)
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
height: 200, height: 200,
child: ListView( child: ListView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
children: [ children: [..._exerciseBase.images.map((e) => ExerciseImageWidget(image: e))],
..._exerciseBase.images.map((e) => ExerciseImageWidget(image: e)),
],
), ),
), ),
Html( Html(
@@ -712,12 +704,7 @@ class SessionPage extends StatefulWidget {
final TimeOfDay _start; final TimeOfDay _start;
final Map<Exercise, int> _exercisePages; final Map<Exercise, int> _exercisePages;
const SessionPage( const SessionPage(this._workoutPlan, this._controller, this._start, this._exercisePages);
this._workoutPlan,
this._controller,
this._start,
this._exercisePages,
);
@override @override
_SessionPageState createState() => _SessionPageState(); _SessionPageState createState() => _SessionPageState();
@@ -777,9 +764,11 @@ class _SessionPageState extends State<SessionPage> {
renderBorder: false, renderBorder: false,
onPressed: (int index) { onPressed: (int index) {
setState(() { setState(() {
for (int buttonIndex = 0; for (
buttonIndex < selectedImpression.length; int buttonIndex = 0;
buttonIndex++) { buttonIndex < selectedImpression.length;
buttonIndex++
) {
_session.impression = index + 1; _session.impression = index + 1;
if (buttonIndex == index) { if (buttonIndex == index) {
@@ -798,9 +787,7 @@ class _SessionPageState extends State<SessionPage> {
], ],
), ),
TextFormField( TextFormField(
decoration: InputDecoration( decoration: InputDecoration(labelText: AppLocalizations.of(context).notes),
labelText: AppLocalizations.of(context).notes,
),
maxLines: 3, maxLines: 3,
controller: notesController, controller: notesController,
keyboardType: TextInputType.multiline, keyboardType: TextInputType.multiline,
@@ -922,11 +909,7 @@ class TimerWidget extends StatefulWidget {
final double _ratioCompleted; final double _ratioCompleted;
final Map<Exercise, int> _exercisePages; final Map<Exercise, int> _exercisePages;
const TimerWidget( const TimerWidget(this._controller, this._ratioCompleted, this._exercisePages);
this._controller,
this._ratioCompleted,
this._exercisePages,
);
@override @override
_TimerWidgetState createState() => _TimerWidgetState(); _TimerWidgetState createState() => _TimerWidgetState();
@@ -1054,18 +1037,11 @@ class NavigationHeader extends StatelessWidget {
final String _title; final String _title;
final Map<Exercise, int> exercisePages; final Map<Exercise, int> exercisePages;
const NavigationHeader( const NavigationHeader(this._title, this._controller, {required this.exercisePages});
this._title,
this._controller, {
required this.exercisePages,
});
Widget getDialog(BuildContext context) { Widget getDialog(BuildContext context) {
return AlertDialog( return AlertDialog(
title: Text( title: Text(AppLocalizations.of(context).jumpTo, textAlign: TextAlign.center),
AppLocalizations.of(context).jumpTo,
textAlign: TextAlign.center,
),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
content: SingleChildScrollView( content: SingleChildScrollView(
child: Column( child: Column(
@@ -1121,10 +1097,7 @@ class NavigationHeader extends StatelessWidget {
IconButton( IconButton(
icon: const Icon(Icons.toc), icon: const Icon(Icons.toc),
onPressed: () { onPressed: () {
showDialog( showDialog(context: context, builder: (ctx) => getDialog(context));
context: context,
builder: (ctx) => getDialog(context),
);
}, },
), ),
], ],

View File

@@ -17,9 +17,9 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:table_calendar/table_calendar.dart'; import 'package:table_calendar/table_calendar.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/exercise.dart'; import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/workouts/log.dart'; import 'package:wger/models/workouts/log.dart';
import 'package:wger/models/workouts/session.dart'; import 'package:wger/models/workouts/session.dart';
@@ -70,10 +70,7 @@ class _WorkoutLogsState extends State<WorkoutLogs> {
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Text( child: Text(AppLocalizations.of(context).logHelpEntries, textAlign: TextAlign.justify),
AppLocalizations.of(context).logHelpEntries,
textAlign: TextAlign.justify,
),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@@ -82,10 +79,7 @@ class _WorkoutLogsState extends State<WorkoutLogs> {
textAlign: TextAlign.justify, textAlign: TextAlign.justify,
), ),
), ),
SizedBox( SizedBox(width: double.infinity, child: WorkoutLogCalendar(widget._workoutPlan)),
width: double.infinity,
child: WorkoutLogCalendar(widget._workoutPlan),
),
], ],
); );
} }

View File

@@ -17,7 +17,7 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/workout_plan.dart'; import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
import 'package:wger/screens/workout_plan_screen.dart'; import 'package:wger/screens/workout_plan_screen.dart';
@@ -50,17 +50,11 @@ class _WorkoutPlanDetailState extends State<WorkoutPlanDetail> {
} }
}, },
isSelected: const [true, false], isSelected: const [true, false],
children: const [ children: const [Icon(Icons.table_chart), Icon(Icons.show_chart)],
Icon(Icons.table_chart),
Icon(Icons.show_chart),
],
), ),
), ),
if (widget._workoutPlan.description != '') if (widget._workoutPlan.description != '')
Padding( Padding(padding: const EdgeInsets.all(15), child: Text(widget._workoutPlan.description)),
padding: const EdgeInsets.all(15),
child: Text(widget._workoutPlan.description),
),
...widget._workoutPlan.days.map((workoutDay) => WorkoutDayWidget(workoutDay)), ...widget._workoutPlan.days.map((workoutDay) => WorkoutDayWidget(workoutDay)),
Column( Column(
children: [ children: [

View File

@@ -17,9 +17,9 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/workout_plan_screen.dart'; import 'package:wger/screens/workout_plan_screen.dart';
import 'package:wger/widgets/core/text_prompt.dart'; import 'package:wger/widgets/core/text_prompt.dart';
@@ -46,10 +46,9 @@ class WorkoutPlansList extends StatelessWidget {
onTap: () { onTap: () {
_workoutProvider.setCurrentPlan(currentWorkout.id!); _workoutProvider.setCurrentPlan(currentWorkout.id!);
Navigator.of(context).pushNamed( Navigator.of(
WorkoutPlanScreen.routeName, context,
arguments: currentWorkout, ).pushNamed(WorkoutPlanScreen.routeName, arguments: currentWorkout);
);
}, },
title: Text(currentWorkout.name), title: Text(currentWorkout.name),
subtitle: Text( subtitle: Text(
@@ -57,62 +56,65 @@ class WorkoutPlansList extends StatelessWidget {
Localizations.localeOf(context).languageCode, Localizations.localeOf(context).languageCode,
).format(currentWorkout.creationDate), ).format(currentWorkout.creationDate),
), ),
trailing: Row(mainAxisSize: MainAxisSize.min, children: [ trailing: Row(
const VerticalDivider(), mainAxisSize: MainAxisSize.min,
IconButton( children: [
icon: const Icon(Icons.delete), const VerticalDivider(),
tooltip: AppLocalizations.of(context).delete, IconButton(
onPressed: () async { icon: const Icon(Icons.delete),
// Delete workout from DB tooltip: AppLocalizations.of(context).delete,
await showDialog( onPressed: () async {
context: context, // Delete workout from DB
builder: (BuildContext contextDialog) { await showDialog(
return AlertDialog( context: context,
content: Text( builder: (BuildContext contextDialog) {
AppLocalizations.of(context).confirmDelete(currentWorkout.name), return AlertDialog(
), content: Text(
actions: [ AppLocalizations.of(context).confirmDelete(currentWorkout.name),
TextButton(
child: Text(
MaterialLocalizations.of(context).cancelButtonLabel,
),
onPressed: () => Navigator.of(contextDialog).pop(),
), ),
TextButton( actions: [
child: Text( TextButton(
AppLocalizations.of(context).delete, child: Text(
style: TextStyle( MaterialLocalizations.of(context).cancelButtonLabel,
color: Theme.of(context).colorScheme.error,
), ),
onPressed: () => Navigator.of(contextDialog).pop(),
), ),
onPressed: () { TextButton(
// Confirmed, delete the workout child: Text(
Provider.of<WorkoutPlansProvider>( AppLocalizations.of(context).delete,
context, style: TextStyle(
listen: false, color: Theme.of(context).colorScheme.error,
).deleteWorkout(currentWorkout.id!);
// Close the popup
Navigator.of(contextDialog).pop();
// and inform the user
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
AppLocalizations.of(context).successfullyDeleted,
textAlign: TextAlign.center,
),
), ),
); ),
}, onPressed: () {
), // Confirmed, delete the workout
], Provider.of<WorkoutPlansProvider>(
); context,
}, listen: false,
); ).deleteWorkout(currentWorkout.id!);
},
), // Close the popup
]), Navigator.of(contextDialog).pop();
// and inform the user
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
AppLocalizations.of(context).successfullyDeleted,
textAlign: TextAlign.center,
),
),
);
},
),
],
);
},
);
},
),
],
),
), ),
); );
}, },

View File

@@ -19,7 +19,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:http/http.dart'; import 'package:http/http.dart';
@@ -28,6 +27,7 @@ import 'package:mockito/mockito.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/auth.dart'; import 'package:wger/providers/auth.dart';
import 'package:wger/screens/auth_screen.dart'; import 'package:wger/screens/auth_screen.dart';
@@ -38,17 +38,9 @@ void main() {
late AuthProvider authProvider; late AuthProvider authProvider;
late MockClient mockClient; late MockClient mockClient;
final Uri tRegistration = Uri( final Uri tRegistration = Uri(scheme: 'https', host: 'wger.de', path: 'api/v2/register/');
scheme: 'https',
host: 'wger.de',
path: 'api/v2/register/',
);
final Uri tLogin = Uri( final Uri tLogin = Uri(scheme: 'https', host: 'wger.de', path: 'api/v2/login/');
scheme: 'https',
host: 'wger.de',
path: 'api/v2/login/',
);
final responseLoginOk = {'token': 'b01c44d3e3e016a615d2f82b16d31f8b924fb936'}; final responseLoginOk = {'token': 'b01c44d3e3e016a615d2f82b16d31f8b924fb936'};
@@ -85,19 +77,15 @@ void main() {
buildSignature: 'buildSignature', buildSignature: 'buildSignature',
); );
when(mockClient.post( when(
tLogin, mockClient.post(tLogin, headers: anyNamed('headers'), body: anyNamed('body')),
headers: anyNamed('headers'), ).thenAnswer((_) => Future(() => Response(json.encode(responseLoginOk), 200)));
body: anyNamed('body'),
)).thenAnswer((_) => Future(() => Response(json.encode(responseLoginOk), 200)));
when(mockClient.get(any)).thenAnswer((_) => Future(() => Response('"1.2.3.4"', 200))); when(mockClient.get(any)).thenAnswer((_) => Future(() => Response('"1.2.3.4"', 200)));
when(mockClient.post( when(
tRegistration, mockClient.post(tRegistration, headers: anyNamed('headers'), body: anyNamed('body')),
headers: anyNamed('headers'), ).thenAnswer((_) => Future(() => Response(json.encode(responseRegistrationOk), 201)));
body: anyNamed('body'),
)).thenAnswer((_) => Future(() => Response(json.encode(responseRegistrationOk), 201)));
}); });
group('Login mode', () { group('Login mode', () {
@@ -134,11 +122,13 @@ void main() {
// Assert // Assert
expect(find.textContaining('An Error Occurred'), findsNothing); expect(find.textContaining('An Error Occurred'), findsNothing);
verify(mockClient.get(any)); verify(mockClient.get(any));
verify(mockClient.post( verify(
tLogin, mockClient.post(
headers: anyNamed('headers'), tLogin,
body: json.encode({'username': 'testuser', 'password': '123456789'}), headers: anyNamed('headers'),
)); body: json.encode({'username': 'testuser', 'password': '123456789'}),
),
);
}); });
testWidgets('Login - wront username & password', (WidgetTester tester) async { testWidgets('Login - wront username & password', (WidgetTester tester) async {
@@ -149,11 +139,9 @@ void main() {
'non_field_errors': ['Username or password unknown'], 'non_field_errors': ['Username or password unknown'],
}; };
when(mockClient.post( when(
tLogin, mockClient.post(tLogin, headers: anyNamed('headers'), body: anyNamed('body')),
headers: anyNamed('headers'), ).thenAnswer((_) => Future(() => Response(json.encode(response), 400)));
body: anyNamed('body'),
)).thenAnswer((_) => Future(() => Response(json.encode(response), 400)));
await tester.pumpWidget(getWidget()); await tester.pumpWidget(getWidget());
// Act // Act
@@ -166,11 +154,13 @@ void main() {
expect(find.textContaining('An Error Occurred'), findsOne); expect(find.textContaining('An Error Occurred'), findsOne);
expect(find.textContaining('Non field errors'), findsOne); expect(find.textContaining('Non field errors'), findsOne);
expect(find.textContaining('Username or password unknown'), findsOne); expect(find.textContaining('Username or password unknown'), findsOne);
verify(mockClient.post( verify(
tLogin, mockClient.post(
headers: anyNamed('headers'), tLogin,
body: json.encode({'username': 'testuser', 'password': '123456789'}), headers: anyNamed('headers'),
)); body: json.encode({'username': 'testuser', 'password': '123456789'}),
),
);
}); });
}); });
@@ -219,11 +209,13 @@ void main() {
// Assert // Assert
expect(find.textContaining('An Error Occurred'), findsNothing); expect(find.textContaining('An Error Occurred'), findsNothing);
verify(mockClient.post( verify(
tRegistration, mockClient.post(
headers: anyNamed('headers'), tRegistration,
body: json.encode({'username': 'testuser', 'password': '123456789'}), headers: anyNamed('headers'),
)); body: json.encode({'username': 'testuser', 'password': '123456789'}),
),
);
}); });
testWidgets('Registration - password problems', (WidgetTester tester) async { testWidgets('Registration - password problems', (WidgetTester tester) async {
@@ -232,17 +224,12 @@ void main() {
tester.view.devicePixelRatio = 1.0; tester.view.devicePixelRatio = 1.0;
final response = { final response = {
'username': ['This field must be unique.'], 'username': ['This field must be unique.'],
'password': [ 'password': ['This password is too common.', 'This password is entirely numeric.'],
'This password is too common.',
'This password is entirely numeric.',
],
}; };
when(mockClient.post( when(
tRegistration, mockClient.post(tRegistration, headers: anyNamed('headers'), body: anyNamed('body')),
headers: anyNamed('headers'), ).thenAnswer((_) => Future(() => Response(json.encode(response), 400)));
body: anyNamed('body'),
)).thenAnswer((_) => Future(() => Response(json.encode(response), 400)));
await tester.pumpWidget(getWidget()); await tester.pumpWidget(getWidget());
// Act // Act
@@ -259,11 +246,13 @@ void main() {
expect(find.textContaining('This password is entirely numeric'), findsOne); expect(find.textContaining('This password is entirely numeric'), findsOne);
expect(find.textContaining('This field must be unique'), findsOne); expect(find.textContaining('This field must be unique'), findsOne);
verify(mockClient.post( verify(
tRegistration, mockClient.post(
headers: anyNamed('headers'), tRegistration,
body: json.encode({'username': 'testuser', 'password': '123456789'}), headers: anyNamed('headers'),
)); body: json.encode({'username': 'testuser', 'password': '123456789'}),
),
);
}); });
}); });
} }

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/widgets/core/settings.dart'; import 'package:wger/widgets/core/settings.dart';

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/add_exercise.dart'; import 'package:wger/providers/add_exercise.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/user.dart'; import 'package:wger/providers/user.dart';

View File

@@ -17,9 +17,9 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/widgets/exercises/exercises.dart'; import 'package:wger/widgets/exercises/exercises.dart';

View File

@@ -27,6 +27,7 @@ import 'package:wger/helpers/consts.dart';
import 'package:wger/models/gallery/image.dart' as gallery; import 'package:wger/models/gallery/image.dart' as gallery;
import 'package:wger/providers/gallery.dart'; import 'package:wger/providers/gallery.dart';
import 'package:wger/widgets/gallery/forms.dart'; import 'package:wger/widgets/gallery/forms.dart';
import '../../test_data/gallery.dart'; import '../../test_data/gallery.dart';
import 'gallery_form_test.mocks.dart'; import 'gallery_form_test.mocks.dart';

View File

@@ -17,13 +17,13 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:network_image_mock/network_image_mock.dart'; import 'package:network_image_mock/network_image_mock.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/gallery.dart'; import 'package:wger/providers/gallery.dart';
import 'package:wger/screens/form_screen.dart'; import 'package:wger/screens/form_screen.dart';
import 'package:wger/widgets/gallery/overview.dart'; import 'package:wger/widgets/gallery/overview.dart';

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/measurements/measurement_category.dart'; import 'package:wger/models/measurements/measurement_category.dart';
import 'package:wger/models/measurements/measurement_entry.dart'; import 'package:wger/models/measurements/measurement_entry.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
@@ -37,14 +37,24 @@ void main() {
setUp(() { setUp(() {
mockMeasurementProvider = MockMeasurementProvider(); mockMeasurementProvider = MockMeasurementProvider();
when(mockMeasurementProvider.categories).thenReturn([ when(mockMeasurementProvider.categories).thenReturn([
MeasurementCategory(id: 1, name: 'body fat', unit: '%', entries: [ MeasurementCategory(
MeasurementEntry(id: 1, category: 1, date: DateTime(2021, 9, 1), value: 10, notes: ''), id: 1,
MeasurementEntry(id: 2, category: 1, date: DateTime(2021, 9, 5), value: 11, notes: ''), name: 'body fat',
]), unit: '%',
MeasurementCategory(id: 2, name: 'biceps', unit: 'cm', entries: [ entries: [
MeasurementEntry(id: 3, category: 2, date: DateTime(2021, 9, 1), value: 30, notes: ''), MeasurementEntry(id: 1, category: 1, date: DateTime(2021, 9, 1), value: 10, notes: ''),
MeasurementEntry(id: 4, category: 2, date: DateTime(2021, 9, 5), value: 40, notes: ''), MeasurementEntry(id: 2, category: 1, date: DateTime(2021, 9, 5), value: 11, notes: ''),
]), ],
),
MeasurementCategory(
id: 2,
name: 'biceps',
unit: 'cm',
entries: [
MeasurementEntry(id: 3, category: 2, date: DateTime(2021, 9, 1), value: 30, notes: ''),
MeasurementEntry(id: 4, category: 2, date: DateTime(2021, 9, 5), value: 40, notes: ''),
],
),
]); ]);
}); });

View File

@@ -17,10 +17,10 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/measurements/measurement_category.dart'; import 'package:wger/models/measurements/measurement_category.dart';
import 'package:wger/models/measurements/measurement_entry.dart'; import 'package:wger/models/measurements/measurement_entry.dart';
import 'package:wger/providers/measurement.dart'; import 'package:wger/providers/measurement.dart';
@@ -37,10 +37,21 @@ void main() {
setUp(() { setUp(() {
mockMeasurementProvider = MockMeasurementProvider(); mockMeasurementProvider = MockMeasurementProvider();
when(mockMeasurementProvider.findCategoryById(any)).thenReturn( when(mockMeasurementProvider.findCategoryById(any)).thenReturn(
MeasurementCategory(id: 1, name: 'body fat', unit: '%', entries: [ MeasurementCategory(
MeasurementEntry(id: 1, category: 1, date: DateTime(2021, 8, 1), value: 10.2, notes: ''), id: 1,
MeasurementEntry(id: 1, category: 1, date: DateTime(2021, 8, 10), value: 18.1, notes: 'a'), name: 'body fat',
]), unit: '%',
entries: [
MeasurementEntry(id: 1, category: 1, date: DateTime(2021, 8, 1), value: 10.2, notes: ''),
MeasurementEntry(
id: 1,
category: 1,
date: DateTime(2021, 8, 10),
value: 18.1,
notes: 'a',
),
],
),
); );
mockNutritionPlansProvider = MockNutritionPlansProvider(); mockNutritionPlansProvider = MockNutritionPlansProvider();

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/widgets/nutrition/charts.dart'; import 'package:wger/widgets/nutrition/charts.dart';
import 'package:wger/widgets/nutrition/nutritional_diary_detail.dart'; import 'package:wger/widgets/nutrition/nutritional_diary_detail.dart';

View File

@@ -18,13 +18,13 @@
import 'package:clock/clock.dart'; import 'package:clock/clock.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/json.dart'; import 'package:wger/helpers/json.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
@@ -61,9 +61,7 @@ void main() {
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
navigatorKey: key, navigatorKey: key,
home: Scaffold(body: MealForm("1", meal)), home: Scaffold(body: MealForm("1", meal)),
routes: { routes: {NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen()},
NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen(),
},
), ),
); );
} }
@@ -81,11 +79,7 @@ void main() {
await tester.pumpWidget(createFormScreen(meal1)); await tester.pumpWidget(createFormScreen(meal1));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(find.text('17:00'), findsOneWidget, reason: 'Time of existing meal is filled in');
find.text('17:00'),
findsOneWidget,
reason: 'Time of existing meal is filled in',
);
expect( expect(
find.text('Initial Name 1'), find.text('Initial Name 1'),

View File

@@ -2,7 +2,6 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@@ -10,6 +9,7 @@ import 'package:mockito/mockito.dart';
import 'package:network_image_mock/network_image_mock.dart'; import 'package:network_image_mock/network_image_mock.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/exercises/ingredient_api.dart'; import 'package:wger/models/exercises/ingredient_api.dart';
import 'package:wger/models/nutrition/ingredient.dart'; import 'package:wger/models/nutrition/ingredient.dart';
import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal.dart';
@@ -74,14 +74,17 @@ void main() {
when(mockNutrition.searchIngredientWithCode('123')).thenAnswer((_) => Future.value(ingredient)); when(mockNutrition.searchIngredientWithCode('123')).thenAnswer((_) => Future.value(ingredient));
when(mockNutrition.searchIngredientWithCode('')).thenAnswer((_) => Future.value(null)); when(mockNutrition.searchIngredientWithCode('')).thenAnswer((_) => Future.value(null));
when(mockNutrition.searchIngredientWithCode('222')).thenAnswer((_) => Future.value(null)); when(mockNutrition.searchIngredientWithCode('222')).thenAnswer((_) => Future.value(null));
when(mockNutrition.searchIngredient( when(
any, mockNutrition.searchIngredient(
languageCode: anyNamed('languageCode'), any,
searchEnglish: anyNamed('searchEnglish'), languageCode: anyNamed('languageCode'),
)).thenAnswer( searchEnglish: anyNamed('searchEnglish'),
),
).thenAnswer(
(_) => Future.value( (_) => Future.value(
IngredientApiSearch.fromJson(json.decode(fixture('nutrition/ingredient_suggestions'))) IngredientApiSearch.fromJson(
.suggestions, json.decode(fixture('nutrition/ingredient_suggestions')),
).suggestions,
), ),
); );
@@ -104,9 +107,7 @@ void main() {
MealItemForm(meal, const [], code, test), MealItemForm(meal, const [], code, test),
), ),
), ),
routes: { routes: {NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen()},
NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen(),
},
), ),
); );
} }
@@ -294,40 +295,41 @@ void main() {
expect(find.text('Please enter a valid number'), findsOneWidget); expect(find.text('Please enter a valid number'), findsOneWidget);
}); });
testWidgets( testWidgets('save complete ingredient with correct weight input type', (
'save complete ingredient with correct weight input type', WidgetTester tester,
(WidgetTester tester) async { ) async {
await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true)); await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true));
final IngredientFormState formState = tester.state(find.byType(IngredientForm)); final IngredientFormState formState = tester.state(find.byType(IngredientForm));
await tester.tap(find.byKey(const Key('scan-button'))); await tester.tap(find.byKey(const Key('scan-button')));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.byKey(const Key('ingredient-scan-result-dialog')), findsOneWidget); expect(find.byKey(const Key('ingredient-scan-result-dialog')), findsOneWidget);
await tester.tap(find.byKey(const Key('ingredient-scan-result-dialog-confirm-button'))); await tester.tap(find.byKey(const Key('ingredient-scan-result-dialog-confirm-button')));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(formState.ingredientIdController.text, '1'); expect(formState.ingredientIdController.text, '1');
await tester.enterText(find.byKey(const Key('field-weight')), '2'); await tester.enterText(find.byKey(const Key('field-weight')), '2');
// once ID and weight are set, it'll fetchIngredient and show macros preview and ingredient image // once ID and weight are set, it'll fetchIngredient and show macros preview and ingredient image
when(mockNutrition.fetchIngredient(1)).thenAnswer((_) => Future.value( when(mockNutrition.fetchIngredient(1)).thenAnswer(
Ingredient.fromJson(jsonDecode(fixture('nutrition/ingredientinfo_59887.json'))), (_) => Future.value(
)); Ingredient.fromJson(jsonDecode(fixture('nutrition/ingredientinfo_59887.json'))),
await mockNetworkImagesFor(() => tester.pumpAndSettle()); ),
);
await mockNetworkImagesFor(() => tester.pumpAndSettle());
expect(find.byKey(const Key('ingredient-scan-result-dialog')), findsNothing); expect(find.byKey(const Key('ingredient-scan-result-dialog')), findsNothing);
await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME))); await tester.tap(find.byKey(const Key(SUBMIT_BUTTON_KEY_NAME)));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(formState.mealItem.amount, 2); expect(formState.mealItem.amount, 2);
verify(mockNutrition.addMealItem(any, meal1)); verify(mockNutrition.addMealItem(any, meal1));
}, });
);
}); });
} }

View File

@@ -17,12 +17,12 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/screens/nutritional_plan_screen.dart';
@@ -59,9 +59,7 @@ void main() {
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
navigatorKey: key, navigatorKey: key,
home: Scaffold(body: PlanForm(plan)), home: Scaffold(body: PlanForm(plan)),
routes: { routes: {NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen()},
NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen(),
},
), ),
); );
} }

View File

@@ -18,13 +18,13 @@
import 'package:drift/native.dart'; import 'package:drift/native.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:golden_toolkit/golden_toolkit.dart'; import 'package:golden_toolkit/golden_toolkit.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/database/ingredients/ingredients_database.dart'; import 'package:wger/database/ingredients/ingredients_database.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/auth.dart'; import 'package:wger/providers/auth.dart';
import 'package:wger/providers/base_provider.dart'; import 'package:wger/providers/base_provider.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
@@ -54,11 +54,7 @@ void main() {
return MultiProvider( return MultiProvider(
providers: [ providers: [
ChangeNotifierProvider<NutritionPlansProvider>( ChangeNotifierProvider<NutritionPlansProvider>(
create: (context) => NutritionPlansProvider( create: (context) => NutritionPlansProvider(mockBaseProvider, [], database: database),
mockBaseProvider,
[],
database: database,
),
), ),
ChangeNotifierProvider<BodyWeightProvider>( ChangeNotifierProvider<BodyWeightProvider>(
create: (context) => BodyWeightProvider(mockBaseProvider), create: (context) => BodyWeightProvider(mockBaseProvider),
@@ -82,64 +78,59 @@ void main() {
); );
} }
testGoldens( testGoldens('Test the widgets on the nutritional plan screen', (tester) async {
'Test the widgets on the nutritional plan screen', await loadAppFonts();
(tester) async { final globalKey = GlobalKey();
await loadAppFonts(); await tester.pumpWidgetBuilder(
final globalKey = GlobalKey(); Material(key: globalKey),
await tester.pumpWidgetBuilder( wrapper: materialAppWrapper(localizations: [AppLocalizations.delegate]),
Material(key: globalKey), surfaceSize: const Size(500, 1000),
wrapper: materialAppWrapper( );
localizations: [AppLocalizations.delegate], await tester.pumpWidget(createNutritionalPlan());
), await tester.tap(find.byType(TextButton));
surfaceSize: const Size(500, 1000), await tester.pumpAndSettle();
);
await tester.pumpWidget(createNutritionalPlan());
await tester.tap(find.byType(TextButton));
await tester.pumpAndSettle();
await screenMatchesGolden(tester, 'nutritional_plan_1_default_view'); await screenMatchesGolden(tester, 'nutritional_plan_1_default_view');
// Default view shows plan description, info button, and no ingredients // Default view shows plan description, info button, and no ingredients
expect(find.text('Less fat, more protein'), findsOneWidget); expect(find.text('Less fat, more protein'), findsOneWidget);
expect(find.byIcon(Icons.info_outline), findsNWidgets(3)); // 2 meals, 1 "other logs" expect(find.byIcon(Icons.info_outline), findsNWidgets(3)); // 2 meals, 1 "other logs"
expect(find.byIcon(Icons.info), findsNothing); expect(find.byIcon(Icons.info), findsNothing);
expect(find.text('100g Water'), findsNothing); expect(find.text('100g Water'), findsNothing);
expect(find.text('75g Burger soup'), findsNothing); expect(find.text('75g Burger soup'), findsNothing);
// tap the first info button changes it and reveals ingredients for the first meal // tap the first info button changes it and reveals ingredients for the first meal
var infoOutlineButtons = find.byIcon(Icons.info_outline); var infoOutlineButtons = find.byIcon(Icons.info_outline);
await tester.tap(infoOutlineButtons.first); // 2nd button shows up also, but is off-screen await tester.tap(infoOutlineButtons.first); // 2nd button shows up also, but is off-screen
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await screenMatchesGolden(tester, 'nutritional_plan_2_one_meal_with_ingredients'); await screenMatchesGolden(tester, 'nutritional_plan_2_one_meal_with_ingredients');
// Ingredients show up now // Ingredients show up now
expect(find.text('100g Water'), findsOneWidget); expect(find.text('100g Water'), findsOneWidget);
expect(find.text('75g Burger soup'), findsOneWidget); expect(find.text('75g Burger soup'), findsOneWidget);
// .. and the button icon has changed // .. and the button icon has changed
expect(find.byIcon(Icons.info_outline), findsNWidgets(2)); expect(find.byIcon(Icons.info_outline), findsNWidgets(2));
expect(find.byIcon(Icons.info), findsOneWidget); expect(find.byIcon(Icons.info), findsOneWidget);
// the goals widget pushes this content down a bit. // the goals widget pushes this content down a bit.
// let's first find our icon (note: the previous icon no longer matches) // let's first find our icon (note: the previous icon no longer matches)
infoOutlineButtons = find.byIcon(Icons.info_outline); infoOutlineButtons = find.byIcon(Icons.info_outline);
await tester.scrollUntilVisible(infoOutlineButtons.first, 30); await tester.scrollUntilVisible(infoOutlineButtons.first, 30);
expect(find.text('300g Broccoli cake'), findsNothing); expect(find.text('300g Broccoli cake'), findsNothing);
await tester.tap(infoOutlineButtons.first); await tester.tap(infoOutlineButtons.first);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await screenMatchesGolden(tester, 'nutritional_plan_3_both_meals_with_ingredients'); await screenMatchesGolden(tester, 'nutritional_plan_3_both_meals_with_ingredients');
expect(find.byIcon(Icons.info_outline), findsOneWidget); expect(find.byIcon(Icons.info_outline), findsOneWidget);
expect(find.byIcon(Icons.info), findsNWidgets(2)); expect(find.byIcon(Icons.info), findsNWidgets(2));
await tester.scrollUntilVisible(find.text('300g Broccoli cake'), 30); await tester.scrollUntilVisible(find.text('300g Broccoli cake'), 30);
expect(find.text('300g Broccoli cake'), findsOneWidget); expect(find.text('300g Broccoli cake'), findsOneWidget);
expect(find.byType(Card), findsNWidgets(3)); expect(find.byType(Card), findsNWidgets(3));
}, });
);
testWidgets('Tests the localization of times - EN', (WidgetTester tester) async { testWidgets('Tests the localization of times - EN', (WidgetTester tester) async {
await tester.pumpWidget(createNutritionalPlan()); await tester.pumpWidget(createNutritionalPlan());

View File

@@ -18,13 +18,13 @@
import 'package:drift/native.dart'; import 'package:drift/native.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/database/ingredients/ingredients_database.dart'; import 'package:wger/database/ingredients/ingredients_database.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/models/nutrition/nutritional_plan.dart';
import 'package:wger/providers/auth.dart'; import 'package:wger/providers/auth.dart';
import 'package:wger/providers/base_provider.dart'; import 'package:wger/providers/base_provider.dart';
@@ -51,34 +51,29 @@ void main() {
}); });
Widget createHomeScreen({locale = 'en'}) { Widget createHomeScreen({locale = 'en'}) {
when(client.delete(any, headers: anyNamed('headers'))) when(
.thenAnswer((_) async => http.Response('', 200)); client.delete(any, headers: anyNamed('headers')),
).thenAnswer((_) async => http.Response('', 200));
when(mockBaseProvider.deleteRequest(any, any)).thenAnswer( when(mockBaseProvider.deleteRequest(any, any)).thenAnswer((_) async => http.Response('', 200));
(_) async => http.Response('', 200),
);
when(mockAuthProvider.token).thenReturn('1234'); when(mockAuthProvider.token).thenReturn('1234');
when(mockAuthProvider.serverUrl).thenReturn('http://localhost'); when(mockAuthProvider.serverUrl).thenReturn('http://localhost');
when(mockAuthProvider.getAppNameHeader()).thenReturn('wger app'); when(mockAuthProvider.getAppNameHeader()).thenReturn('wger app');
return ChangeNotifierProvider<NutritionPlansProvider>( return ChangeNotifierProvider<NutritionPlansProvider>(
create: (context) => NutritionPlansProvider( create: (context) => NutritionPlansProvider(mockBaseProvider, [
mockBaseProvider, NutritionalPlan(
[ id: 'deadbeefa',
NutritionalPlan( description: 'test plan 1',
id: 'deadbeefa', creationDate: DateTime(2021, 01, 01),
description: 'test plan 1', ),
creationDate: DateTime(2021, 01, 01), NutritionalPlan(
), id: 'deadbeefb',
NutritionalPlan( description: 'test plan 2',
id: 'deadbeefb', creationDate: DateTime(2021, 01, 10),
description: 'test plan 2', ),
creationDate: DateTime(2021, 01, 10), ], database: database),
),
],
database: database,
),
child: MaterialApp( child: MaterialApp(
locale: Locale(locale), locale: Locale(locale),
localizationsDelegates: AppLocalizations.localizationsDelegates, localizationsDelegates: AppLocalizations.localizationsDelegates,

View File

@@ -17,8 +17,8 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/body_weight/weight_entry.dart'; import 'package:wger/models/body_weight/weight_entry.dart';
import 'package:wger/widgets/weight/forms.dart'; import 'package:wger/widgets/weight/forms.dart';

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/nutrition.dart';
import 'package:wger/providers/user.dart'; import 'package:wger/providers/user.dart';

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/base_provider.dart'; import 'package:wger/providers/base_provider.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
@@ -45,11 +45,8 @@ void main() {
Widget createHomeScreen({locale = 'en'}) { Widget createHomeScreen({locale = 'en'}) {
return ChangeNotifierProvider<WorkoutPlansProvider>( return ChangeNotifierProvider<WorkoutPlansProvider>(
create: (context) => WorkoutPlansProvider( create: (context) =>
mockBaseProvider, WorkoutPlansProvider(mockBaseProvider, mockExerciseProvider, [workoutPlan]),
mockExerciseProvider,
[workoutPlan],
),
child: ChangeNotifierProvider<ExercisesProvider>( child: ChangeNotifierProvider<ExercisesProvider>(
create: (context) => mockExerciseProvider, create: (context) => mockExerciseProvider,
child: MaterialApp( child: MaterialApp(
@@ -66,9 +63,7 @@ void main() {
), ),
child: const SizedBox(), child: const SizedBox(),
), ),
routes: { routes: {WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen()},
WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen(),
},
), ),
), ),
); );

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/repetition_unit.dart'; import 'package:wger/models/workouts/repetition_unit.dart';
import 'package:wger/models/workouts/setting.dart'; import 'package:wger/models/workouts/setting.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
@@ -65,9 +65,7 @@ void main() {
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
navigatorKey: key, navigatorKey: key,
home: Scaffold(body: RepetitionUnitInputWidget(setting1)), home: Scaffold(body: RepetitionUnitInputWidget(setting1)),
routes: { routes: {WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen()},
WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen(),
},
), ),
); );
} }

View File

@@ -17,11 +17,11 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/setting.dart'; import 'package:wger/models/workouts/setting.dart';
import 'package:wger/models/workouts/weight_unit.dart'; import 'package:wger/models/workouts/weight_unit.dart';
import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/body_weight.dart';
@@ -66,9 +66,7 @@ void main() {
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
navigatorKey: key, navigatorKey: key,
home: Scaffold(body: WeightUnitInputWidget(setting1)), home: Scaffold(body: WeightUnitInputWidget(setting1)),
routes: { routes: {WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen()},
WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen(),
},
), ),
); );
} }

View File

@@ -17,12 +17,12 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/day.dart'; import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/workout_plan.dart'; import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';

View File

@@ -17,12 +17,12 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/workout_plan.dart'; import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/workout_plan_screen.dart'; import 'package:wger/screens/workout_plan_screen.dart';
@@ -45,8 +45,9 @@ void main() {
setUp(() { setUp(() {
mockWorkoutPlans = MockWorkoutPlansProvider(); mockWorkoutPlans = MockWorkoutPlansProvider();
when(mockWorkoutPlans.editWorkout(any)).thenAnswer((_) => Future.value(existingPlan)); when(mockWorkoutPlans.editWorkout(any)).thenAnswer((_) => Future.value(existingPlan));
when(mockWorkoutPlans.fetchAndSetWorkoutPlanFull(any)) when(
.thenAnswer((_) => Future.value(existingPlan)); mockWorkoutPlans.fetchAndSetWorkoutPlanFull(any),
).thenAnswer((_) => Future.value(existingPlan));
}); });
Widget createHomeScreen(WorkoutPlan workoutPlan, {locale = 'en'}) { Widget createHomeScreen(WorkoutPlan workoutPlan, {locale = 'en'}) {
@@ -60,9 +61,7 @@ void main() {
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
navigatorKey: key, navigatorKey: key,
home: Scaffold(body: WorkoutForm(workoutPlan)), home: Scaffold(body: WorkoutForm(workoutPlan)),
routes: { routes: {WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen()},
WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen(),
},
), ),
); );
} }
@@ -79,11 +78,7 @@ void main() {
await tester.pumpWidget(createHomeScreen(existingPlan)); await tester.pumpWidget(createHomeScreen(existingPlan));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(find.text('test 1'), findsOneWidget, reason: 'Name of existing workout plan');
find.text('test 1'),
findsOneWidget,
reason: 'Name of existing workout plan',
);
expect( expect(
find.text('description 1'), find.text('description 1'),
findsOneWidget, findsOneWidget,

View File

@@ -18,11 +18,11 @@
import 'package:drift/native.dart'; import 'package:drift/native.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/database/exercises/exercise_database.dart'; import 'package:wger/database/exercises/exercise_database.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/base_provider.dart'; import 'package:wger/providers/base_provider.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/workout_plans.dart'; import 'package:wger/providers/workout_plans.dart';
@@ -57,9 +57,7 @@ void main() {
), ),
child: const SizedBox(), child: const SizedBox(),
), ),
routes: { routes: {WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen()},
WorkoutPlanScreen.routeName: (ctx) => const WorkoutPlanScreen(),
},
), ),
); );
} }

View File

@@ -18,13 +18,13 @@
import 'package:drift/native.dart'; import 'package:drift/native.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/database/exercises/exercise_database.dart'; import 'package:wger/database/exercises/exercise_database.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/workout_plan.dart'; import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/base_provider.dart'; import 'package:wger/providers/base_provider.dart';
import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/exercises.dart';
@@ -49,23 +49,15 @@ void main() {
}); });
Widget createHomeScreen({locale = 'en'}) { Widget createHomeScreen({locale = 'en'}) {
final uri = Uri( final uri = Uri(scheme: 'https', host: 'localhost', path: 'api/v2/workout/');
scheme: 'https',
host: 'localhost',
path: 'api/v2/workout/',
);
when(mockBaseProvider.makeUrl('workout', query: anyNamed('query'))).thenReturn(uri); when(mockBaseProvider.makeUrl('workout', query: anyNamed('query'))).thenReturn(uri);
when(mockBaseProvider.deleteRequest(any, any)).thenAnswer((_) async => http.Response('', 204)); when(mockBaseProvider.deleteRequest(any, any)).thenAnswer((_) async => http.Response('', 204));
return ChangeNotifierProvider<WorkoutPlansProvider>( return ChangeNotifierProvider<WorkoutPlansProvider>(
create: (context) => WorkoutPlansProvider( create: (context) => WorkoutPlansProvider(mockBaseProvider, testExercisesProvider, [
mockBaseProvider, WorkoutPlan(id: 1, creationDate: DateTime(2021, 01, 01), name: 'test 1'),
testExercisesProvider, WorkoutPlan(id: 2, creationDate: DateTime(2021, 02, 12), name: 'test 2'),
[ ]),
WorkoutPlan(id: 1, creationDate: DateTime(2021, 01, 01), name: 'test 1'),
WorkoutPlan(id: 2, creationDate: DateTime(2021, 02, 12), name: 'test 2'),
],
),
child: MaterialApp( child: MaterialApp(
locale: Locale(locale), locale: Locale(locale),
localizationsDelegates: AppLocalizations.localizationsDelegates, localizationsDelegates: AppLocalizations.localizationsDelegates,

View File

@@ -17,12 +17,12 @@
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart'; import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/consts.dart';
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/day.dart'; import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/set.dart'; import 'package:wger/models/workouts/set.dart';
import 'package:wger/models/workouts/setting.dart'; import 'package:wger/models/workouts/setting.dart';
@@ -51,11 +51,8 @@ void main() {
Widget createHomeScreen({locale = 'en'}) { Widget createHomeScreen({locale = 'en'}) {
return ChangeNotifierProvider<WorkoutPlansProvider>( return ChangeNotifierProvider<WorkoutPlansProvider>(
create: (context) => WorkoutPlansProvider( create: (context) =>
mockBaseProvider, WorkoutPlansProvider(mockBaseProvider, mockExerciseProvider, [workoutPlan]),
mockExerciseProvider,
[workoutPlan],
),
child: ChangeNotifierProvider<ExercisesProvider>( child: ChangeNotifierProvider<ExercisesProvider>(
create: (context) => mockExerciseProvider, create: (context) => mockExerciseProvider,
child: MaterialApp( child: MaterialApp(
@@ -84,11 +81,13 @@ void main() {
when(mockWorkoutPlans.addSet(any)).thenAnswer((_) => Future.value(Set.empty())); when(mockWorkoutPlans.addSet(any)).thenAnswer((_) => Future.value(Set.empty()));
when(mockWorkoutPlans.addSetting(any)).thenAnswer((_) => Future.value(Setting.empty())); when(mockWorkoutPlans.addSetting(any)).thenAnswer((_) => Future.value(Setting.empty()));
when(mockWorkoutPlans.fetchSmartText(any, any)).thenAnswer((_) => Future.value('2 x 10')); when(mockWorkoutPlans.fetchSmartText(any, any)).thenAnswer((_) => Future.value('2 x 10'));
when(mockExerciseProvider.searchExercise( when(
any, mockExerciseProvider.searchExercise(
languageCode: anyNamed('languageCode'), any,
searchEnglish: anyNamed('searchEnglish'), languageCode: anyNamed('languageCode'),
)).thenAnswer((_) => Future.value([getTestExercises().first])); searchEnglish: anyNamed('searchEnglish'),
),
).thenAnswer((_) => Future.value([getTestExercises().first]));
await tester.pumpWidget(createHomeScreen()); await tester.pumpWidget(createHomeScreen());
await tester.pumpAndSettle(); await tester.pumpAndSettle();