Stage 3: Plan editor with Steps, Supersets and reordering

- Plan model with immutable edits: add with Mode defaults, move, remove,
  Superset with next, take a member out, ungroup; Stretching length
  estimate from holds, sides, rounds and Transitions
- drift database (plans table, items as JSON, ADR 0005) and
  PlanRepository; Plans list per Mode with rename/duplicate/delete
- Editor: drag handles, step editor sheet (sets, reps or time, optional
  kg; hold, both sides, rounds; Superset sets and rest between),
  pause between holds for Stretching Plans
- Exercise picker reusing the Library browser; Add to plan from the
  Exercise detail page
- Theme: Mode-styled snackbar, FAB, menus, segmented buttons, switches

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CedricandClaude Opus 5.5 committed 2026-10-28 23:48:07 +01:00
1 parent 786dd52e30
commit bbdca95541
28 files changed
+3654 -11

No files matched your search

+7
View File
@@ -6,8 +6,11 @@ import 'package:zenxercise/src/app.dart';
import 'package:zenxercise/src/exercises/exercise.dart';
import 'package:zenxercise/src/exercises/exercise_library.dart';
import 'package:zenxercise/src/modes/mode.dart';
import 'package:zenxercise/src/plans/plan_repository.dart';
import 'package:zenxercise/src/settings/settings_controller.dart';
import 'test_database.dart';
Exercise exercise(
String id,
Mode mode, {
@@ -58,15 +61,19 @@ Future<SettingsController> pumpApp(
WidgetTester tester, {
ExerciseLibrary? library,
Map<String, Object> prefs = const {},
PlanRepository? plans,
}) async {
SharedPreferences.setMockInitialValues(prefs);
final settings = SettingsController(SettingsService());
await settings.loadSettings();
final db = testDatabase();
addTearDown(db.close);
await tester.pumpWidget(
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: settings),
Provider.value(value: library ?? sampleLibrary),
Provider.value(value: plans ?? PlanRepository(db)),
],
child: const ZenXerciseApp(),
),
+21
View File
@@ -0,0 +1,21 @@
import 'dart:ffi';
import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:sqlite3/open.dart';
import 'package:zenxercise/src/database/database.dart';
/// An in-memory database for tests. On Windows hosts the sqlite3 library comes
/// from ZENXERCISE_SQLITE_DLL if set, otherwise from the system's winsqlite3.dll.
AppDatabase testDatabase() {
if (Platform.isWindows) {
open.overrideFor(OperatingSystem.windows, () {
final custom = Platform.environment['ZENXERCISE_SQLITE_DLL'];
return DynamicLibrary.open(custom ?? 'winsqlite3.dll');
});
}
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;
// Synchronous stream teardown keeps widget tests from hanging on pending timers.
return AppDatabase(DatabaseConnection(NativeDatabase.memory(), closeStreamsSynchronously: true));
}