- 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>
84 lines
2.7 KiB
Dart
84 lines
2.7 KiB
Dart
import 'package:flutter/widgets.dart';
|
||
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:provider/provider.dart';
|
||
import 'package:shared_preferences/shared_preferences.dart';
|
||
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, {
|
||
String? name,
|
||
List<String> primary = const ['hamstrings'],
|
||
List<String> secondary = const [],
|
||
String? equipment = 'body only',
|
||
String level = 'beginner',
|
||
List<String> instructions = const ['Breathe.'],
|
||
int imageCount = 0,
|
||
}) => Exercise(
|
||
id: id,
|
||
name: name ?? id.replaceAll('_', ' '),
|
||
mode: mode,
|
||
category: mode == Mode.stretching ? 'stretching' : 'strength',
|
||
level: level,
|
||
equipment: equipment,
|
||
primaryMuscles: primary,
|
||
secondaryMuscles: secondary,
|
||
instructions: instructions,
|
||
imageCount: imageCount,
|
||
);
|
||
|
||
/// Two stretches and a squat. The 90/90 Hamstring's images exist in the real assets.
|
||
final sampleLibrary = ExerciseLibrary([
|
||
exercise(
|
||
'90_90_Hamstring',
|
||
Mode.stretching,
|
||
name: '90/90 Hamstring',
|
||
secondary: const ['calves'],
|
||
instructions: const ['Lie on your back.', 'Straighten one leg.'],
|
||
imageCount: 2,
|
||
),
|
||
exercise('Calf_Stretch', Mode.stretching, primary: const ['calves'], equipment: 'other', level: 'intermediate'),
|
||
exercise('Barbell_Squat', Mode.workout, primary: const ['quadriceps'], equipment: 'barbell'),
|
||
]);
|
||
|
||
/// A Pixel-sized screen instead of the default 800×600, so the floating
|
||
/// navigation bar does not cover what a test taps.
|
||
void usePhoneScreen(WidgetTester tester) {
|
||
tester.view.physicalSize = const Size(1080, 2400);
|
||
tester.view.devicePixelRatio = 2.75;
|
||
addTearDown(tester.view.reset);
|
||
}
|
||
|
||
/// The whole app over [library], with preferences starting from [prefs].
|
||
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(),
|
||
),
|
||
);
|
||
await tester.pumpAndSettle();
|
||
return settings;
|
||
}
|