Move more widgets to use the new providers

This commit is contained in:
Roland Geider
2025-10-31 12:46:22 +01:00
parent 92eee49a7b
commit 30c7c5ad8b
7 changed files with 75 additions and 71 deletions

View File

@@ -152,12 +152,45 @@ final class ExerciseStateNotifier extends _$ExerciseStateNotifier {
}).toList();
}
Exercise? getById(int id) {
try {
return state.exercises.firstWhere((e) => e.id == id);
} catch (_) {
return null;
List<Exercise> get allExercises {
return state.exercises;
}
Exercise getById(int id) {
return state.exercises.firstWhere((e) => e.id == id);
}
Map<int, List<Exercise>> get exerciseByVariation {
final Map<int, List<Exercise>> variations = {};
for (final exercise in state.exercises.where((e) => e.variationId != null)) {
if (!variations.containsKey(exercise.variationId)) {
variations[exercise.variationId!] = [];
}
variations[exercise.variationId]!.add(exercise);
}
return variations;
}
/// Find exercises by variation IDs
///
/// exerciseIdToExclude: the ID of the exercise to exclude from the list of
/// returned exercises. Since this is typically called by one exercise, we are
/// not interested in seeing that same exercise returned in the list of variations.
/// If this parameter is not passed, all exercises are returned.
List<Exercise> findExercisesByVariationId(int? variationId, {int? exerciseIdToExclude}) {
if (variationId == null) {
return [];
}
var out = state.exercises.where((base) => base.variationId == variationId).toList();
if (exerciseIdToExclude != null) {
out = out.where((e) => e.id != exerciseIdToExclude).toList();
}
return out;
}
Future<List<Exercise>> searchExercise(

View File

@@ -1,21 +1,3 @@
/*
* This file is part of wger Workout Manager <https://github.com/wger-project>.
* Copyright (c) 2020, 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/>.
*/
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'exercise_state_notifier.dart';
@@ -92,7 +74,7 @@ final class ExerciseStateNotifierProvider
}
}
String _$exerciseStateNotifierHash() => r'2afd58c1f64a23010125795263121a745d2b17c0';
String _$exerciseStateNotifierHash() => r'317a9ce4bccae9899e30048be1586a6c21a2a006';
abstract class _$ExerciseStateNotifier extends $Notifier<ExerciseState> {
ExerciseState build();

View File

@@ -106,25 +106,6 @@ class ExercisesProvider with ChangeNotifier {
);
}
/// Find exercises by variation IDs
///
/// exerciseIdToExclude: the ID of the exercise to exclude from the list of
/// returned exercises. Since this is typically called by one exercise, we are
/// not interested in seeing that same exercise returned in the list of variations.
/// If this parameter is not passed, all exercises are returned.
List<Exercise> findExercisesByVariationId(int? variationId, {int? exerciseIdToExclude}) {
if (variationId == null) {
return [];
}
var out = exercises.where((base) => base.variationId == variationId).toList();
if (exerciseIdToExclude != null) {
out = out.where((e) => e.id != exerciseIdToExclude).toList();
}
return out;
}
/// Find category by ID
ExerciseCategory findCategoryById(int id) {
return _categories.firstWhere(

View File

@@ -1,17 +1,18 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:provider/provider.dart' as provider;
import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/providers/add_exercise.dart';
import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/exercise_state_notifier.dart';
class Step2Variations extends StatelessWidget {
class Step2Variations extends ConsumerWidget {
final GlobalKey<FormState> formkey;
const Step2Variations({required this.formkey});
@override
Widget build(BuildContext context) {
final exerciseProvider = context.read<ExercisesProvider>();
Widget build(BuildContext context, WidgetRef ref) {
final exerciseProvider = ref.read(exerciseStateProvider.notifier);
return Form(
key: formkey,
@@ -49,7 +50,7 @@ class Step2Variations extends StatelessWidget {
],
),
),
Consumer<AddExerciseProvider>(
provider.Consumer<AddExerciseProvider>(
builder: (ctx, provider, __) => Switch(
value: provider.variationId == key,
onChanged: (state) => provider.variationId = key,
@@ -59,7 +60,7 @@ class Step2Variations extends StatelessWidget {
),
),
// Exercise bases without variations
...exerciseProvider.exercises
...exerciseProvider.allExercises
.where((b) => b.variationId == null)
.map(
(base) => Row(
@@ -82,7 +83,7 @@ class Step2Variations extends StatelessWidget {
],
),
),
Consumer<AddExerciseProvider>(
provider.Consumer<AddExerciseProvider>(
builder: (ctx, provider, __) => Switch(
value: provider.variationConnectToExercise == base.id,
onChanged: (state) => provider.variationConnectToExercise = base.id,

View File

@@ -19,8 +19,8 @@
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:provider/provider.dart';
import 'package:wger/helpers/consts.dart';
import 'package:wger/helpers/i18n.dart';
import 'package:wger/helpers/platform.dart';
@@ -29,22 +29,24 @@ import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/exercises/image.dart';
import 'package:wger/models/exercises/muscle.dart';
import 'package:wger/models/exercises/translation.dart';
import 'package:wger/providers/exercises.dart';
import 'package:wger/providers/exercise_state_notifier.dart';
import 'package:wger/widgets/core/core.dart';
import 'package:wger/widgets/exercises/images.dart';
import 'package:wger/widgets/exercises/list_tile.dart';
import 'package:wger/widgets/exercises/videos.dart';
class ExerciseDetail extends StatelessWidget {
class ExerciseDetail extends ConsumerWidget {
final Exercise _exercise;
late Translation _translation;
late final Translation _translation;
late final ExerciseStateNotifier _exerciseStateNotifier;
static const PADDING = 9.0;
final CarouselController carouselController = CarouselController();
ExerciseDetail(this._exercise);
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
_exerciseStateNotifier = ref.read(exerciseStateProvider.notifier);
_translation = _exercise.getTranslation(Localizations.localeOf(context).languageCode);
return SingleChildScrollView(
@@ -81,11 +83,10 @@ class ExerciseDetail extends StatelessWidget {
}
List<Widget> getVariations(BuildContext context) {
final variations = Provider.of<ExercisesProvider>(context, listen: false)
.findExercisesByVariationId(
_exercise.variationId,
exerciseIdToExclude: _exercise.id,
);
final variations = _exerciseStateNotifier.findExercisesByVariationId(
_exercise.variationId,
exerciseIdToExclude: _exercise.id,
);
final List<Widget> out = [];
if (_exercise.variationId == null) {

View File

@@ -118,7 +118,7 @@ class _GymModeState extends ConsumerState<GymMode> {
for (final slot in widget._dayDataGym.slots) {
var firstPage = true;
for (final config in slot.setConfigs) {
final exercise = context.read<ExercisesProvider>().findExerciseById(config.exerciseId);
final exercise = ref.read(exerciseStateProvider.notifier).getById(config.exerciseId);
if (firstPage) {
_exercisePages[exercise] = currentPage;
@@ -141,7 +141,7 @@ class _GymModeState extends ConsumerState<GymMode> {
var firstPage = true;
for (final config in slotData.setConfigs) {
final ratioCompleted = currentElement / _totalElements;
final exercise = exercisesAsync.getById(config.exerciseId)!;
final exercise = exercisesAsync.getById(config.exerciseId);
currentElement++;
if (firstPage && state.showExercisePages) {

View File

@@ -17,6 +17,7 @@
*/
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:wger/helpers/colors.dart';
import 'package:wger/helpers/date.dart';
@@ -26,31 +27,34 @@ import 'package:wger/l10n/generated/app_localizations.dart';
import 'package:wger/models/workouts/log.dart';
import 'package:wger/models/workouts/routine.dart';
import 'package:wger/models/workouts/session.dart';
import 'package:wger/providers/network_provider.dart';
import 'package:wger/widgets/measurements/charts.dart';
import 'package:wger/widgets/routines/charts.dart';
import 'package:wger/widgets/routines/forms/session.dart';
class SessionInfo extends StatefulWidget {
class SessionInfo extends ConsumerStatefulWidget {
final WorkoutSession _session;
const SessionInfo(this._session);
@override
State<SessionInfo> createState() => _SessionInfoState();
ConsumerState<SessionInfo> createState() => _SessionInfoState();
}
class _SessionInfoState extends State<SessionInfo> {
class _SessionInfoState extends ConsumerState<SessionInfo> {
bool editMode = false;
@override
Widget build(BuildContext context) {
final i18n = AppLocalizations.of(context);
final isOnline = ref.watch(networkStatusProvider);
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
ListTile(
enabled: isOnline,
title: Text(
i18n.workoutSession,
style: Theme.of(context).textTheme.headlineSmall,
@@ -160,14 +164,16 @@ class ExerciseLogChart extends StatelessWidget {
}
}
class DayLogWidget extends StatelessWidget {
class DayLogWidget extends ConsumerWidget {
final DateTime _date;
final Routine _routine;
const DayLogWidget(this._date, this._routine);
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final isOnline = ref.watch(networkStatusProvider);
final sessionApi = _routine.sessions.firstWhere(
(sessionApi) => sessionApi.session.date.isSameDayAs(_date),
);
@@ -197,9 +203,9 @@ class DayLogWidget extends StatelessWidget {
IconButton(
icon: const Icon(Icons.delete),
key: ValueKey('delete-log-${log.id}'),
onPressed: () {
showDeleteDialog(context, translation.name, log);
},
onPressed: isOnline
? () => showDeleteLogDialog(context, translation.name, log)
: null,
),
],
),