mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Move dashboard visibility settings to own screen
This seems cleaner and can be opened from other places
This commit is contained in:
@@ -100,6 +100,7 @@
|
||||
"@labelWorkoutPlan": {
|
||||
"description": "Title for screen workout plan"
|
||||
},
|
||||
"dashboardWidgets": "Dashboard widgets",
|
||||
"labelDashboard": "Dashboard",
|
||||
"@labelDashboard": {
|
||||
"description": "Title for screen dashboard"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (C) 2020, 2021 wger Team
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wger Workout Manager is distributed in the hope that it will be useful,
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
@@ -37,7 +37,6 @@ import 'package:wger/providers/routines.dart';
|
||||
import 'package:wger/providers/user.dart';
|
||||
import 'package:wger/screens/add_exercise_screen.dart';
|
||||
import 'package:wger/screens/auth_screen.dart';
|
||||
import 'package:wger/screens/configure_plates_screen.dart';
|
||||
import 'package:wger/screens/dashboard.dart';
|
||||
import 'package:wger/screens/exercise_screen.dart';
|
||||
import 'package:wger/screens/exercises_screen.dart';
|
||||
@@ -56,6 +55,8 @@ import 'package:wger/screens/routine_edit_screen.dart';
|
||||
import 'package:wger/screens/routine_list_screen.dart';
|
||||
import 'package:wger/screens/routine_logs_screen.dart';
|
||||
import 'package:wger/screens/routine_screen.dart';
|
||||
import 'package:wger/screens/settings_dashboard_widgets_screen.dart';
|
||||
import 'package:wger/screens/settings_plates_screen.dart';
|
||||
import 'package:wger/screens/splash_screen.dart';
|
||||
import 'package:wger/screens/update_app_screen.dart';
|
||||
import 'package:wger/screens/weight_screen.dart';
|
||||
@@ -252,6 +253,8 @@ class MainApp extends StatelessWidget {
|
||||
SettingsPage.routeName: (ctx) => const SettingsPage(),
|
||||
LogOverviewPage.routeName: (ctx) => const LogOverviewPage(),
|
||||
ConfigurePlatesScreen.routeName: (ctx) => const ConfigurePlatesScreen(),
|
||||
ConfigureDashboardWidgetsScreen.routeName: (ctx) =>
|
||||
const ConfigureDashboardWidgetsScreen(),
|
||||
},
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (C) 2020, 2021 wger Team
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
@@ -26,19 +26,36 @@ import 'package:wger/helpers/shared_preferences.dart';
|
||||
import 'package:wger/models/user/profile.dart';
|
||||
import 'package:wger/providers/base_provider.dart';
|
||||
|
||||
enum DashboardWidget {
|
||||
routines('routines'),
|
||||
weight('weight'),
|
||||
measurements('measurements'),
|
||||
calendar('calendar'),
|
||||
nutrition('nutrition');
|
||||
|
||||
final String value;
|
||||
const DashboardWidget(this.value);
|
||||
|
||||
static DashboardWidget? fromString(String s) {
|
||||
for (final e in DashboardWidget.values) {
|
||||
if (e.value == s) return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class UserProvider with ChangeNotifier {
|
||||
ThemeMode themeMode = ThemeMode.system;
|
||||
final WgerBaseProvider baseProvider;
|
||||
late SharedPreferencesAsync prefs;
|
||||
// bool hideNutrition = false;
|
||||
|
||||
// New: visibility state for dashboard widgets
|
||||
Map<String, bool> dashboardWidgetVisibility = {
|
||||
'routines': true,
|
||||
'weight': true,
|
||||
'measurements': true,
|
||||
'calendar': true,
|
||||
'nutrition': true,
|
||||
Map<DashboardWidget, bool> dashboardWidgetVisibility = {
|
||||
DashboardWidget.routines: true,
|
||||
DashboardWidget.weight: true,
|
||||
DashboardWidget.measurements: true,
|
||||
DashboardWidget.calendar: true,
|
||||
DashboardWidget.nutrition: true,
|
||||
};
|
||||
|
||||
static const String PREFS_DASHBOARD_VISIBILITY = 'dashboardWidgetVisibility';
|
||||
@@ -80,31 +97,47 @@ class UserProvider with ChangeNotifier {
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
Future<void> _loadDashboardVisibility() async {
|
||||
final jsonString = await prefs.getString(PREFS_DASHBOARD_VISIBILITY);
|
||||
|
||||
if (jsonString != null) {
|
||||
try {
|
||||
final decoded = jsonDecode(jsonString) as Map<String, dynamic>;
|
||||
dashboardWidgetVisibility =
|
||||
decoded.map((k, v) => MapEntry(k, v as bool));
|
||||
} catch (_) {
|
||||
// If parsing fails, keep defaults
|
||||
Future<void> _loadDashboardVisibility() async {
|
||||
final jsonString = await prefs.getString(PREFS_DASHBOARD_VISIBILITY);
|
||||
if (jsonString == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final decoded = jsonDecode(jsonString) as Map<String, dynamic>;
|
||||
final Map<DashboardWidget, bool> loaded = {};
|
||||
|
||||
for (final entry in decoded.entries) {
|
||||
final widget = DashboardWidget.fromString(entry.key);
|
||||
if (widget != null) {
|
||||
loaded[widget] = entry.value as bool;
|
||||
}
|
||||
}
|
||||
|
||||
if (loaded.isNotEmpty) {
|
||||
dashboardWidgetVisibility = loaded;
|
||||
}
|
||||
} catch (_) {
|
||||
// parsing failed -> keep defaults
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
bool isDashboardWidgetVisible(String key) {
|
||||
bool isDashboardWidgetVisible(DashboardWidget key) {
|
||||
return dashboardWidgetVisibility[key] ?? true;
|
||||
}
|
||||
|
||||
Future<void> setDashboardWidgetVisible(String key, bool visible) async {
|
||||
Future<void> setDashboardWidgetVisible(DashboardWidget key, bool visible) async {
|
||||
dashboardWidgetVisibility[key] = visible;
|
||||
final Map<String, bool> serializable = {
|
||||
for (final e in dashboardWidgetVisibility.entries) e.key.value: e.value,
|
||||
};
|
||||
|
||||
await prefs.setString(
|
||||
PREFS_DASHBOARD_VISIBILITY,
|
||||
jsonEncode(dashboardWidgetVisibility),
|
||||
jsonEncode(serializable),
|
||||
);
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -133,7 +166,6 @@ class UserProvider with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Save the user's profile to the server
|
||||
Future<void> saveProfile() async {
|
||||
await baseProvider.post(
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/providers/user.dart';
|
||||
import 'package:wger/widgets/core/app_bar.dart';
|
||||
import 'package:wger/widgets/dashboard/calendar.dart';
|
||||
import 'package:wger/widgets/dashboard/widgets/measurements.dart';
|
||||
import 'package:wger/widgets/dashboard/widgets/nutrition.dart';
|
||||
import 'package:wger/widgets/dashboard/widgets/routines.dart';
|
||||
import 'package:wger/widgets/dashboard/widgets/weight.dart';
|
||||
import 'package:wger/providers/user.dart';
|
||||
|
||||
class DashboardScreen extends StatelessWidget {
|
||||
const DashboardScreen({super.key});
|
||||
@@ -42,19 +42,19 @@ class DashboardScreen extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
children: [
|
||||
if (user.isDashboardWidgetVisible('routines'))
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.routines))
|
||||
const DashboardRoutineWidget(),
|
||||
if (user.isDashboardWidgetVisible('weight'))
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.weight))
|
||||
const DashboardWeightWidget(),
|
||||
if (user.isDashboardWidgetVisible('measurements'))
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.measurements))
|
||||
const DashboardMeasurementWidget(),
|
||||
if (user.isDashboardWidgetVisible('calendar'))
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.calendar))
|
||||
const DashboardCalendarWidget(),
|
||||
if (user.isDashboardWidgetVisible('nutrition'))
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.nutrition))
|
||||
const DashboardNutritionWidget(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
lib/screens/settings_dashboard_widgets_screen.dart
Normal file
38
lib/screens/settings_dashboard_widgets_screen.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:wger/core/wide_screen_wrapper.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/widgets/core/settings/dashboard_visibility.dart';
|
||||
|
||||
class ConfigureDashboardWidgetsScreen extends StatelessWidget {
|
||||
static const routeName = '/ConfigureDashboardWidgetScreen';
|
||||
|
||||
const ConfigureDashboardWidgetsScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(i18n.dashboardWidgets)),
|
||||
body: const WidescreenWrapper(child: SettingsDashboardVisibility()),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (C) 2020, 2021 wger Team
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
@@ -26,6 +26,7 @@ import 'package:wger/providers/nutrition.dart';
|
||||
import 'package:wger/providers/routines.dart';
|
||||
import 'package:wger/providers/user.dart';
|
||||
import 'package:wger/screens/form_screen.dart';
|
||||
import 'package:wger/screens/settings_dashboard_widgets_screen.dart';
|
||||
import 'package:wger/widgets/core/about.dart';
|
||||
import 'package:wger/widgets/core/settings.dart';
|
||||
import 'package:wger/widgets/user/forms.dart';
|
||||
@@ -40,71 +41,19 @@ class MainAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
return AppBar(
|
||||
title: Text(_title),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.widgets_outlined),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed(ConfigureDashboardWidgetsScreen.routeName);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.settings),
|
||||
onPressed: () async {
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(AppLocalizations.of(context).optionsLabel),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
MaterialLocalizations.of(context).closeButtonLabel,
|
||||
),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
//dense: true,
|
||||
leading: const Icon(Icons.person),
|
||||
title: Text(AppLocalizations.of(context).userProfile),
|
||||
onTap: () => Navigator.pushNamed(
|
||||
context,
|
||||
FormScreen.routeName,
|
||||
arguments: FormScreenArguments(
|
||||
AppLocalizations.of(context).userProfile,
|
||||
UserProfileForm(
|
||||
context.read<UserProvider>().profile!,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.settings),
|
||||
onTap: () => Navigator.of(context).pushNamed(SettingsPage.routeName),
|
||||
title: Text(AppLocalizations.of(context).settingsTitle),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info),
|
||||
onTap: () => Navigator.of(context).pushNamed(AboutPage.routeName),
|
||||
title: Text(AppLocalizations.of(context).aboutPageTitle),
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
//dense: true,
|
||||
leading: const Icon(Icons.exit_to_app),
|
||||
title: Text(AppLocalizations.of(context).logout),
|
||||
onTap: () {
|
||||
context.read<AuthProvider>().logout();
|
||||
context.read<RoutinesProvider>().clear();
|
||||
context.read<NutritionPlansProvider>().clear();
|
||||
context.read<BodyWeightProvider>().clear();
|
||||
context.read<GalleryProvider>().clear();
|
||||
context.read<UserProvider>().clear();
|
||||
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushReplacementNamed('/');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return const MainSettingsDialog();
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -117,6 +66,73 @@ class MainAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
|
||||
}
|
||||
|
||||
class MainSettingsDialog extends StatelessWidget {
|
||||
const MainSettingsDialog({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(AppLocalizations.of(context).optionsLabel),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
MaterialLocalizations.of(context).closeButtonLabel,
|
||||
),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
],
|
||||
contentPadding: EdgeInsets.zero,
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
//dense: true,
|
||||
leading: const Icon(Icons.person),
|
||||
title: Text(AppLocalizations.of(context).userProfile),
|
||||
onTap: () => Navigator.pushNamed(
|
||||
context,
|
||||
FormScreen.routeName,
|
||||
arguments: FormScreenArguments(
|
||||
AppLocalizations.of(context).userProfile,
|
||||
UserProfileForm(
|
||||
context.read<UserProvider>().profile!,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.settings),
|
||||
onTap: () => Navigator.of(context).pushNamed(SettingsPage.routeName),
|
||||
title: Text(AppLocalizations.of(context).settingsTitle),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info),
|
||||
onTap: () => Navigator.of(context).pushNamed(AboutPage.routeName),
|
||||
title: Text(AppLocalizations.of(context).aboutPageTitle),
|
||||
),
|
||||
const Divider(),
|
||||
ListTile(
|
||||
//dense: true,
|
||||
leading: const Icon(Icons.exit_to_app),
|
||||
title: Text(AppLocalizations.of(context).logout),
|
||||
onTap: () {
|
||||
context.read<AuthProvider>().logout();
|
||||
context.read<RoutinesProvider>().clear();
|
||||
context.read<NutritionPlansProvider>().clear();
|
||||
context.read<BodyWeightProvider>().clear();
|
||||
context.read<GalleryProvider>().clear();
|
||||
context.read<UserProvider>().clear();
|
||||
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushReplacementNamed('/');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// App bar that only displays a title
|
||||
class EmptyAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
final String _title;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (C) wger Team
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wger Workout Manager is distributed in the hope that it will be useful,
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
@@ -16,17 +16,14 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//import 'package:drift/drift.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:wger/core/wide_screen_wrapper.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/screens/configure_plates_screen.dart';
|
||||
import 'package:wger/widgets/core/settings/exercise_cache.dart';
|
||||
import 'package:wger/widgets/core/settings/ingredient_cache.dart';
|
||||
import 'package:wger/widgets/core/settings/theme.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/providers/user.dart';
|
||||
import 'package:wger/screens/settings_dashboard_widgets_screen.dart';
|
||||
import 'package:wger/screens/settings_plates_screen.dart';
|
||||
|
||||
import './settings/exercise_cache.dart';
|
||||
import './settings/ingredient_cache.dart';
|
||||
import './settings/theme.dart';
|
||||
|
||||
class SettingsPage extends StatelessWidget {
|
||||
static String routeName = '/SettingsPage';
|
||||
@@ -48,44 +45,6 @@ class SettingsPage extends StatelessWidget {
|
||||
const SettingsIngredientCache(),
|
||||
ListTile(title: Text(i18n.others, style: Theme.of(context).textTheme.headlineSmall)),
|
||||
const SettingsTheme(),
|
||||
Consumer<UserProvider>(
|
||||
builder: (context, user, _) {
|
||||
return Column(
|
||||
children: [
|
||||
SwitchListTile(
|
||||
title: const Text('Show routines on dashboard'),
|
||||
value: user.isDashboardWidgetVisible('routines'),
|
||||
onChanged: (v) =>
|
||||
user.setDashboardWidgetVisible('routines', v),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: const Text('Show weight on dashboard'),
|
||||
value: user.isDashboardWidgetVisible('weight'),
|
||||
onChanged: (v) =>
|
||||
user.setDashboardWidgetVisible('weight', v),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: const Text('Show measurements on dashboard'),
|
||||
value: user.isDashboardWidgetVisible('measurements'),
|
||||
onChanged: (v) =>
|
||||
user.setDashboardWidgetVisible('measurements', v),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: const Text('Show calendar on dashboard'),
|
||||
value: user.isDashboardWidgetVisible('calendar'),
|
||||
onChanged: (v) =>
|
||||
user.setDashboardWidgetVisible('calendar', v),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: const Text('Show nutrition on dashboard'),
|
||||
value: user.isDashboardWidgetVisible('nutrition'),
|
||||
onChanged: (v) =>
|
||||
user.setDashboardWidgetVisible('nutrition', v),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Text(i18n.selectAvailablePlates),
|
||||
onTap: () {
|
||||
@@ -93,6 +52,13 @@ class SettingsPage extends StatelessWidget {
|
||||
},
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
),
|
||||
ListTile(
|
||||
title: Text(i18n.dashboardWidgets),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(ConfigureDashboardWidgetsScreen.routeName);
|
||||
},
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
65
lib/widgets/core/settings/dashboard_visibility.dart
Normal file
65
lib/widgets/core/settings/dashboard_visibility.dart
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/providers/user.dart';
|
||||
|
||||
class SettingsDashboardVisibility extends StatelessWidget {
|
||||
const SettingsDashboardVisibility({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context);
|
||||
|
||||
return Consumer<UserProvider>(
|
||||
builder: (context, user, _) {
|
||||
return Column(
|
||||
children: [
|
||||
SwitchListTile(
|
||||
title: Text(i18n.routines),
|
||||
value: user.isDashboardWidgetVisible(DashboardWidget.routines),
|
||||
onChanged: (v) => user.setDashboardWidgetVisible(DashboardWidget.routines, v),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(i18n.weight),
|
||||
value: user.isDashboardWidgetVisible(DashboardWidget.weight),
|
||||
onChanged: (v) => user.setDashboardWidgetVisible(DashboardWidget.weight, v),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(i18n.measurements),
|
||||
value: user.isDashboardWidgetVisible(DashboardWidget.measurements),
|
||||
onChanged: (v) => user.setDashboardWidgetVisible(DashboardWidget.measurements, v),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(i18n.calendar),
|
||||
value: user.isDashboardWidgetVisible(DashboardWidget.calendar),
|
||||
onChanged: (v) => user.setDashboardWidgetVisible(DashboardWidget.calendar, v),
|
||||
),
|
||||
SwitchListTile(
|
||||
title: Text(i18n.nutritionalPlans),
|
||||
value: user.isDashboardWidgetVisible(DashboardWidget.nutrition),
|
||||
onChanged: (v) => user.setDashboardWidgetVisible(DashboardWidget.nutrition, v),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import 'package:wger/providers/gym_log_state.dart';
|
||||
import 'package:wger/providers/gym_state.dart';
|
||||
import 'package:wger/providers/plate_weights.dart';
|
||||
import 'package:wger/providers/routines.dart';
|
||||
import 'package:wger/screens/configure_plates_screen.dart';
|
||||
import 'package:wger/screens/settings_plates_screen.dart';
|
||||
import 'package:wger/widgets/core/core.dart';
|
||||
import 'package:wger/widgets/core/progress_indicator.dart';
|
||||
import 'package:wger/widgets/routines/forms/reps_unit.dart';
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*
|
||||
* This file is part of wger Workout Manager <https://github.com/wger-project>.
|
||||
* Copyright (C) 2020, 2021 wger Team
|
||||
* Copyright (c) 2026 wger Team
|
||||
*
|
||||
* wger Workout Manager is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wger Workout Manager is distributed in the hope that it will be useful,
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
@@ -49,13 +49,9 @@ void main() {
|
||||
|
||||
setUp(() {
|
||||
when(mockUserProvider.themeMode).thenReturn(ThemeMode.system);
|
||||
when(mockUserProvider.isDashboardWidgetVisible(any)).thenReturn(true);
|
||||
when(mockExerciseProvider.exercises).thenReturn(getTestExercises());
|
||||
when(mockNutritionProvider.ingredients).thenReturn([ingredient1, ingredient2]);
|
||||
when(mockUserProvider.isDashboardWidgetVisible('routines')).thenReturn(true);
|
||||
when(mockUserProvider.isDashboardWidgetVisible('weight')).thenReturn(true);
|
||||
when(mockUserProvider.isDashboardWidgetVisible('measurements')).thenReturn(true);
|
||||
when(mockUserProvider.isDashboardWidgetVisible('calendar')).thenReturn(true);
|
||||
when(mockUserProvider.isDashboardWidgetVisible('nutrition')).thenReturn(true);
|
||||
});
|
||||
|
||||
Widget createSettingsScreen({locale = 'en'}) {
|
||||
@@ -105,24 +101,27 @@ void main() {
|
||||
group('Theme settings', () {
|
||||
test('Default theme is system', () async {
|
||||
when(mockSharedPreferences.getBool(PREFS_USER_DARK_THEME)).thenAnswer((_) async => null);
|
||||
when(mockSharedPreferences.getString('dashboardWidgetVisibility'))
|
||||
.thenAnswer((_) async => null);
|
||||
when(
|
||||
mockSharedPreferences.getString('dashboardWidgetVisibility'),
|
||||
).thenAnswer((_) async => null);
|
||||
final userProvider = await UserProvider(MockWgerBaseProvider(), prefs: mockSharedPreferences);
|
||||
expect(userProvider.themeMode, ThemeMode.system);
|
||||
});
|
||||
|
||||
test('Loads light theme', () async {
|
||||
when(mockSharedPreferences.getBool(PREFS_USER_DARK_THEME)).thenAnswer((_) async => false);
|
||||
when(mockSharedPreferences.getString('dashboardWidgetVisibility'))
|
||||
.thenAnswer((_) async => null);
|
||||
when(
|
||||
mockSharedPreferences.getString('dashboardWidgetVisibility'),
|
||||
).thenAnswer((_) async => null);
|
||||
final userProvider = await UserProvider(MockWgerBaseProvider(), prefs: mockSharedPreferences);
|
||||
expect(userProvider.themeMode, ThemeMode.light);
|
||||
});
|
||||
|
||||
test('Saves theme to prefs', () {
|
||||
when(mockSharedPreferences.getBool(any)).thenAnswer((_) async => null);
|
||||
when(mockSharedPreferences.getString('dashboardWidgetVisibility'))
|
||||
.thenAnswer((_) async => null);
|
||||
when(
|
||||
mockSharedPreferences.getString('dashboardWidgetVisibility'),
|
||||
).thenAnswer((_) async => null);
|
||||
final userProvider = UserProvider(MockWgerBaseProvider(), prefs: mockSharedPreferences);
|
||||
userProvider.setThemeMode(ThemeMode.dark);
|
||||
verify(mockSharedPreferences.setBool(PREFS_USER_DARK_THEME, true)).called(1);
|
||||
|
||||
@@ -943,6 +943,14 @@ class MockUserProvider extends _i1.Mock implements _i21.UserProvider {
|
||||
)
|
||||
as _i14.SharedPreferencesAsync);
|
||||
|
||||
@override
|
||||
Map<_i21.DashboardWidget, bool> get dashboardWidgetVisibility =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#dashboardWidgetVisibility),
|
||||
returnValue: <_i21.DashboardWidget, bool>{},
|
||||
)
|
||||
as Map<_i21.DashboardWidget, bool>);
|
||||
|
||||
@override
|
||||
set themeMode(_i22.ThemeMode? value) => super.noSuchMethod(
|
||||
Invocation.setter(#themeMode, value),
|
||||
@@ -955,6 +963,12 @@ class MockUserProvider extends _i1.Mock implements _i21.UserProvider {
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set dashboardWidgetVisibility(Map<_i21.DashboardWidget, bool>? value) => super.noSuchMethod(
|
||||
Invocation.setter(#dashboardWidgetVisibility, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set profile(_i23.Profile? value) => super.noSuchMethod(
|
||||
Invocation.setter(#profile, value),
|
||||
@@ -971,6 +985,26 @@ class MockUserProvider extends _i1.Mock implements _i21.UserProvider {
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
bool isDashboardWidgetVisible(_i21.DashboardWidget? key) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#isDashboardWidgetVisible, [key]),
|
||||
returnValue: false,
|
||||
)
|
||||
as bool);
|
||||
|
||||
@override
|
||||
_i18.Future<void> setDashboardWidgetVisible(
|
||||
_i21.DashboardWidget? key,
|
||||
bool? visible,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#setDashboardWidgetVisible, [key, visible]),
|
||||
returnValue: _i18.Future<void>.value(),
|
||||
returnValueForMissingStub: _i18.Future<void>.value(),
|
||||
)
|
||||
as _i18.Future<void>);
|
||||
|
||||
@override
|
||||
void setThemeMode(_i22.ThemeMode? mode) => super.noSuchMethod(
|
||||
Invocation.method(#setThemeMode, [mode]),
|
||||
|
||||
@@ -389,6 +389,14 @@ class MockUserProvider extends _i1.Mock implements _i17.UserProvider {
|
||||
)
|
||||
as _i4.SharedPreferencesAsync);
|
||||
|
||||
@override
|
||||
Map<_i17.DashboardWidget, bool> get dashboardWidgetVisibility =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#dashboardWidgetVisibility),
|
||||
returnValue: <_i17.DashboardWidget, bool>{},
|
||||
)
|
||||
as Map<_i17.DashboardWidget, bool>);
|
||||
|
||||
@override
|
||||
set themeMode(_i18.ThemeMode? value) => super.noSuchMethod(
|
||||
Invocation.setter(#themeMode, value),
|
||||
@@ -401,6 +409,12 @@ class MockUserProvider extends _i1.Mock implements _i17.UserProvider {
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set dashboardWidgetVisibility(Map<_i17.DashboardWidget, bool>? value) => super.noSuchMethod(
|
||||
Invocation.setter(#dashboardWidgetVisibility, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set profile(_i19.Profile? value) => super.noSuchMethod(
|
||||
Invocation.setter(#profile, value),
|
||||
@@ -417,6 +431,26 @@ class MockUserProvider extends _i1.Mock implements _i17.UserProvider {
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
bool isDashboardWidgetVisible(_i17.DashboardWidget? key) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#isDashboardWidgetVisible, [key]),
|
||||
returnValue: false,
|
||||
)
|
||||
as bool);
|
||||
|
||||
@override
|
||||
_i15.Future<void> setDashboardWidgetVisible(
|
||||
_i17.DashboardWidget? key,
|
||||
bool? visible,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#setDashboardWidgetVisible, [key, visible]),
|
||||
returnValue: _i15.Future<void>.value(),
|
||||
returnValueForMissingStub: _i15.Future<void>.value(),
|
||||
)
|
||||
as _i15.Future<void>);
|
||||
|
||||
@override
|
||||
void setThemeMode(_i18.ThemeMode? mode) => super.noSuchMethod(
|
||||
Invocation.method(#setThemeMode, [mode]),
|
||||
|
||||
@@ -231,6 +231,14 @@ class MockUserProvider extends _i1.Mock implements _i13.UserProvider {
|
||||
)
|
||||
as _i4.SharedPreferencesAsync);
|
||||
|
||||
@override
|
||||
Map<_i13.DashboardWidget, bool> get dashboardWidgetVisibility =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#dashboardWidgetVisibility),
|
||||
returnValue: <_i13.DashboardWidget, bool>{},
|
||||
)
|
||||
as Map<_i13.DashboardWidget, bool>);
|
||||
|
||||
@override
|
||||
set themeMode(_i14.ThemeMode? value) => super.noSuchMethod(
|
||||
Invocation.setter(#themeMode, value),
|
||||
@@ -243,6 +251,12 @@ class MockUserProvider extends _i1.Mock implements _i13.UserProvider {
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set dashboardWidgetVisibility(Map<_i13.DashboardWidget, bool>? value) => super.noSuchMethod(
|
||||
Invocation.setter(#dashboardWidgetVisibility, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set profile(_i15.Profile? value) => super.noSuchMethod(
|
||||
Invocation.setter(#profile, value),
|
||||
@@ -259,6 +273,26 @@ class MockUserProvider extends _i1.Mock implements _i13.UserProvider {
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
bool isDashboardWidgetVisible(_i13.DashboardWidget? key) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#isDashboardWidgetVisible, [key]),
|
||||
returnValue: false,
|
||||
)
|
||||
as bool);
|
||||
|
||||
@override
|
||||
_i11.Future<void> setDashboardWidgetVisible(
|
||||
_i13.DashboardWidget? key,
|
||||
bool? visible,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#setDashboardWidgetVisible, [key, visible]),
|
||||
returnValue: _i11.Future<void>.value(),
|
||||
returnValueForMissingStub: _i11.Future<void>.value(),
|
||||
)
|
||||
as _i11.Future<void>);
|
||||
|
||||
@override
|
||||
void setThemeMode(_i14.ThemeMode? mode) => super.noSuchMethod(
|
||||
Invocation.method(#setThemeMode, [mode]),
|
||||
|
||||
Reference in New Issue
Block a user