diff --git a/lib/screens/timer/flow_timer.dart b/lib/screens/timer/flow_timer.dart index 3233dfe..9e3bf30 100644 --- a/lib/screens/timer/flow_timer.dart +++ b/lib/screens/timer/flow_timer.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lightmeter/data/models/exposure_pair.dart'; -import 'package:lightmeter/interactors/metering_interactor.dart'; import 'package:lightmeter/interactors/timer_interactor.dart'; import 'package:lightmeter/providers/services_provider.dart'; import 'package:lightmeter/screens/timer/bloc_timer.dart'; diff --git a/lib/screens/timer/screen_timer.dart b/lib/screens/timer/screen_timer.dart index 8d0e5d9..ffafb5e 100644 --- a/lib/screens/timer/screen_timer.dart +++ b/lib/screens/timer/screen_timer.dart @@ -22,10 +22,11 @@ class TimerScreen extends StatefulWidget { }); @override - State createState() => _TimerScreenState(); + State createState() => TimerScreenState(); } -class _TimerScreenState extends State with TickerProviderStateMixin { +@visibleForTesting +class TimerScreenState extends State with TickerProviderStateMixin { late AnimationController timelineController; late Animation timelineAnimation; late AnimationController startStopIconController; @@ -47,12 +48,6 @@ class _TimerScreenState extends State with TickerProviderStateMixin startStopIconAnimation = Tween(begin: 0, end: 1).animate(startStopIconController); } - @override - void didChangeDependencies() { - super.didChangeDependencies(); - context.read().add(const StartTimerEvent()); - } - @override void dispose() { timelineController.dispose(); @@ -113,7 +108,7 @@ class _TimerScreenState extends State with TickerProviderStateMixin ), ), ), - right: Navigator.of(context).canPop() ? const CloseButton() : null, + right: const CloseButton(), ), ], ), diff --git a/test/screens/timer/goldens/timer_screen.png b/test/screens/timer/goldens/timer_screen.png new file mode 100644 index 0000000..a1af354 Binary files /dev/null and b/test/screens/timer/goldens/timer_screen.png differ diff --git a/test/screens/timer/screen_metering_golden_test.dart b/test/screens/timer/screen_metering_golden_test.dart deleted file mode 100644 index 8c7e15f..0000000 --- a/test/screens/timer/screen_metering_golden_test.dart +++ /dev/null @@ -1,144 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:golden_toolkit/golden_toolkit.dart'; -import 'package:lightmeter/data/models/ev_source_type.dart'; -import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; -import 'package:lightmeter/data/models/theme_type.dart'; -import 'package:lightmeter/data/shared_prefs_service.dart'; -import 'package:lightmeter/providers/user_preferences_provider.dart'; -import 'package:lightmeter/screens/metering/flow_metering.dart'; -import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import '../../../integration_test/utils/finder_actions.dart'; -import '../../../integration_test/utils/platform_channel_mock.dart'; -import '../../application_mock.dart'; - -class _MeteringScreenConfig { - final IAPProductStatus iapProductStatus; - final EvSourceType evSourceType; - - _MeteringScreenConfig( - this.iapProductStatus, - this.evSourceType, - ); - - @override - String toString() { - final buffer = StringBuffer(); - buffer.write(iapProductStatus.toString().split('.')[1]); - buffer.write(' - '); - buffer.write(evSourceType.toString().split('.')[1]); - return buffer.toString(); - } -} - -final _testScenarios = [IAPProductStatus.purchased, IAPProductStatus.purchasable].expand( - (iapProductStatus) => EvSourceType.values.map( - (evSourceType) => _MeteringScreenConfig(iapProductStatus, evSourceType), - ), -); - -void main() { - Future setEvSource(WidgetTester tester, Key scenarioWidgetKey, EvSourceType evSourceType) async { - final flow = find.descendant( - of: find.byKey(scenarioWidgetKey), - matching: find.byType(MeteringFlow), - ); - final BuildContext context = tester.element(flow); - if (UserPreferencesProvider.evSourceTypeOf(context) != evSourceType) { - UserPreferencesProvider.of(context).toggleEvSourceType(); - } - await tester.pumpAndSettle(); - } - - Future setTheme(WidgetTester tester, Key scenarioWidgetKey, ThemeType themeType) async { - final flow = find.descendant( - of: find.byKey(scenarioWidgetKey), - matching: find.byType(MeteringFlow), - ); - final BuildContext context = tester.element(flow); - UserPreferencesProvider.of(context).setThemeType(themeType); - await tester.pumpAndSettle(); - } - - Future takePhoto(WidgetTester tester, Key scenarioWidgetKey) async { - final button = find.descendant( - of: find.byKey(scenarioWidgetKey), - matching: find.measureButton(), - ); - await tester.tap(button); - await tester.pump(const Duration(seconds: 2)); // wait for circular progress indicator - await tester.pump(const Duration(seconds: 1)); // wait for circular progress indicator - await tester.pumpAndSettle(); - } - - Future toggleIncidentMetering(WidgetTester tester, Key scenarioWidgetKey, double ev) async { - final button = find.descendant( - of: find.byKey(scenarioWidgetKey), - matching: find.measureButton(), - ); - await tester.tap(button); - await sendMockIncidentEv(ev); - await tester.tap(button); - await tester.pumpAndSettle(); - } - - setUpAll(() { - SharedPreferences.setMockInitialValues({ - UserPreferencesService.evSourceTypeKey: EvSourceType.camera.index, - UserPreferencesService.meteringScreenLayoutKey: json.encode( - { - MeteringScreenLayoutFeature.equipmentProfiles: true, - MeteringScreenLayoutFeature.extremeExposurePairs: true, - MeteringScreenLayoutFeature.filmPicker: true, - }.toJson(), - ), - }); - }); - - testGoldens( - 'MeteringScreen golden test', - (tester) async { - final builder = DeviceBuilder(); - for (final scenario in _testScenarios) { - builder.addScenario( - name: scenario.toString(), - widget: _MockMeteringFlow(productStatus: scenario.iapProductStatus), - onCreate: (scenarioWidgetKey) async { - await setEvSource(tester, scenarioWidgetKey, scenario.evSourceType); - if (scenarioWidgetKey.toString().contains('Dark')) { - await setTheme(tester, scenarioWidgetKey, ThemeType.dark); - } - if (scenario.evSourceType == EvSourceType.camera) { - await takePhoto(tester, scenarioWidgetKey); - } else { - await toggleIncidentMetering(tester, scenarioWidgetKey, 7.3); - } - }, - ); - } - await tester.pumpDeviceBuilder(builder); - await screenMatchesGolden( - tester, - 'metering_screen', - ); - }, - ); -} - -class _MockMeteringFlow extends StatelessWidget { - final IAPProductStatus productStatus; - - const _MockMeteringFlow({required this.productStatus}); - - @override - Widget build(BuildContext context) { - return GoldenTestApplicationMock( - productStatus: productStatus, - child: const MeteringFlow(), - ); - } -} diff --git a/test/screens/timer/screen_timer_golden_test.dart b/test/screens/timer/screen_timer_golden_test.dart new file mode 100644 index 0000000..985edf8 --- /dev/null +++ b/test/screens/timer/screen_timer_golden_test.dart @@ -0,0 +1,138 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:golden_toolkit/golden_toolkit.dart'; +import 'package:lightmeter/data/models/exposure_pair.dart'; +import 'package:lightmeter/data/models/theme_type.dart'; +import 'package:lightmeter/providers/user_preferences_provider.dart'; +import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/shared/animated_circular_button/widget_button_circular_animated.dart'; +import 'package:lightmeter/screens/timer/flow_timer.dart'; +import 'package:lightmeter/screens/timer/screen_timer.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../../application_mock.dart'; + +class _TimerScreenConfig { + final ShutterSpeedValue shutterSpeedValue; + final bool isStopped; + + _TimerScreenConfig({ + required this.shutterSpeedValue, + required this.isStopped, + }); + + @override + String toString() { + final buffer = StringBuffer(); + buffer.write(shutterSpeedValue.toString()); + buffer.write(' - '); + buffer.write(isStopped ? 'stopped' : 'resumed'); + return buffer.toString(); + } +} + +final _testScenarios = [ + const ShutterSpeedValue( + 74, + false, + StopType.full, + ), + const ShutterSpeedValue( + 3642, + false, + StopType.full, + ), +].expand( + (shutterSpeedValue) => [ + _TimerScreenConfig(shutterSpeedValue: shutterSpeedValue, isStopped: true), + _TimerScreenConfig(shutterSpeedValue: shutterSpeedValue, isStopped: false), + ], +); + +void main() { + Future setTheme(WidgetTester tester, Key scenarioWidgetKey, ThemeType themeType) async { + final flow = find.descendant( + of: find.byKey(scenarioWidgetKey), + matching: find.byType(TimerFlow), + ); + final BuildContext context = tester.element(flow); + UserPreferencesProvider.of(context).setThemeType(themeType); + await tester.pumpAndSettle(); + } + + Future toggleTimer(WidgetTester tester, Key scenarioWidgetKey) async { + final button = find.descendant( + of: find.byKey(scenarioWidgetKey), + matching: find.byType(AnimatedCircluarButton), + ); + await tester.tap(button); + await tester.pump(Dimens.durationS); + } + + Future mockResumedState(WidgetTester tester, Key scenarioWidgetKey) async { + final screen = find.descendant( + of: find.byKey(scenarioWidgetKey), + matching: find.byType(TimerScreen), + ); + final TimerScreenState state = tester.state(screen); + state.startStopIconController.stop(); + state.timelineController.stop(); + await tester.pump(); + } + + setUpAll(() { + SharedPreferences.setMockInitialValues({}); + }); + + testGoldens( + 'TimerScreen golden test', + (tester) async { + final builder = DeviceBuilder(); + for (final scenario in _testScenarios) { + builder.addScenario( + name: scenario.toString(), + widget: _MockTimerFlow(scenario.shutterSpeedValue), + onCreate: (scenarioWidgetKey) async { + if (scenarioWidgetKey.toString().contains('Dark')) { + await setTheme(tester, scenarioWidgetKey, ThemeType.dark); + } + await toggleTimer(tester, scenarioWidgetKey); + late final skipTimerDuration = Duration( + milliseconds: (scenario.shutterSpeedValue.value * 0.35 * Duration.millisecondsPerSecond).toInt(), + ); + await tester.pump(skipTimerDuration); + if (scenario.isStopped) { + await toggleTimer(tester, scenarioWidgetKey); + } else { + await mockResumedState(tester, scenarioWidgetKey); + } + }, + ); + } + await tester.pumpDeviceBuilder(builder); + await screenMatchesGolden( + tester, + 'timer_screen', + ); + }, + ); +} + +class _MockTimerFlow extends StatelessWidget { + final ShutterSpeedValue shutterSpeedValue; + + const _MockTimerFlow(this.shutterSpeedValue); + + @override + Widget build(BuildContext context) { + return GoldenTestApplicationMock( + child: TimerFlow( + exposurePair: ExposurePair( + ApertureValue.values.first, + shutterSpeedValue, + ), + ), + ); + } +}