diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 335df77c..efce357f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -263,6 +263,7 @@ }, "selectExercises": "If you want to do a superset you can search for several exercises, they will be grouped together", "@selectExercises": {}, + "personalRecords": "Personal records", "gymMode": "Gym mode", "@gymMode": { "description": "Label when starting the gym mode" diff --git a/lib/models/trophies/user_trophy.dart b/lib/models/trophies/user_trophy.dart index 81cb51e3..8e1e7a81 100644 --- a/lib/models/trophies/user_trophy.dart +++ b/lib/models/trophies/user_trophy.dart @@ -20,6 +20,7 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:wger/helpers/json.dart'; import 'trophy.dart'; +import 'user_trophy_context_data.dart'; part 'user_trophy.g.dart'; @@ -42,12 +43,16 @@ class UserTrophy { @JsonKey(required: true, name: 'is_notified') final bool isNotified; + @JsonKey(required: true, name: 'context_data') + final ContextData? contextData; + UserTrophy({ required this.id, required this.trophy, required this.earnedAt, required this.progress, required this.isNotified, + this.contextData, }); // Boilerplate diff --git a/lib/models/trophies/user_trophy.g.dart b/lib/models/trophies/user_trophy.g.dart index 3208ebf6..97d9da44 100644 --- a/lib/models/trophies/user_trophy.g.dart +++ b/lib/models/trophies/user_trophy.g.dart @@ -15,6 +15,7 @@ UserTrophy _$UserTrophyFromJson(Map json) { 'earned_at', 'progress', 'is_notified', + 'context_data', ], ); return UserTrophy( @@ -23,6 +24,9 @@ UserTrophy _$UserTrophyFromJson(Map json) { earnedAt: utcIso8601ToLocalDate(json['earned_at'] as String), progress: json['progress'] as num, isNotified: json['is_notified'] as bool, + contextData: json['context_data'] == null + ? null + : ContextData.fromJson(json['context_data'] as Map), ); } @@ -32,4 +36,5 @@ Map _$UserTrophyToJson(UserTrophy instance) => . + * Copyright (c) 2025 wger Team + * + * wger Workout Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import 'package:json_annotation/json_annotation.dart'; +import 'package:wger/helpers/json.dart'; + +part 'user_trophy_context_data.g.dart'; + +/// A trophy awarded to a user for achieving a specific milestone. + +@JsonSerializable() +class ContextData { + @JsonKey(required: true, name: 'log_id') + final int logId; + + @JsonKey(required: true, fromJson: utcIso8601ToLocalDate) + final DateTime date; + + @JsonKey(required: true, name: 'session_id') + final int sessionId; + + @JsonKey(required: true, name: 'exercise_id') + final int exerciseId; + + @JsonKey(required: true, name: 'repetitions_unit_id') + final int repetitionsUnitId; + + @JsonKey(required: true) + final num repetitions; + + @JsonKey(required: true, name: 'weight_unit_id') + final int weightUnitId; + + @JsonKey(required: true) + final num weight; + + @JsonKey(required: true) + final int? iteration; + + @JsonKey(required: true, name: 'one_rep_max_estimate') + final num oneRepMaxEstimate; + + ContextData({ + required this.logId, + required this.date, + required this.sessionId, + required this.exerciseId, + required this.repetitionsUnitId, + required this.repetitions, + required this.weightUnitId, + required this.weight, + this.iteration, + required this.oneRepMaxEstimate, + }); + + // Boilerplate + factory ContextData.fromJson(Map json) => _$ContextDataFromJson(json); + + Map toJson() => _$ContextDataToJson(this); +} diff --git a/lib/models/trophies/user_trophy_context_data.g.dart b/lib/models/trophies/user_trophy_context_data.g.dart new file mode 100644 index 00000000..e1fcc63a --- /dev/null +++ b/lib/models/trophies/user_trophy_context_data.g.dart @@ -0,0 +1,50 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_trophy_context_data.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ContextData _$ContextDataFromJson(Map json) { + $checkKeys( + json, + requiredKeys: const [ + 'log_id', + 'date', + 'session_id', + 'exercise_id', + 'repetitions_unit_id', + 'repetitions', + 'weight_unit_id', + 'weight', + 'iteration', + 'one_rep_max_estimate', + ], + ); + return ContextData( + logId: (json['log_id'] as num).toInt(), + date: utcIso8601ToLocalDate(json['date'] as String), + sessionId: (json['session_id'] as num).toInt(), + exerciseId: (json['exercise_id'] as num).toInt(), + repetitionsUnitId: (json['repetitions_unit_id'] as num).toInt(), + repetitions: json['repetitions'] as num, + weightUnitId: (json['weight_unit_id'] as num).toInt(), + weight: json['weight'] as num, + iteration: (json['iteration'] as num?)?.toInt(), + oneRepMaxEstimate: json['one_rep_max_estimate'] as num, + ); +} + +Map _$ContextDataToJson(ContextData instance) => { + 'log_id': instance.logId, + 'date': instance.date.toIso8601String(), + 'session_id': instance.sessionId, + 'exercise_id': instance.exerciseId, + 'repetitions_unit_id': instance.repetitionsUnitId, + 'repetitions': instance.repetitions, + 'weight_unit_id': instance.weightUnitId, + 'weight': instance.weight, + 'iteration': instance.iteration, + 'one_rep_max_estimate': instance.oneRepMaxEstimate, +}; diff --git a/lib/providers/gym_state.dart b/lib/providers/gym_state.dart index 949a753f..752f785d 100644 --- a/lib/providers/gym_state.dart +++ b/lib/providers/gym_state.dart @@ -481,7 +481,7 @@ class GymStateNotifier extends _$GymStateNotifier { pages.add(PageEntry(type: PageType.workoutSummary, pageIndex: pageIndex + 1)); state = state.copyWith(pages: pages); - print(readPageStructure()); + // _logger.fine(readPageStructure()); _logger.finer('Initialized ${state.pages.length} pages'); } diff --git a/lib/providers/gym_state.g.dart b/lib/providers/gym_state.g.dart index 1899e808..1ddf6b8b 100644 --- a/lib/providers/gym_state.g.dart +++ b/lib/providers/gym_state.g.dart @@ -40,7 +40,7 @@ final class GymStateNotifierProvider extends $NotifierProvider r'4e1ac85de3c9f5c7dad4b0c5e6ad80ad36397610'; +String _$gymStateNotifierHash() => r'8474afce33638bf67570fd64b64e9b5d171804d3'; abstract class _$GymStateNotifier extends $Notifier { GymModeState build(); diff --git a/lib/providers/trophies.dart b/lib/providers/trophies.dart index 1da6eea3..e172f5ec 100644 --- a/lib/providers/trophies.dart +++ b/lib/providers/trophies.dart @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import 'package:logging/logging.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:wger/helpers/consts.dart'; import 'package:wger/models/trophies/trophy.dart'; @@ -28,6 +29,8 @@ import 'base_provider.dart'; part 'trophies.g.dart'; class TrophyRepository { + final _logger = Logger('TrophyRepository'); + final WgerBaseProvider base; final trophiesPath = 'trophy'; final userTrophiesPath = 'user-trophy'; @@ -36,21 +39,43 @@ class TrophyRepository { TrophyRepository(this.base); Future> fetchTrophies() async { - final url = base.makeUrl(trophiesPath, query: {'limit': API_MAX_PAGE_SIZE}); - final trophyData = await base.fetchPaginated(url); - return trophyData.map((e) => Trophy.fromJson(e)).toList(); + try { + final url = base.makeUrl(trophiesPath, query: {'limit': API_MAX_PAGE_SIZE}); + final trophyData = await base.fetchPaginated(url); + return trophyData.map((e) => Trophy.fromJson(e)).toList(); + } catch (e, stk) { + _logger.warning('Error fetching trophies:', e, stk); + return []; + } } - Future> fetchUserTrophies() async { - final url = base.makeUrl(userTrophiesPath, query: {'limit': API_MAX_PAGE_SIZE}); - final trophyData = await base.fetchPaginated(url); - return trophyData.map((e) => UserTrophy.fromJson(e)).toList(); + Future> fetchUserTrophies({Map? filterQuery}) async { + final query = {'limit': API_MAX_PAGE_SIZE}; + if (filterQuery != null) { + query.addAll(filterQuery); + } + + try { + final url = base.makeUrl(userTrophiesPath, query: query); + final trophyData = await base.fetchPaginated(url); + return trophyData.map((e) => UserTrophy.fromJson(e)).toList(); + } catch (e, stk) { + _logger.warning('Error fetching user trophies:'); + _logger.warning(e); + _logger.warning(stk); + return []; + } } - Future> fetchProgression() async { - final url = base.makeUrl(userTrophyProgressionPath); - final List data = await base.fetch(url); - return data.map((e) => UserTrophyProgression.fromJson(e)).toList(); + Future> fetchProgression({Map? filterQuery}) async { + try { + final url = base.makeUrl(userTrophyProgressionPath, query: filterQuery); + final List data = await base.fetch(url); + return data.map((e) => UserTrophyProgression.fromJson(e)).toList(); + } catch (e, stk) { + _logger.warning('Error fetching user trophy progression:', e, stk); + return []; + } } List filterByType(List list, TrophyType type) => @@ -74,15 +99,27 @@ final class TrophyStateNotifier extends _$TrophyStateNotifier { return repo.fetchTrophies(); } - /// Fetch trophies awarded to the user + /// Fetch trophies awarded to the user. + /// Excludes hidden trophies as well as repeatable (PR) trophies since they are + /// handled separately Future> fetchUserTrophies() async { final repo = ref.read(trophyRepositoryProvider); - return repo.fetchUserTrophies(); + return repo.fetchUserTrophies( + filterQuery: {'trophy__is_hidden': 'false', 'trophy__is_repeatable': 'false'}, + ); + } + + /// Fetch PR trophies awarded to the user + Future> fetchUserPRTrophies() async { + final repo = ref.read(trophyRepositoryProvider); + return repo.fetchUserTrophies(filterQuery: {'trophy__trophy_type': TrophyType.pr.name}); } /// Fetch trophy progression for the user Future> fetchTrophyProgression() async { final repo = ref.read(trophyRepositoryProvider); - return repo.fetchProgression(); + return repo.fetchProgression( + filterQuery: {'trophy__is_hidden': 'false', 'trophy__is_repeatable': 'false'}, + ); } } diff --git a/lib/providers/trophies.g.dart b/lib/providers/trophies.g.dart index 81c82726..4b413f7f 100644 --- a/lib/providers/trophies.g.dart +++ b/lib/providers/trophies.g.dart @@ -81,7 +81,7 @@ final class TrophyStateNotifierProvider extends $NotifierProvider r'e5c8f2a9477b8f7e5efe4e9ba23765f951627a9f'; +String _$trophyStateNotifierHash() => r'7f50ce352d980168dae169916a17d9b62b388d28'; abstract class _$TrophyStateNotifier extends $Notifier { void build(); diff --git a/lib/widgets/routines/gym_mode/summary.dart b/lib/widgets/routines/gym_mode/summary.dart index 439d7a0d..850af71a 100644 --- a/lib/widgets/routines/gym_mode/summary.dart +++ b/lib/widgets/routines/gym_mode/summary.dart @@ -1,6 +1,6 @@ /* * This file is part of wger Workout Manager . - * Copyright (c) 2020, 2025 wger Team + * Copyright (c) 2020 - 2025 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 @@ -24,10 +24,12 @@ import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; import 'package:wger/helpers/date.dart'; import 'package:wger/l10n/generated/app_localizations.dart'; +import 'package:wger/models/trophies/user_trophy.dart'; import 'package:wger/models/workouts/routine.dart'; import 'package:wger/models/workouts/session_api.dart'; import 'package:wger/providers/gym_state.dart'; import 'package:wger/providers/routines.dart'; +import 'package:wger/providers/trophies.dart'; import 'package:wger/widgets/core/progress_indicator.dart'; import 'package:wger/widgets/routines/gym_mode/navigation.dart'; @@ -48,6 +50,7 @@ class WorkoutSummary extends ConsumerStatefulWidget { class _WorkoutSummaryState extends ConsumerState { late Future _initData; late Routine _routine; + late List _userPrTrophies; @override void initState() { @@ -62,6 +65,9 @@ class _WorkoutSummaryState extends ConsumerState { _routine = await context.read().fetchAndSetRoutineFull( gymState.routine.id!, ); + + final trophyNotifier = ref.read(trophyStateProvider.notifier); + _userPrTrophies = await trophyNotifier.fetchUserPRTrophies(); } @override @@ -82,10 +88,18 @@ class _WorkoutSummaryState extends ConsumerState { } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}: ${snapshot.stackTrace}')); } else if (snapshot.connectionState == ConnectionState.done) { + final apiSession = _routine.sessions.firstWhereOrNull( + (s) => s.session.date.isSameDayAs(clock.now()), + ); + final userTrophies = _userPrTrophies + .where( + (t) => t.contextData!.sessionId == apiSession?.session.id, + ) + .toList(); + return WorkoutSessionStats( - _routine.sessions.firstWhereOrNull( - (s) => s.session.date.isSameDayAs(clock.now()), - ), + apiSession, + userTrophies, ); } @@ -102,12 +116,14 @@ class _WorkoutSummaryState extends ConsumerState { class WorkoutSessionStats extends ConsumerWidget { final _logger = Logger('WorkoutSessionStats'); final WorkoutSessionApi? _sessionApi; + final List _userPrTrophies; - WorkoutSessionStats(this._sessionApi, {super.key}); + WorkoutSessionStats(this._sessionApi, this._userPrTrophies, {super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final i18n = AppLocalizations.of(context); + final theme = Theme.of(context); if (_sessionApi == null) { return Center( @@ -159,16 +175,19 @@ class WorkoutSessionStats extends ConsumerWidget { ), ], ), - // const SizedBox(height: 16), - // InfoCard( - // title: 'Personal Records', - // value: prCount.toString(), - // color: theme.colorScheme.tertiaryContainer, - // ), + if (_userPrTrophies.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 10), + child: InfoCard( + title: i18n.personalRecords, + value: _userPrTrophies.length.toString(), + color: theme.colorScheme.tertiaryContainer, + ), + ), const SizedBox(height: 10), MuscleGroupsCard(_sessionApi.logs), const SizedBox(height: 10), - ExercisesCard(_sessionApi), + ExercisesCard(_sessionApi, _userPrTrophies), FilledButton( onPressed: () { ref.read(gymStateProvider.notifier).clear(); diff --git a/lib/widgets/routines/logs/exercises_expansion_card.dart b/lib/widgets/routines/logs/exercises_expansion_card.dart index 0286418f..ea9634e7 100644 --- a/lib/widgets/routines/logs/exercises_expansion_card.dart +++ b/lib/widgets/routines/logs/exercises_expansion_card.dart @@ -1,6 +1,6 @@ /* * This file is part of wger Workout Manager . - * Copyright (c) 2020, 2025 wger Team + * Copyright (c) 2020 - 2025 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 @@ -20,13 +20,15 @@ import 'package:flutter/material.dart'; import 'package:wger/helpers/i18n.dart'; import 'package:wger/l10n/generated/app_localizations.dart'; import 'package:wger/models/exercises/exercise.dart'; +import 'package:wger/models/trophies/user_trophy.dart'; import 'package:wger/models/workouts/log.dart'; import 'package:wger/models/workouts/session_api.dart'; class ExercisesCard extends StatelessWidget { final WorkoutSessionApi session; + final List userPrTrophies; - const ExercisesCard(this.session, {super.key}); + const ExercisesCard(this.session, this.userPrTrophies, {super.key}); @override Widget build(BuildContext context) { @@ -44,7 +46,11 @@ class ExercisesCard extends StatelessWidget { const SizedBox(height: 16), ...exercises.map((exercise) { final logs = session.logs.where((log) => log.exerciseId == exercise.id).toList(); - return _ExerciseExpansionTile(exercise: exercise, logs: logs); + return _ExerciseExpansionTile( + exercise: exercise, + logs: logs, + userPrTrophies: userPrTrophies, + ); }), ], ), @@ -57,8 +63,10 @@ class _ExerciseExpansionTile extends StatelessWidget { const _ExerciseExpansionTile({ required this.exercise, required this.logs, + required this.userPrTrophies, }); + final List userPrTrophies; final Exercise exercise; final List logs; @@ -78,20 +86,20 @@ class _ExerciseExpansionTile extends StatelessWidget { // leading: const Icon(Icons.fitness_center), title: Text(exercise.getTranslation(languageCode).name, style: theme.textTheme.titleMedium), subtitle: Text('Top set: $topSetWeight $topSetWeightUnit'), - children: logs.map((log) => _SetDataRow(log: log)).toList(), + children: logs.map((log) => _SetDataRow(log: log, userPrTrophies: userPrTrophies)).toList(), ); } } class _SetDataRow extends StatelessWidget { - const _SetDataRow({required this.log}); + const _SetDataRow({required this.log, required this.userPrTrophies}); final Log log; + final List userPrTrophies; @override Widget build(BuildContext context) { final theme = Theme.of(context); - final i18n = AppLocalizations.of(context); return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), @@ -103,6 +111,8 @@ class _SetDataRow extends StatelessWidget { log.repTextNoNl(context), style: theme.textTheme.bodyMedium, ), + if (userPrTrophies.any((trophy) => trophy.contextData?.logId == log.id)) + Icon(Icons.emoji_events, color: theme.colorScheme.primary, size: 20), // if (log.volume() > 0) // Text( // '${log.volume().toStringAsFixed(0)} ${getServerStringTranslation(log.weightUnitObj!.name, context)}', diff --git a/test/core/validators_test.mocks.dart b/test/core/validators_test.mocks.dart index 389f1556..fb63573c 100644 --- a/test/core/validators_test.mocks.dart +++ b/test/core/validators_test.mocks.dart @@ -1107,6 +1107,17 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); + @override + String get personalRecords => + (super.noSuchMethod( + Invocation.getter(#personalRecords), + returnValue: _i3.dummyValue( + this, + Invocation.getter(#personalRecords), + ), + ) + as String); + @override String get gymMode => (super.noSuchMethod( diff --git a/test/trophies/widgets/dashboard_trophies_widget_test.dart b/test/trophies/widgets/dashboard_trophies_widget_test.dart index 7c6a92b4..9d7ae799 100644 --- a/test/trophies/widgets/dashboard_trophies_widget_test.dart +++ b/test/trophies/widgets/dashboard_trophies_widget_test.dart @@ -33,7 +33,9 @@ void main() { testWidgets('DashboardTrophiesWidget shows trophies', (WidgetTester tester) async { // Arrange final mockRepository = MockTrophyRepository(); - when(mockRepository.fetchUserTrophies()).thenAnswer((_) async => getUserTrophies()); + when( + mockRepository.fetchUserTrophies(filterQuery: anyNamed('filterQuery')), + ).thenAnswer((_) async => getUserTrophies()); // Act await mockNetworkImagesFor(() async { @@ -52,7 +54,6 @@ void main() { await tester.pumpAndSettle(); // Assert - // expect(find.text('Trophies'), findsOneWidget); expect(find.text('New Year, New Me'), findsOneWidget); }); }); diff --git a/test/trophies/widgets/dashboard_trophies_widget_test.mocks.dart b/test/trophies/widgets/dashboard_trophies_widget_test.mocks.dart index 1c8f3bde..47c030af 100644 --- a/test/trophies/widgets/dashboard_trophies_widget_test.mocks.dart +++ b/test/trophies/widgets/dashboard_trophies_widget_test.mocks.dart @@ -94,9 +94,13 @@ class MockTrophyRepository extends _i1.Mock implements _i3.TrophyRepository { as _i5.Future>); @override - _i5.Future> fetchUserTrophies() => + _i5.Future> fetchUserTrophies({ + Map? filterQuery, + }) => (super.noSuchMethod( - Invocation.method(#fetchUserTrophies, []), + Invocation.method(#fetchUserTrophies, [], { + #filterQuery: filterQuery, + }), returnValue: _i5.Future>.value( <_i7.UserTrophy>[], ), @@ -104,9 +108,13 @@ class MockTrophyRepository extends _i1.Mock implements _i3.TrophyRepository { as _i5.Future>); @override - _i5.Future> fetchProgression() => + _i5.Future> fetchProgression({ + Map? filterQuery, + }) => (super.noSuchMethod( - Invocation.method(#fetchProgression, []), + Invocation.method(#fetchProgression, [], { + #filterQuery: filterQuery, + }), returnValue: _i5.Future>.value( <_i8.UserTrophyProgression>[], ), diff --git a/test/trophies/widgets/trophies_overview_test.dart b/test/trophies/widgets/trophies_overview_test.dart index 7d7d65aa..7874f991 100644 --- a/test/trophies/widgets/trophies_overview_test.dart +++ b/test/trophies/widgets/trophies_overview_test.dart @@ -33,7 +33,9 @@ void main() { testWidgets('TrophiesOverview shows trophies', (WidgetTester tester) async { // Arrange final mockRepository = MockTrophyRepository(); - when(mockRepository.fetchProgression()).thenAnswer((_) async => getUserTrophyProgression()); + when( + mockRepository.fetchProgression(filterQuery: anyNamed('filterQuery')), + ).thenAnswer((_) async => getUserTrophyProgression()); // Act await mockNetworkImagesFor(() async { diff --git a/test/trophies/widgets/trophies_overview_test.mocks.dart b/test/trophies/widgets/trophies_overview_test.mocks.dart new file mode 100644 index 00000000..039b622a --- /dev/null +++ b/test/trophies/widgets/trophies_overview_test.mocks.dart @@ -0,0 +1,131 @@ +// Mocks generated by Mockito 5.4.6 from annotations +// in wger/test/trophies/widgets/trophies_overview_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i5; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i4; +import 'package:wger/models/trophies/trophy.dart' as _i6; +import 'package:wger/models/trophies/user_trophy.dart' as _i7; +import 'package:wger/models/trophies/user_trophy_progression.dart' as _i8; +import 'package:wger/providers/base_provider.dart' as _i2; +import 'package:wger/providers/trophies.dart' as _i3; + +// 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); +} + +/// A class which mocks [TrophyRepository]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockTrophyRepository extends _i1.Mock implements _i3.TrophyRepository { + MockTrophyRepository() { + _i1.throwOnMissingStub(this); + } + + @override + _i2.WgerBaseProvider get base => + (super.noSuchMethod( + Invocation.getter(#base), + returnValue: _FakeWgerBaseProvider_0( + this, + Invocation.getter(#base), + ), + ) + as _i2.WgerBaseProvider); + + @override + String get trophiesPath => + (super.noSuchMethod( + Invocation.getter(#trophiesPath), + returnValue: _i4.dummyValue( + this, + Invocation.getter(#trophiesPath), + ), + ) + as String); + + @override + String get userTrophiesPath => + (super.noSuchMethod( + Invocation.getter(#userTrophiesPath), + returnValue: _i4.dummyValue( + this, + Invocation.getter(#userTrophiesPath), + ), + ) + as String); + + @override + String get userTrophyProgressionPath => + (super.noSuchMethod( + Invocation.getter(#userTrophyProgressionPath), + returnValue: _i4.dummyValue( + this, + Invocation.getter(#userTrophyProgressionPath), + ), + ) + as String); + + @override + _i5.Future> fetchTrophies() => + (super.noSuchMethod( + Invocation.method(#fetchTrophies, []), + returnValue: _i5.Future>.value(<_i6.Trophy>[]), + ) + as _i5.Future>); + + @override + _i5.Future> fetchUserTrophies({ + Map? filterQuery, + }) => + (super.noSuchMethod( + Invocation.method(#fetchUserTrophies, [], { + #filterQuery: filterQuery, + }), + returnValue: _i5.Future>.value( + <_i7.UserTrophy>[], + ), + ) + as _i5.Future>); + + @override + _i5.Future> fetchProgression({ + Map? filterQuery, + }) => + (super.noSuchMethod( + Invocation.method(#fetchProgression, [], { + #filterQuery: filterQuery, + }), + returnValue: _i5.Future>.value( + <_i8.UserTrophyProgression>[], + ), + ) + as _i5.Future>); + + @override + List<_i6.Trophy> filterByType(List<_i6.Trophy>? list, _i6.TrophyType? type) => + (super.noSuchMethod( + Invocation.method(#filterByType, [list, type]), + returnValue: <_i6.Trophy>[], + ) + as List<_i6.Trophy>); +}