mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Use the powersync drift provider to show exercises
This commit is contained in:
@@ -11,10 +11,14 @@ import 'package:wger/models/exercises/language.dart';
|
||||
import 'package:wger/models/exercises/muscle.dart';
|
||||
import 'package:wger/models/exercises/translation.dart';
|
||||
import 'package:wger/models/exercises/video.dart';
|
||||
import 'package:wger/models/measurements/measurement_category.dart';
|
||||
import 'package:wger/models/workouts/log.dart';
|
||||
|
||||
import 'powersync.dart';
|
||||
import 'tables/exercise.dart';
|
||||
import 'tables/language.dart';
|
||||
import 'tables/measurements.dart';
|
||||
import 'tables/routines.dart';
|
||||
import 'tables/weight.dart';
|
||||
|
||||
part 'database.g.dart';
|
||||
@@ -37,6 +41,8 @@ part 'database.g.dart';
|
||||
|
||||
// User data
|
||||
WeightEntryTable,
|
||||
MeasurementCategoryTable,
|
||||
WorkoutLogTable,
|
||||
],
|
||||
//include: {'queries.drift'},
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
24
lib/database/powersync/tables/measurements.dart
Normal file
24
lib/database/powersync/tables/measurements.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:wger/models/measurements/measurement_category.dart';
|
||||
import 'package:wger/models/measurements/measurement_entry.dart';
|
||||
|
||||
@UseRowClass(MeasurementCategory)
|
||||
class MeasurementCategoryTable extends Table {
|
||||
@override
|
||||
String get tableName => 'measurements_category';
|
||||
|
||||
IntColumn get id => integer()();
|
||||
TextColumn get name => text()();
|
||||
TextColumn get unit => text()();
|
||||
}
|
||||
|
||||
@UseRowClass(MeasurementEntry)
|
||||
class MeasurementEntryTable extends Table {
|
||||
@override
|
||||
String get tableName => 'measurements_measurement';
|
||||
|
||||
IntColumn get id => integer()();
|
||||
DateTimeColumn get date => dateTime()();
|
||||
RealColumn get value => real()();
|
||||
TextColumn get notes => text()();
|
||||
}
|
||||
29
lib/database/powersync/tables/routines.dart
Normal file
29
lib/database/powersync/tables/routines.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:powersync/powersync.dart' show uuid;
|
||||
import 'package:wger/models/workouts/log.dart';
|
||||
|
||||
@UseRowClass(Log)
|
||||
class WorkoutLogTable extends Table {
|
||||
@override
|
||||
String get tableName => 'manager_workoutlog';
|
||||
|
||||
TextColumn get id => text().clientDefault(() => uuid.v4())();
|
||||
IntColumn get exerciseId => integer().named('exercise_id')();
|
||||
IntColumn get routineId => integer().named('routine_id')();
|
||||
IntColumn get sessionId => integer().named('session_id').nullable()();
|
||||
IntColumn get iteration => integer().nullable()();
|
||||
IntColumn get slotEntryId => integer().named('slot_entry_id').nullable()();
|
||||
|
||||
RealColumn get rir => real().nullable()();
|
||||
RealColumn get rirTarget => real().named('rir_target').nullable()();
|
||||
|
||||
RealColumn get repetitions => real()();
|
||||
RealColumn get repetitionsTarget => real().named('repetitions_target')();
|
||||
IntColumn get repetitionsUnitId => integer().named('repetitions_unit_id').nullable()();
|
||||
|
||||
RealColumn get weight => real()();
|
||||
RealColumn get weightTarget => real().named('weight_target')();
|
||||
IntColumn get weightUnitId => integer().named('weight_unit_id').nullable()();
|
||||
|
||||
DateTimeColumn get date => dateTime()();
|
||||
}
|
||||
@@ -296,7 +296,7 @@ void showDeleteDialog(BuildContext context, String confirmDeleteName, Log log) a
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.error),
|
||||
),
|
||||
onPressed: () {
|
||||
context.read<RoutinesProvider>().deleteLog(log.id!, log.routineId);
|
||||
context.read<RoutinesProvider>().deleteLog(log.id.toString(), log.routineId);
|
||||
|
||||
Navigator.of(contextDialog).pop();
|
||||
|
||||
|
||||
@@ -95,6 +95,9 @@ Schema schema = const Schema([
|
||||
Column.text('url'),
|
||||
Column.integer('is_main'),
|
||||
],
|
||||
indexes: [
|
||||
Index('exercise', [IndexedColumn('exercise_id')]),
|
||||
],
|
||||
),
|
||||
Table(
|
||||
'exercises_exercisevideo',
|
||||
@@ -111,6 +114,9 @@ Schema schema = const Schema([
|
||||
Column.integer('license_id'),
|
||||
Column.text('license_author'),
|
||||
],
|
||||
indexes: [
|
||||
Index('exercise', [IndexedColumn('exercise_id')]),
|
||||
],
|
||||
),
|
||||
|
||||
//
|
||||
@@ -124,4 +130,38 @@ Schema schema = const Schema([
|
||||
Column.text('date'),
|
||||
],
|
||||
),
|
||||
Table(
|
||||
'measurements_category',
|
||||
[
|
||||
Column.text('name'),
|
||||
Column.real('unit'),
|
||||
],
|
||||
),
|
||||
Table(
|
||||
'manager_workoutlog',
|
||||
[
|
||||
Column.integer('exercise_id'),
|
||||
Column.integer('routine_id'),
|
||||
Column.integer('session_id'),
|
||||
Column.integer('iteration'),
|
||||
Column.integer('slot_entry_id'),
|
||||
Column.real('rir'),
|
||||
Column.real('rir_target'),
|
||||
Column.real('repetitions'),
|
||||
Column.real('repetitions_target'),
|
||||
Column.integer('repetitions_unit_id'),
|
||||
Column.real('weight'),
|
||||
Column.real('weight_target'),
|
||||
Column.integer('weight_unit_id'),
|
||||
Column.text('date'),
|
||||
],
|
||||
indexes: [
|
||||
Index('exercise', [IndexedColumn('exercise_id')]),
|
||||
Index('slot_entry', [IndexedColumn('slot_entry_id')]),
|
||||
Index('routine', [IndexedColumn('routine_id')]),
|
||||
Index('session', [IndexedColumn('session_id')]),
|
||||
Index('repetitions_unit', [IndexedColumn('repetitions_unit_id')]),
|
||||
Index('weight_unit', [IndexedColumn('weight_unit_id')]),
|
||||
],
|
||||
),
|
||||
]);
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:wger/database/powersync/database.dart';
|
||||
import 'package:wger/models/exercises/equipment.dart';
|
||||
import 'package:wger/models/exercises/exercise.dart';
|
||||
import 'package:wger/models/exercises/muscle.dart';
|
||||
|
||||
part 'exercise_data.g.dart';
|
||||
|
||||
@@ -14,6 +15,7 @@ final class ExerciseNotifier extends _$ExerciseNotifier {
|
||||
@override
|
||||
Stream<List<Exercise>> build() {
|
||||
final db = ref.read(driftPowerSyncDatabase);
|
||||
_logger.fine('Building exercise stream');
|
||||
|
||||
final primaryMuscleTable = db.alias(db.muscleTable, 'pm');
|
||||
final secondaryMuscleTable = db.alias(db.muscleTable, 'sm');
|
||||
@@ -25,6 +27,12 @@ final class ExerciseNotifier extends _$ExerciseNotifier {
|
||||
db.exerciseTranslationTable.exerciseId.equalsExp(db.exerciseTable.id),
|
||||
),
|
||||
|
||||
// Language
|
||||
leftOuterJoin(
|
||||
db.languageTable,
|
||||
db.languageTable.id.equalsExp(db.exerciseTranslationTable.languageId),
|
||||
),
|
||||
|
||||
// Exercise <-> Muscle
|
||||
leftOuterJoin(
|
||||
db.exerciseMuscleM2N,
|
||||
@@ -80,6 +88,7 @@ final class ExerciseNotifier extends _$ExerciseNotifier {
|
||||
}
|
||||
|
||||
if (translation != null && !entry.translations.any((t) => t.id == translation.id)) {
|
||||
translation.language = row.readTable(db.languageTable);
|
||||
entry.translations.add(translation);
|
||||
}
|
||||
|
||||
@@ -104,6 +113,21 @@ final class ExerciseNotifier extends _$ExerciseNotifier {
|
||||
return map.values.toList();
|
||||
});
|
||||
}
|
||||
|
||||
Exercise? getById(int id) {
|
||||
// Can be null e.g. during initial loading
|
||||
final cached = state.asData?.value;
|
||||
if (cached == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (final e in cached) {
|
||||
if (e.id == id) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
@@ -114,3 +138,12 @@ final class ExerciseEquipmentNotifier extends _$ExerciseEquipmentNotifier {
|
||||
return db.select(db.equipmentTable).watch();
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
final class ExerciseMuscleNotifier extends _$ExerciseMuscleNotifier {
|
||||
@override
|
||||
Stream<List<Muscle>> build() {
|
||||
final db = ref.read(driftPowerSyncDatabase);
|
||||
return db.select(db.muscleTable).watch();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ final class ExerciseNotifierProvider
|
||||
ExerciseNotifier create() => ExerciseNotifier();
|
||||
}
|
||||
|
||||
String _$exerciseNotifierHash() => r'4f6613f81e292dd3c74f9eebbbb20482b8da1e42';
|
||||
String _$exerciseNotifierHash() => r'2b7dafd181f3659590ddbd961e7f903d6ba31338';
|
||||
|
||||
abstract class _$ExerciseNotifier extends $StreamNotifier<List<Exercise>> {
|
||||
Stream<List<Exercise>> build();
|
||||
@@ -98,3 +98,48 @@ abstract class _$ExerciseEquipmentNotifier extends $StreamNotifier<List<Equipmen
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(ExerciseMuscleNotifier)
|
||||
const exerciseMuscleProvider = ExerciseMuscleNotifierProvider._();
|
||||
|
||||
final class ExerciseMuscleNotifierProvider
|
||||
extends $StreamNotifierProvider<ExerciseMuscleNotifier, List<Muscle>> {
|
||||
const ExerciseMuscleNotifierProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'exerciseMuscleProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$exerciseMuscleNotifierHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
ExerciseMuscleNotifier create() => ExerciseMuscleNotifier();
|
||||
}
|
||||
|
||||
String _$exerciseMuscleNotifierHash() => r'6be0b7400776f1593194fb43667acbeee8e3a4a8';
|
||||
|
||||
abstract class _$ExerciseMuscleNotifier extends $StreamNotifier<List<Muscle>> {
|
||||
Stream<List<Muscle>> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final created = build();
|
||||
final ref = this.ref as $Ref<AsyncValue<List<Muscle>>, List<Muscle>>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<List<Muscle>>, List<Muscle>>,
|
||||
AsyncValue<List<Muscle>>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleValue(ref, created);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:wger/l10n/generated/app_localizations.dart';
|
||||
import 'package:wger/models/exercises/exercise.dart';
|
||||
import 'package:wger/providers/exercises.dart';
|
||||
import 'package:wger/providers/exercise_data.dart';
|
||||
import 'package:wger/widgets/core/app_bar.dart';
|
||||
import 'package:wger/widgets/core/progress_indicator.dart';
|
||||
import 'package:wger/widgets/exercises/filter_row.dart';
|
||||
import 'package:wger/widgets/exercises/list_tile.dart';
|
||||
|
||||
class ExercisesScreen extends StatefulWidget {
|
||||
class ExercisesScreen extends ConsumerWidget {
|
||||
const ExercisesScreen({super.key});
|
||||
|
||||
static const routeName = '/exercises';
|
||||
|
||||
@override
|
||||
_ExercisesScreenState createState() => _ExercisesScreenState();
|
||||
}
|
||||
|
||||
class _ExercisesScreenState extends State<ExercisesScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final exercisesList = Provider.of<ExercisesProvider>(context).filteredExercises;
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final exercises = ref.watch(exerciseProvider);
|
||||
|
||||
return Scaffold(
|
||||
appBar: EmptyAppBar(AppLocalizations.of(context).exercises),
|
||||
@@ -27,15 +23,21 @@ class _ExercisesScreenState extends State<ExercisesScreen> {
|
||||
children: [
|
||||
const FilterRow(),
|
||||
Expanded(
|
||||
child: exercisesList.isEmpty
|
||||
? const Center(
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
width: 30,
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
)
|
||||
: _ExercisesList(exerciseList: exercisesList),
|
||||
child: exercises.when(
|
||||
data: (List<Exercise> exercisesList) {
|
||||
return exercisesList.isEmpty
|
||||
? const Center(
|
||||
child: SizedBox(
|
||||
height: 30,
|
||||
width: 30,
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
)
|
||||
: _ExercisesList(exerciseList: exercisesList);
|
||||
},
|
||||
loading: () => const BoxedProgressIndicator(),
|
||||
error: (err, st) => Center(child: Text('Error: $err')),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -61,7 +61,7 @@ Widget _getStatusIcon(ps.SyncStatus status) {
|
||||
} else if (status.downloading) {
|
||||
return _makeIcon('Downloading', Icons.cloud_download_outlined);
|
||||
} else {
|
||||
return _makeIcon('Connected', Icons.cloud_queue);
|
||||
return _makeIcon('Connected', Icons.cloud_done_outlined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user