mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Also allow changing the order of the dashboard widgets
This makes the behaviour more consistent and allows users to remove widgets they won't be using, like the trophies
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:wger/helpers/consts.dart';
|
||||
@@ -28,44 +29,48 @@ import 'package:wger/providers/base_provider.dart';
|
||||
|
||||
enum DashboardWidget {
|
||||
routines('routines'),
|
||||
nutrition('nutrition'),
|
||||
weight('weight'),
|
||||
measurements('measurements'),
|
||||
calendar('calendar'),
|
||||
nutrition('nutrition');
|
||||
calendar('calendar');
|
||||
|
||||
final String value;
|
||||
const DashboardWidget(this.value);
|
||||
|
||||
static DashboardWidget? fromString(String s) {
|
||||
for (final e in DashboardWidget.values) {
|
||||
if (e.value == s) return e;
|
||||
if (e.value == s) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class DashboardItem {
|
||||
final DashboardWidget widget;
|
||||
bool isVisible;
|
||||
|
||||
DashboardItem(this.widget, {this.isVisible = true});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'widget': widget.value,
|
||||
'visible': isVisible,
|
||||
};
|
||||
}
|
||||
|
||||
class UserProvider with ChangeNotifier {
|
||||
ThemeMode themeMode = ThemeMode.system;
|
||||
final WgerBaseProvider baseProvider;
|
||||
late SharedPreferencesAsync prefs;
|
||||
|
||||
// New: visibility state for dashboard widgets
|
||||
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';
|
||||
|
||||
UserProvider(this.baseProvider, {SharedPreferencesAsync? prefs}) {
|
||||
this.prefs = prefs ?? PreferenceHelper.asyncPref;
|
||||
_loadThemeMode();
|
||||
_loadDashboardVisibility();
|
||||
_loadDashboardConfig();
|
||||
}
|
||||
|
||||
static const String PREFS_DASHBOARD_CONFIG = 'dashboardConfig';
|
||||
static const PROFILE_URL = 'userprofile';
|
||||
static const VERIFY_EMAIL = 'verify-email';
|
||||
|
||||
@@ -76,15 +81,6 @@ class UserProvider with ChangeNotifier {
|
||||
profile = null;
|
||||
}
|
||||
|
||||
// // change the unit of plates
|
||||
// void changeUnit({changeTo = 'kg'}) {
|
||||
// if (changeTo == 'kg') {
|
||||
// profile?.weightUnitStr = 'lb';
|
||||
// } else {
|
||||
// profile?.weightUnitStr = 'kg';
|
||||
// }
|
||||
// }
|
||||
|
||||
// Load theme mode from SharedPreferences
|
||||
Future<void> _loadThemeMode() async {
|
||||
final prefsDarkMode = await prefs.getBool(PREFS_USER_DARK_THEME);
|
||||
@@ -98,47 +94,76 @@ class UserProvider with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _loadDashboardVisibility() async {
|
||||
final jsonString = await prefs.getString(PREFS_DASHBOARD_VISIBILITY);
|
||||
// Dashboard configuration
|
||||
List<DashboardItem> _dashboardItems = DashboardWidget.values
|
||||
.map((w) => DashboardItem(w))
|
||||
.toList();
|
||||
|
||||
List<DashboardWidget> get dashboardOrder => _dashboardItems.map((e) => e.widget).toList();
|
||||
|
||||
Future<void> _loadDashboardConfig() async {
|
||||
final jsonString = await prefs.getString(PREFS_DASHBOARD_CONFIG);
|
||||
if (jsonString == null) {
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final decoded = jsonDecode(jsonString) as Map<String, dynamic>;
|
||||
final Map<DashboardWidget, bool> loaded = {};
|
||||
final List<dynamic> decoded = jsonDecode(jsonString);
|
||||
final List<DashboardItem> loaded = [];
|
||||
|
||||
for (final entry in decoded.entries) {
|
||||
final widget = DashboardWidget.fromString(entry.key);
|
||||
for (final item in decoded) {
|
||||
final widget = DashboardWidget.fromString(item['widget']);
|
||||
if (widget != null) {
|
||||
loaded[widget] = entry.value as bool;
|
||||
loaded.add(
|
||||
DashboardItem(widget, isVisible: item['visible'] as bool),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (loaded.isNotEmpty) {
|
||||
dashboardWidgetVisibility = loaded;
|
||||
// Add any missing widgets (e.g. newly added features)
|
||||
for (final widget in DashboardWidget.values) {
|
||||
if (!loaded.any((item) => item.widget == widget)) {
|
||||
loaded.add(DashboardItem(widget));
|
||||
}
|
||||
}
|
||||
|
||||
_dashboardItems = loaded;
|
||||
} catch (_) {
|
||||
// parsing failed -> keep defaults
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _saveDashboardConfig() async {
|
||||
final serializable = _dashboardItems.map((e) => e.toJson()).toList();
|
||||
await prefs.setString(PREFS_DASHBOARD_CONFIG, jsonEncode(serializable));
|
||||
}
|
||||
|
||||
bool isDashboardWidgetVisible(DashboardWidget key) {
|
||||
return dashboardWidgetVisibility[key] ?? true;
|
||||
final widget = _dashboardItems.firstWhereOrNull((e) => e.widget == key);
|
||||
return widget == null || widget.isVisible;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
final item = _dashboardItems.firstWhereOrNull((e) => e.widget == key);
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await prefs.setString(
|
||||
PREFS_DASHBOARD_VISIBILITY,
|
||||
jsonEncode(serializable),
|
||||
);
|
||||
item.isVisible = visible;
|
||||
await _saveDashboardConfig();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> setDashboardOrder(int oldIndex, int newIndex) async {
|
||||
if (oldIndex < newIndex) {
|
||||
newIndex -= 1;
|
||||
}
|
||||
final item = _dashboardItems.removeAt(oldIndex);
|
||||
_dashboardItems.insert(newIndex, item);
|
||||
|
||||
await _saveDashboardConfig();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -32,6 +32,21 @@ class DashboardScreen extends StatelessWidget {
|
||||
|
||||
static const routeName = '/dashboard';
|
||||
|
||||
Widget _getDashboardWidget(DashboardWidget widget) {
|
||||
switch (widget) {
|
||||
case DashboardWidget.routines:
|
||||
return const DashboardRoutineWidget();
|
||||
case DashboardWidget.weight:
|
||||
return const DashboardWeightWidget();
|
||||
case DashboardWidget.measurements:
|
||||
return const DashboardMeasurementWidget();
|
||||
case DashboardWidget.calendar:
|
||||
return const DashboardCalendarWidget();
|
||||
case DashboardWidget.nutrition:
|
||||
return const DashboardNutritionWidget();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final user = Provider.of<UserProvider>(context);
|
||||
@@ -41,18 +56,10 @@ class DashboardScreen extends StatelessWidget {
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
children: [
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.routines))
|
||||
const DashboardRoutineWidget(),
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.weight))
|
||||
const DashboardWeightWidget(),
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.measurements))
|
||||
const DashboardMeasurementWidget(),
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.calendar))
|
||||
const DashboardCalendarWidget(),
|
||||
if (user.isDashboardWidgetVisible(DashboardWidget.nutrition))
|
||||
const DashboardNutritionWidget(),
|
||||
],
|
||||
children: user.dashboardOrder
|
||||
.where((w) => user.isDashboardWidgetVisible(w))
|
||||
.map(_getDashboardWidget)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/screens/settings_dashboard_widgets_screen.dart';
|
||||
import 'package:wger/screens/settings_plates_screen.dart';
|
||||
|
||||
import './settings/exercise_cache.dart';
|
||||
@@ -52,13 +51,6 @@ 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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -28,36 +28,49 @@ class SettingsDashboardVisibility extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context);
|
||||
|
||||
String getTitle(DashboardWidget w) {
|
||||
switch (w) {
|
||||
case DashboardWidget.routines:
|
||||
return i18n.routines;
|
||||
case DashboardWidget.weight:
|
||||
return i18n.weight;
|
||||
case DashboardWidget.measurements:
|
||||
return i18n.measurements;
|
||||
case DashboardWidget.calendar:
|
||||
return i18n.calendar;
|
||||
case DashboardWidget.nutrition:
|
||||
return i18n.nutritionalPlans;
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
),
|
||||
],
|
||||
return ReorderableListView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
buildDefaultDragHandles: false,
|
||||
onReorder: user.setDashboardOrder,
|
||||
children: user.dashboardOrder.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
final w = entry.value;
|
||||
|
||||
return ListTile(
|
||||
key: ValueKey(w),
|
||||
title: Text(getTitle(w)),
|
||||
leading: IconButton(
|
||||
icon: user.isDashboardWidgetVisible(w)
|
||||
? const Icon(Icons.visibility)
|
||||
: const Icon(Icons.visibility_off, color: Colors.grey),
|
||||
onPressed: () => user.setDashboardWidgetVisible(
|
||||
w,
|
||||
!user.isDashboardWidgetVisible(w),
|
||||
),
|
||||
),
|
||||
trailing: ReorderableDragStartListener(
|
||||
index: index,
|
||||
child: const Icon(Icons.drag_handle),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
121
test/core/settings_dashboard_visibility_test.dart
Normal file
121
test/core/settings_dashboard_visibility_test.dart
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
|
||||
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/providers/base_provider.dart';
|
||||
import 'package:wger/providers/user.dart';
|
||||
import 'package:wger/widgets/core/settings/dashboard_visibility.dart';
|
||||
|
||||
import 'settings_dashboard_visibility_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([
|
||||
UserProvider,
|
||||
WgerBaseProvider,
|
||||
])
|
||||
void main() {
|
||||
late UserProvider userProvider;
|
||||
late MockWgerBaseProvider mockBaseProvider;
|
||||
|
||||
setUp(() {
|
||||
SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty();
|
||||
mockBaseProvider = MockWgerBaseProvider();
|
||||
userProvider = UserProvider(mockBaseProvider);
|
||||
});
|
||||
|
||||
Widget createWidget() {
|
||||
return ChangeNotifierProvider<UserProvider>.value(
|
||||
value: userProvider,
|
||||
child: const MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: Scaffold(
|
||||
body: SettingsDashboardVisibility(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('renders list of dashboard widgets', (tester) async {
|
||||
await tester.pumpWidget(createWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Verify all items are present
|
||||
expect(find.byType(ListTile), findsNWidgets(DashboardWidget.values.length));
|
||||
expect(find.text('Routines'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('toggle visibility updates provider', (tester) async {
|
||||
await tester.pumpWidget(createWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Routines should be visible initally (default is true)
|
||||
expect(userProvider.isDashboardWidgetVisible(DashboardWidget.routines), true);
|
||||
|
||||
// Find the visibility icon for Routines
|
||||
final routineTile = find.byKey(const ValueKey(DashboardWidget.routines));
|
||||
final iconBtn = find.descendant(of: routineTile, matching: find.byType(IconButton));
|
||||
|
||||
// Check icon is 'visibility'
|
||||
expect(find.descendant(of: iconBtn, matching: find.byIcon(Icons.visibility)), findsOneWidget);
|
||||
|
||||
// Tap to toggle
|
||||
await tester.tap(iconBtn);
|
||||
await tester.pump(); // re-render
|
||||
|
||||
// Check provider state
|
||||
expect(userProvider.isDashboardWidgetVisible(DashboardWidget.routines), false);
|
||||
|
||||
// Check icon is 'visibility_off'
|
||||
expect(
|
||||
find.descendant(of: iconBtn, matching: find.byIcon(Icons.visibility_off)),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
|
||||
// Reordering test is a bit flaky without full drag setup, but we can try
|
||||
testWidgets('dragging reorders items', (tester) async {
|
||||
await tester.pumpWidget(createWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Initial order: routines, nutrition, weight...
|
||||
expect(userProvider.dashboardOrder[0], DashboardWidget.routines);
|
||||
expect(userProvider.dashboardOrder[1], DashboardWidget.nutrition);
|
||||
|
||||
// Find drag handle for Routines (index 0)
|
||||
final handleFinder = find.byIcon(Icons.drag_handle);
|
||||
final firstHandle = handleFinder.at(0);
|
||||
// final secondHandle = handleFinder.at(1);
|
||||
|
||||
// Drag first item down
|
||||
await tester.drag(firstHandle, const Offset(0, 100)); // Drag down enough to swap
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Verify order changed
|
||||
// If swapped with second item (nutrition) and maybe third (weight) depending on height
|
||||
// Based on running test: index 0 is nutrition, index 1 is weight.
|
||||
expect(userProvider.dashboardOrder[0], DashboardWidget.nutrition);
|
||||
expect(userProvider.dashboardOrder[1], DashboardWidget.weight);
|
||||
expect(userProvider.dashboardOrder[2], DashboardWidget.routines);
|
||||
});
|
||||
}
|
||||
349
test/core/settings_dashboard_visibility_test.mocks.dart
Normal file
349
test/core/settings_dashboard_visibility_test.mocks.dart
Normal file
@@ -0,0 +1,349 @@
|
||||
// Mocks generated by Mockito 5.4.6 from annotations
|
||||
// in wger/test/core/settings_dashboard_visibility_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i9;
|
||||
import 'dart:ui' as _i10;
|
||||
|
||||
import 'package:flutter/material.dart' as _i7;
|
||||
import 'package:http/http.dart' as _i5;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:shared_preferences/shared_preferences.dart' as _i3;
|
||||
import 'package:wger/models/user/profile.dart' as _i8;
|
||||
import 'package:wger/providers/auth.dart' as _i4;
|
||||
import 'package:wger/providers/base_provider.dart' as _i2;
|
||||
import 'package:wger/providers/user.dart' as _i6;
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: avoid_redundant_argument_values
|
||||
// ignore_for_file: avoid_setters_without_getters
|
||||
// ignore_for_file: comment_references
|
||||
// ignore_for_file: deprecated_member_use
|
||||
// ignore_for_file: deprecated_member_use_from_same_package
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
// ignore_for_file: must_be_immutable
|
||||
// ignore_for_file: prefer_const_constructors
|
||||
// ignore_for_file: unnecessary_parenthesis
|
||||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: subtype_of_sealed_class
|
||||
// ignore_for_file: invalid_use_of_internal_member
|
||||
|
||||
class _FakeWgerBaseProvider_0 extends _i1.SmartFake implements _i2.WgerBaseProvider {
|
||||
_FakeWgerBaseProvider_0(Object parent, Invocation parentInvocation)
|
||||
: super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeSharedPreferencesAsync_1 extends _i1.SmartFake implements _i3.SharedPreferencesAsync {
|
||||
_FakeSharedPreferencesAsync_1(Object parent, Invocation parentInvocation)
|
||||
: super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeAuthProvider_2 extends _i1.SmartFake implements _i4.AuthProvider {
|
||||
_FakeAuthProvider_2(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeClient_3 extends _i1.SmartFake implements _i5.Client {
|
||||
_FakeClient_3(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeUri_4 extends _i1.SmartFake implements Uri {
|
||||
_FakeUri_4(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
class _FakeResponse_5 extends _i1.SmartFake implements _i5.Response {
|
||||
_FakeResponse_5(Object parent, Invocation parentInvocation) : super(parent, parentInvocation);
|
||||
}
|
||||
|
||||
/// A class which mocks [UserProvider].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockUserProvider extends _i1.Mock implements _i6.UserProvider {
|
||||
MockUserProvider() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_i7.ThemeMode get themeMode =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#themeMode),
|
||||
returnValue: _i7.ThemeMode.system,
|
||||
)
|
||||
as _i7.ThemeMode);
|
||||
|
||||
@override
|
||||
_i2.WgerBaseProvider get baseProvider =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#baseProvider),
|
||||
returnValue: _FakeWgerBaseProvider_0(
|
||||
this,
|
||||
Invocation.getter(#baseProvider),
|
||||
),
|
||||
)
|
||||
as _i2.WgerBaseProvider);
|
||||
|
||||
@override
|
||||
_i3.SharedPreferencesAsync get prefs =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#prefs),
|
||||
returnValue: _FakeSharedPreferencesAsync_1(
|
||||
this,
|
||||
Invocation.getter(#prefs),
|
||||
),
|
||||
)
|
||||
as _i3.SharedPreferencesAsync);
|
||||
|
||||
@override
|
||||
List<_i6.DashboardWidget> get dashboardOrder =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#dashboardOrder),
|
||||
returnValue: <_i6.DashboardWidget>[],
|
||||
)
|
||||
as List<_i6.DashboardWidget>);
|
||||
|
||||
@override
|
||||
set themeMode(_i7.ThemeMode? value) => super.noSuchMethod(
|
||||
Invocation.setter(#themeMode, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set prefs(_i3.SharedPreferencesAsync? value) => super.noSuchMethod(
|
||||
Invocation.setter(#prefs, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set profile(_i8.Profile? value) => super.noSuchMethod(
|
||||
Invocation.setter(#profile, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
bool get hasListeners =>
|
||||
(super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false) as bool);
|
||||
|
||||
@override
|
||||
void clear() => super.noSuchMethod(
|
||||
Invocation.method(#clear, []),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
bool isDashboardWidgetVisible(_i6.DashboardWidget? key) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#isDashboardWidgetVisible, [key]),
|
||||
returnValue: false,
|
||||
)
|
||||
as bool);
|
||||
|
||||
@override
|
||||
_i9.Future<void> setDashboardWidgetVisible(
|
||||
_i6.DashboardWidget? key,
|
||||
bool? visible,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#setDashboardWidgetVisible, [key, visible]),
|
||||
returnValue: _i9.Future<void>.value(),
|
||||
returnValueForMissingStub: _i9.Future<void>.value(),
|
||||
)
|
||||
as _i9.Future<void>);
|
||||
|
||||
@override
|
||||
_i9.Future<void> setDashboardOrder(int? oldIndex, int? newIndex) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#setDashboardOrder, [oldIndex, newIndex]),
|
||||
returnValue: _i9.Future<void>.value(),
|
||||
returnValueForMissingStub: _i9.Future<void>.value(),
|
||||
)
|
||||
as _i9.Future<void>);
|
||||
|
||||
@override
|
||||
void setThemeMode(_i7.ThemeMode? mode) => super.noSuchMethod(
|
||||
Invocation.method(#setThemeMode, [mode]),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
_i9.Future<void> fetchAndSetProfile() =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetchAndSetProfile, []),
|
||||
returnValue: _i9.Future<void>.value(),
|
||||
returnValueForMissingStub: _i9.Future<void>.value(),
|
||||
)
|
||||
as _i9.Future<void>);
|
||||
|
||||
@override
|
||||
_i9.Future<void> saveProfile() =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#saveProfile, []),
|
||||
returnValue: _i9.Future<void>.value(),
|
||||
returnValueForMissingStub: _i9.Future<void>.value(),
|
||||
)
|
||||
as _i9.Future<void>);
|
||||
|
||||
@override
|
||||
_i9.Future<void> verifyEmail() =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#verifyEmail, []),
|
||||
returnValue: _i9.Future<void>.value(),
|
||||
returnValueForMissingStub: _i9.Future<void>.value(),
|
||||
)
|
||||
as _i9.Future<void>);
|
||||
|
||||
@override
|
||||
void addListener(_i10.VoidCallback? listener) => super.noSuchMethod(
|
||||
Invocation.method(#addListener, [listener]),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
void removeListener(_i10.VoidCallback? listener) => super.noSuchMethod(
|
||||
Invocation.method(#removeListener, [listener]),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
void dispose() => super.noSuchMethod(
|
||||
Invocation.method(#dispose, []),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
void notifyListeners() => super.noSuchMethod(
|
||||
Invocation.method(#notifyListeners, []),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
}
|
||||
|
||||
/// A class which mocks [WgerBaseProvider].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockWgerBaseProvider extends _i1.Mock implements _i2.WgerBaseProvider {
|
||||
MockWgerBaseProvider() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_i4.AuthProvider get auth =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#auth),
|
||||
returnValue: _FakeAuthProvider_2(this, Invocation.getter(#auth)),
|
||||
)
|
||||
as _i4.AuthProvider);
|
||||
|
||||
@override
|
||||
_i5.Client get client =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#client),
|
||||
returnValue: _FakeClient_3(this, Invocation.getter(#client)),
|
||||
)
|
||||
as _i5.Client);
|
||||
|
||||
@override
|
||||
set auth(_i4.AuthProvider? value) => super.noSuchMethod(
|
||||
Invocation.setter(#auth, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
set client(_i5.Client? value) => super.noSuchMethod(
|
||||
Invocation.setter(#client, value),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
|
||||
@override
|
||||
Map<String, String> getDefaultHeaders({bool? includeAuth = false}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getDefaultHeaders, [], {
|
||||
#includeAuth: includeAuth,
|
||||
}),
|
||||
returnValue: <String, String>{},
|
||||
)
|
||||
as Map<String, String>);
|
||||
|
||||
@override
|
||||
Uri makeUrl(
|
||||
String? path, {
|
||||
int? id,
|
||||
String? objectMethod,
|
||||
Map<String, dynamic>? query,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#makeUrl,
|
||||
[path],
|
||||
{#id: id, #objectMethod: objectMethod, #query: query},
|
||||
),
|
||||
returnValue: _FakeUri_4(
|
||||
this,
|
||||
Invocation.method(
|
||||
#makeUrl,
|
||||
[path],
|
||||
{#id: id, #objectMethod: objectMethod, #query: query},
|
||||
),
|
||||
),
|
||||
)
|
||||
as Uri);
|
||||
|
||||
@override
|
||||
_i9.Future<dynamic> fetch(
|
||||
Uri? uri, {
|
||||
int? maxRetries = 3,
|
||||
Duration? initialDelay = const Duration(milliseconds: 250),
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#fetch,
|
||||
[uri],
|
||||
{#maxRetries: maxRetries, #initialDelay: initialDelay},
|
||||
),
|
||||
returnValue: _i9.Future<dynamic>.value(),
|
||||
)
|
||||
as _i9.Future<dynamic>);
|
||||
|
||||
@override
|
||||
_i9.Future<List<dynamic>> fetchPaginated(Uri? uri) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#fetchPaginated, [uri]),
|
||||
returnValue: _i9.Future<List<dynamic>>.value(<dynamic>[]),
|
||||
)
|
||||
as _i9.Future<List<dynamic>>);
|
||||
|
||||
@override
|
||||
_i9.Future<Map<String, dynamic>> post(Map<String, dynamic>? data, Uri? uri) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#post, [data, uri]),
|
||||
returnValue: _i9.Future<Map<String, dynamic>>.value(
|
||||
<String, dynamic>{},
|
||||
),
|
||||
)
|
||||
as _i9.Future<Map<String, dynamic>>);
|
||||
|
||||
@override
|
||||
_i9.Future<Map<String, dynamic>> patch(
|
||||
Map<String, dynamic>? data,
|
||||
Uri? uri,
|
||||
) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#patch, [data, uri]),
|
||||
returnValue: _i9.Future<Map<String, dynamic>>.value(
|
||||
<String, dynamic>{},
|
||||
),
|
||||
)
|
||||
as _i9.Future<Map<String, dynamic>>);
|
||||
|
||||
@override
|
||||
_i9.Future<_i5.Response> deleteRequest(String? url, int? id) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#deleteRequest, [url, id]),
|
||||
returnValue: _i9.Future<_i5.Response>.value(
|
||||
_FakeResponse_5(
|
||||
this,
|
||||
Invocation.method(#deleteRequest, [url, id]),
|
||||
),
|
||||
),
|
||||
)
|
||||
as _i9.Future<_i5.Response>);
|
||||
}
|
||||
@@ -49,7 +49,9 @@ void main() {
|
||||
|
||||
setUp(() {
|
||||
when(mockUserProvider.themeMode).thenReturn(ThemeMode.system);
|
||||
when(mockUserProvider.isDashboardWidgetVisible(any)).thenReturn(true);
|
||||
when(
|
||||
mockSharedPreferences.getString(UserProvider.PREFS_DASHBOARD_CONFIG),
|
||||
).thenAnswer((_) async => null);
|
||||
when(mockExerciseProvider.exercises).thenReturn(getTestExercises());
|
||||
when(mockNutritionProvider.ingredients).thenReturn([ingredient1, ingredient2]);
|
||||
});
|
||||
@@ -101,19 +103,15 @@ 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);
|
||||
final userProvider = await UserProvider(MockWgerBaseProvider(), prefs: mockSharedPreferences);
|
||||
final userProvider = UserProvider(MockWgerBaseProvider(), prefs: mockSharedPreferences);
|
||||
await Future.delayed(const Duration(milliseconds: 50)); // wait for async prefs load
|
||||
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);
|
||||
final userProvider = await UserProvider(MockWgerBaseProvider(), prefs: mockSharedPreferences);
|
||||
final userProvider = UserProvider(MockWgerBaseProvider(), prefs: mockSharedPreferences);
|
||||
await Future.delayed(const Duration(milliseconds: 50)); // wait for async prefs load
|
||||
expect(userProvider.themeMode, ThemeMode.light);
|
||||
});
|
||||
|
||||
|
||||
@@ -944,12 +944,12 @@ class MockUserProvider extends _i1.Mock implements _i21.UserProvider {
|
||||
as _i14.SharedPreferencesAsync);
|
||||
|
||||
@override
|
||||
Map<_i21.DashboardWidget, bool> get dashboardWidgetVisibility =>
|
||||
List<_i21.DashboardWidget> get dashboardOrder =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#dashboardWidgetVisibility),
|
||||
returnValue: <_i21.DashboardWidget, bool>{},
|
||||
Invocation.getter(#dashboardOrder),
|
||||
returnValue: <_i21.DashboardWidget>[],
|
||||
)
|
||||
as Map<_i21.DashboardWidget, bool>);
|
||||
as List<_i21.DashboardWidget>);
|
||||
|
||||
@override
|
||||
set themeMode(_i22.ThemeMode? value) => super.noSuchMethod(
|
||||
@@ -963,12 +963,6 @@ 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),
|
||||
@@ -1005,6 +999,15 @@ class MockUserProvider extends _i1.Mock implements _i21.UserProvider {
|
||||
)
|
||||
as _i18.Future<void>);
|
||||
|
||||
@override
|
||||
_i18.Future<void> setDashboardOrder(int? oldIndex, int? newIndex) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#setDashboardOrder, [oldIndex, newIndex]),
|
||||
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]),
|
||||
|
||||
@@ -404,6 +404,17 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations {
|
||||
)
|
||||
as String);
|
||||
|
||||
@override
|
||||
String get dashboardWidgets =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#dashboardWidgets),
|
||||
returnValue: _i3.dummyValue<String>(
|
||||
this,
|
||||
Invocation.getter(#dashboardWidgets),
|
||||
),
|
||||
)
|
||||
as String);
|
||||
|
||||
@override
|
||||
String get labelDashboard =>
|
||||
(super.noSuchMethod(
|
||||
|
||||
@@ -390,12 +390,12 @@ class MockUserProvider extends _i1.Mock implements _i17.UserProvider {
|
||||
as _i4.SharedPreferencesAsync);
|
||||
|
||||
@override
|
||||
Map<_i17.DashboardWidget, bool> get dashboardWidgetVisibility =>
|
||||
List<_i17.DashboardWidget> get dashboardOrder =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#dashboardWidgetVisibility),
|
||||
returnValue: <_i17.DashboardWidget, bool>{},
|
||||
Invocation.getter(#dashboardOrder),
|
||||
returnValue: <_i17.DashboardWidget>[],
|
||||
)
|
||||
as Map<_i17.DashboardWidget, bool>);
|
||||
as List<_i17.DashboardWidget>);
|
||||
|
||||
@override
|
||||
set themeMode(_i18.ThemeMode? value) => super.noSuchMethod(
|
||||
@@ -409,12 +409,6 @@ 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),
|
||||
@@ -451,6 +445,15 @@ class MockUserProvider extends _i1.Mock implements _i17.UserProvider {
|
||||
)
|
||||
as _i15.Future<void>);
|
||||
|
||||
@override
|
||||
_i15.Future<void> setDashboardOrder(int? oldIndex, int? newIndex) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#setDashboardOrder, [oldIndex, newIndex]),
|
||||
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]),
|
||||
|
||||
@@ -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.
|
||||
@@ -21,6 +21,7 @@ import 'dart:convert';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart';
|
||||
import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart';
|
||||
import 'package:wger/providers/base_provider.dart';
|
||||
@@ -51,7 +52,6 @@ void main() {
|
||||
);
|
||||
|
||||
setUp(() {
|
||||
/// Replacement for SharedPreferences.setMockInitialValues()
|
||||
SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty();
|
||||
mockWgerBaseProvider = MockWgerBaseProvider();
|
||||
userProvider = UserProvider(mockWgerBaseProvider);
|
||||
@@ -103,4 +103,80 @@ void main() {
|
||||
verify(userProvider.baseProvider.fetch(tEmailVerifyUri));
|
||||
});
|
||||
});
|
||||
|
||||
group('dashboard config', () {
|
||||
test('initial config should be default (all visible, default order)', () {
|
||||
expect(userProvider.dashboardOrder.length, 5);
|
||||
|
||||
expect(
|
||||
userProvider.dashboardOrder,
|
||||
orderedEquals([
|
||||
DashboardWidget.routines,
|
||||
DashboardWidget.nutrition,
|
||||
DashboardWidget.weight,
|
||||
DashboardWidget.measurements,
|
||||
DashboardWidget.calendar,
|
||||
]),
|
||||
);
|
||||
expect(userProvider.isDashboardWidgetVisible(DashboardWidget.routines), true);
|
||||
});
|
||||
|
||||
test('toggling visibility should update state', () async {
|
||||
// act
|
||||
await userProvider.setDashboardWidgetVisible(DashboardWidget.routines, false);
|
||||
|
||||
// assert
|
||||
expect(userProvider.isDashboardWidgetVisible(DashboardWidget.routines), false);
|
||||
|
||||
// re-enable
|
||||
await userProvider.setDashboardWidgetVisible(DashboardWidget.routines, true);
|
||||
expect(userProvider.isDashboardWidgetVisible(DashboardWidget.routines), true);
|
||||
});
|
||||
|
||||
test('reordering should update order', () async {
|
||||
// arrange
|
||||
final initialFirst = userProvider.dashboardOrder[0];
|
||||
final initialSecond = userProvider.dashboardOrder[1];
|
||||
|
||||
// act: move first to second position
|
||||
// oldIndex: 0, newIndex: 2 (because insert is before index)
|
||||
await userProvider.setDashboardOrder(0, 2);
|
||||
|
||||
// assert
|
||||
expect(userProvider.dashboardOrder[0], initialSecond);
|
||||
expect(userProvider.dashboardOrder[1], initialFirst);
|
||||
});
|
||||
|
||||
test('should load config from prefs', () async {
|
||||
// arrange
|
||||
final prefs = SharedPreferencesAsync();
|
||||
final customConfig = [
|
||||
{'widget': 'nutrition', 'visible': true},
|
||||
{'widget': 'routines', 'visible': false},
|
||||
];
|
||||
await prefs.setString(
|
||||
UserProvider.PREFS_DASHBOARD_CONFIG,
|
||||
jsonEncode(customConfig),
|
||||
);
|
||||
|
||||
// act
|
||||
final newProvider = UserProvider(mockWgerBaseProvider, prefs: prefs);
|
||||
await Future.delayed(const Duration(milliseconds: 50)); // wait for async prefs load
|
||||
|
||||
// assert
|
||||
// The loaded ones come first
|
||||
expect(newProvider.dashboardOrder[0], DashboardWidget.nutrition);
|
||||
expect(newProvider.dashboardOrder[1], DashboardWidget.routines);
|
||||
|
||||
// Check visibility
|
||||
expect(newProvider.isDashboardWidgetVisible(DashboardWidget.nutrition), true);
|
||||
expect(newProvider.isDashboardWidgetVisible(DashboardWidget.routines), false);
|
||||
|
||||
// Remaining items are added after
|
||||
expect(newProvider.dashboardOrder.length, 5);
|
||||
|
||||
// Items not in the prefs are visible by default
|
||||
expect(newProvider.isDashboardWidgetVisible(DashboardWidget.weight), true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -232,12 +232,12 @@ class MockUserProvider extends _i1.Mock implements _i13.UserProvider {
|
||||
as _i4.SharedPreferencesAsync);
|
||||
|
||||
@override
|
||||
Map<_i13.DashboardWidget, bool> get dashboardWidgetVisibility =>
|
||||
List<_i13.DashboardWidget> get dashboardOrder =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#dashboardWidgetVisibility),
|
||||
returnValue: <_i13.DashboardWidget, bool>{},
|
||||
Invocation.getter(#dashboardOrder),
|
||||
returnValue: <_i13.DashboardWidget>[],
|
||||
)
|
||||
as Map<_i13.DashboardWidget, bool>);
|
||||
as List<_i13.DashboardWidget>);
|
||||
|
||||
@override
|
||||
set themeMode(_i14.ThemeMode? value) => super.noSuchMethod(
|
||||
@@ -251,12 +251,6 @@ 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),
|
||||
@@ -293,6 +287,15 @@ class MockUserProvider extends _i1.Mock implements _i13.UserProvider {
|
||||
)
|
||||
as _i11.Future<void>);
|
||||
|
||||
@override
|
||||
_i11.Future<void> setDashboardOrder(int? oldIndex, int? newIndex) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#setDashboardOrder, [oldIndex, newIndex]),
|
||||
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