diff --git a/iap/lib/src/providers/iap_products_provider.dart b/iap/lib/src/providers/iap_products_provider.dart index 4895fdf..9d381ae 100644 --- a/iap/lib/src/providers/iap_products_provider.dart +++ b/iap/lib/src/providers/iap_products_provider.dart @@ -6,8 +6,10 @@ class IAPProductsProvider extends StatefulWidget { const IAPProductsProvider({required this.child, super.key}); - static IAPProductsProviderState of(BuildContext context) { - return context.findAncestorStateOfType()!; + static IAPProductsProviderState of(BuildContext context) => IAPProductsProvider.maybeOf(context)!; + + static IAPProductsProviderState? maybeOf(BuildContext context) { + return context.findAncestorStateOfType(); } @override @@ -54,8 +56,7 @@ class IAPProducts extends InheritedModel { bool updateShouldNotify(IAPProducts oldWidget) => false; @override - bool updateShouldNotifyDependent(IAPProducts oldWidget, Set dependencies) => - false; + bool updateShouldNotifyDependent(IAPProducts oldWidget, Set dependencies) => false; IAPProduct? _findProduct(IAPProductType type) { try { diff --git a/lib/data/volume_events_service.dart b/lib/data/volume_events_service.dart index d57936a..360de75 100644 --- a/lib/data/volume_events_service.dart +++ b/lib/data/volume_events_service.dart @@ -3,7 +3,7 @@ import 'package:flutter/services.dart'; import 'package:platform/platform.dart'; class VolumeEventsService { - final LocalPlatform localPlatform; + final LocalPlatform _localPlatform; @visibleForTesting static const volumeHandlingChannel = MethodChannel("com.vodemn.lightmeter/volumeHandling"); @@ -11,12 +11,12 @@ class VolumeEventsService { @visibleForTesting static const volumeEventsChannel = EventChannel("com.vodemn.lightmeter/volumeEvents"); - const VolumeEventsService(this.localPlatform); + const VolumeEventsService(this._localPlatform); /// If set to `false` we allow system to handle key events. /// Returns current status of volume handling. Future setVolumeHandling(bool enableHandling) async { - if (!localPlatform.isAndroid) { + if (!_localPlatform.isAndroid) { return false; } return volumeHandlingChannel @@ -29,7 +29,7 @@ class VolumeEventsService { /// KEYCODE_VOLUME_DOWN = 25; /// pressed Stream volumeButtonsEventStream() { - if (!localPlatform.isAndroid) { + if (!_localPlatform.isAndroid) { return const Stream.empty(); } return volumeEventsChannel diff --git a/lib/providers/equipment_profile_provider.dart b/lib/providers/equipment_profile_provider.dart index a5e0999..564c5ef 100644 --- a/lib/providers/equipment_profile_provider.dart +++ b/lib/providers/equipment_profile_provider.dart @@ -54,9 +54,7 @@ class EquipmentProfileProviderState extends State { _defaultProfile, if (IAPProducts.isPurchased(context, IAPProductType.paidFeatures)) ..._customProfiles, ], - selected: IAPProducts.isPurchased(context, IAPProductType.paidFeatures) - ? _selectedProfile - : _defaultProfile, + selected: IAPProducts.isPurchased(context, IAPProductType.paidFeatures) ? _selectedProfile : _defaultProfile, child: widget.child, ); } @@ -85,7 +83,7 @@ class EquipmentProfileProviderState extends State { _refreshSavedProfiles(); } - void updateProdile(EquipmentProfile data) { + void updateProfile(EquipmentProfile data) { final indexToUpdate = _customProfiles.indexWhere((element) => element.id == data.id); if (indexToUpdate >= 0) { _customProfiles[indexToUpdate] = data; @@ -118,13 +116,14 @@ class EquipmentProfiles extends SelectableInheritedModel { /// [_defaultProfile] + profiles created by the user static List of(BuildContext context) { - return InheritedModel.inheritFrom(context, aspect: SelectableAspect.list)! - .values; + return InheritedModel.inheritFrom(context, aspect: SelectableAspect.list)!.values; } static EquipmentProfile selectedOf(BuildContext context) { - return InheritedModel.inheritFrom(context, - aspect: SelectableAspect.selected,)! + return InheritedModel.inheritFrom( + context, + aspect: SelectableAspect.selected, + )! .selected; } } diff --git a/lib/screens/metering/bloc_metering.dart b/lib/screens/metering/bloc_metering.dart index cbb0356..753a7e7 100644 --- a/lib/screens/metering/bloc_metering.dart +++ b/lib/screens/metering/bloc_metering.dart @@ -10,9 +10,9 @@ import 'package:lightmeter/screens/metering/communication/event_communication_me as communication_events; import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; -import 'package:lightmeter/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart'; import 'package:lightmeter/screens/metering/event_metering.dart'; import 'package:lightmeter/screens/metering/state_metering.dart'; +import 'package:lightmeter/screens/metering/utils/notifier_volume_keys.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class MeteringBloc extends Bloc { diff --git a/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart b/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart index 484ee4b..40ec1f0 100644 --- a/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart +++ b/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart @@ -72,7 +72,7 @@ class _Ruler extends StatelessWidget { children: [ if (showValue) Text( - (index + min).toStringSigned(), + (index + min).toStringSignedAsFixed(0), style: Theme.of(context).textTheme.bodyLarge, ), const SizedBox(width: Dimens.grid8), diff --git a/lib/screens/metering/flow_metering.dart b/lib/screens/metering/flow_metering.dart index cca5675..f78482d 100644 --- a/lib/screens/metering/flow_metering.dart +++ b/lib/screens/metering/flow_metering.dart @@ -4,8 +4,8 @@ import 'package:lightmeter/interactors/metering_interactor.dart'; import 'package:lightmeter/providers/services_provider.dart'; import 'package:lightmeter/screens/metering/bloc_metering.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; -import 'package:lightmeter/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart'; import 'package:lightmeter/screens/metering/screen_metering.dart'; +import 'package:lightmeter/screens/metering/utils/notifier_volume_keys.dart'; class MeteringFlow extends StatefulWidget { const MeteringFlow({super.key}); diff --git a/lib/screens/metering/screen_metering.dart b/lib/screens/metering/screen_metering.dart index 6900159..380411f 100644 --- a/lib/screens/metering/screen_metering.dart +++ b/lib/screens/metering/screen_metering.dart @@ -13,7 +13,7 @@ import 'package:lightmeter/screens/metering/components/camera_container/provider import 'package:lightmeter/screens/metering/components/light_sensor_container/provider_container_light_sensor.dart'; import 'package:lightmeter/screens/metering/event_metering.dart'; import 'package:lightmeter/screens/metering/state_metering.dart'; -import 'package:lightmeter/screens/metering/utils/listsner_equipment_profiles.dart'; +import 'package:lightmeter/screens/metering/utils/listener_equipment_profiles.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class MeteringScreen extends StatelessWidget { diff --git a/lib/screens/metering/utils/listsner_equipment_profiles.dart b/lib/screens/metering/utils/listener_equipment_profiles.dart similarity index 100% rename from lib/screens/metering/utils/listsner_equipment_profiles.dart rename to lib/screens/metering/utils/listener_equipment_profiles.dart diff --git a/lib/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart b/lib/screens/metering/utils/notifier_volume_keys.dart similarity index 82% rename from lib/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart rename to lib/screens/metering/utils/notifier_volume_keys.dart index df64fdf..0c19955 100644 --- a/lib/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart +++ b/lib/screens/metering/utils/notifier_volume_keys.dart @@ -5,12 +5,12 @@ import 'package:lightmeter/data/models/volume_action.dart'; import 'package:lightmeter/data/volume_events_service.dart'; class VolumeKeysNotifier extends ChangeNotifier with RouteAware { - final VolumeEventsService volumeEventsService; + final VolumeEventsService _volumeEventsService; late final StreamSubscription _volumeKeysSubscription; VolumeKey _value = VolumeKey.up; - VolumeKeysNotifier(this.volumeEventsService) { - _volumeKeysSubscription = volumeEventsService + VolumeKeysNotifier(this._volumeEventsService) { + _volumeKeysSubscription = _volumeEventsService .volumeButtonsEventStream() .map((event) => event == 24 ? VolumeKey.up : VolumeKey.down) .listen((event) { @@ -19,6 +19,8 @@ class VolumeKeysNotifier extends ChangeNotifier with RouteAware { } VolumeKey get value => _value; + + @protected set value(VolumeKey newValue) { _value = newValue; notifyListeners(); diff --git a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart index 5f8adcd..854a914 100644 --- a/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart +++ b/lib/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart @@ -4,7 +4,7 @@ import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/providers/remote_config_provider.dart'; import 'package:lightmeter/providers/services_provider.dart'; import 'package:lightmeter/res/dimens.dart'; -import 'package:lightmeter/screens/settings/components/utils/show_buy_pro_dialog.dart'; +import 'package:lightmeter/screens/settings/utils/show_buy_pro_dialog.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; class BuyProListTile extends StatelessWidget { diff --git a/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart index b10190f..6879a2c 100644 --- a/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart +++ b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart @@ -90,7 +90,7 @@ class _EquipmentProfilesScreenState extends State { } void _updateProfileAt(EquipmentProfile data) { - EquipmentProfileProvider.of(context).updateProdile(data); + EquipmentProfileProvider.of(context).updateProfile(data); } void _removeProfileAt(EquipmentProfile data) { diff --git a/lib/screens/settings/components/utils/show_buy_pro_dialog.dart b/lib/screens/settings/utils/show_buy_pro_dialog.dart similarity index 94% rename from lib/screens/settings/components/utils/show_buy_pro_dialog.dart rename to lib/screens/settings/utils/show_buy_pro_dialog.dart index 50edbd1..7ce3ff6 100644 --- a/lib/screens/settings/components/utils/show_buy_pro_dialog.dart +++ b/lib/screens/settings/utils/show_buy_pro_dialog.dart @@ -28,7 +28,7 @@ Future showBuyProDialog(BuildContext context) { FilledButton( onPressed: () { Navigator.of(context).pop(); - IAPProductsProvider.of(context).buy(IAPProductType.paidFeatures); + IAPProductsProvider.maybeOf(context)?.buy(IAPProductType.paidFeatures); }, child: Text(unlockFeaturesEnabled ? S.of(context).unlock : S.of(context).buy), ), diff --git a/lib/utils/text_line_height.dart b/lib/utils/text_line_height.dart deleted file mode 100644 index a531074..0000000 --- a/lib/utils/text_line_height.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/widgets.dart'; - -extension TextLineHeight on TextStyle { - double get lineHeight => fontSize! * height!; -} diff --git a/lib/utils/to_string_signed.dart b/lib/utils/to_string_signed.dart index 4122893..fcced8d 100644 --- a/lib/utils/to_string_signed.dart +++ b/lib/utils/to_string_signed.dart @@ -1,13 +1,4 @@ -extension SignedString on num { - String toStringSigned() { - if (this > 0) { - return "+${toString()}"; - } else { - return toString(); - } - } -} - +/// Returns value in form -1 or + 1. The only exception - 0. extension SignedStringDouble on double { String toStringSignedAsFixed(int fractionDigits) { if (this > 0) { diff --git a/pubspec.yaml b/pubspec.yaml index 6fd97bc..ed5fc90 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: m3_lightmeter_iap: git: url: "https://github.com/vodemn/m3_lightmeter_iap" - ref: v0.6.3 + ref: v0.7.0 m3_lightmeter_resources: git: url: "https://github.com/vodemn/m3_lightmeter_resources" diff --git a/test/function_mock.dart b/test/function_mock.dart new file mode 100644 index 0000000..8a4abfe --- /dev/null +++ b/test/function_mock.dart @@ -0,0 +1,7 @@ +import 'package:mocktail/mocktail.dart'; + +class _ValueChanged { + void onChanged(T value) {} +} + +class MockValueChanged extends Mock implements _ValueChanged {} diff --git a/test/interactors/metering_interactor_test.dart b/test/interactors/metering_interactor_test.dart index 1f0b05a..083a116 100644 --- a/test/interactors/metering_interactor_test.dart +++ b/test/interactors/metering_interactor_test.dart @@ -236,7 +236,7 @@ void main() { ); group( - 'Haptics', + 'Light sensor', () { test('hasAmbientLightSensor() - true', () async { when(() => mockLightSensorService.hasSensor()).thenAnswer((_) async => true); diff --git a/test/providers/equipment_profile_provider_test.dart b/test/providers/equipment_profile_provider_test.dart index 83f04f7..fb329cd 100644 --- a/test/providers/equipment_profile_provider_test.dart +++ b/test/providers/equipment_profile_provider_test.dart @@ -260,7 +260,7 @@ class _Application extends StatelessWidget { ElevatedButton( key: updateProfileButtonKey(profile.id), onPressed: () { - EquipmentProfileProvider.of(context).updateProdile( + EquipmentProfileProvider.of(context).updateProfile( profile.copyWith( name: '${profile.name} updated', isoValues: _customProfiles.first.isoValues, diff --git a/test/screens/metering/bloc_metering_test.dart b/test/screens/metering/bloc_metering_test.dart index fbffbbc..f07d35c 100644 --- a/test/screens/metering/bloc_metering_test.dart +++ b/test/screens/metering/bloc_metering_test.dart @@ -7,9 +7,9 @@ import 'package:lightmeter/screens/metering/communication/event_communication_me as communication_events; import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; -import 'package:lightmeter/screens/metering/components/shared/volume_keys_notifier/notifier_volume_keys.dart'; import 'package:lightmeter/screens/metering/event_metering.dart'; import 'package:lightmeter/screens/metering/state_metering.dart'; +import 'package:lightmeter/screens/metering/utils/notifier_volume_keys.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; diff --git a/test/screens/metering/components/shared/readings_container/shared/dialog_picker_test.dart b/test/screens/metering/components/shared/readings_container/shared/dialog_picker_test.dart index 39c38ba..bd037af 100644 --- a/test/screens/metering/components/shared/readings_container/shared/dialog_picker_test.dart +++ b/test/screens/metering/components/shared/readings_container/shared/dialog_picker_test.dart @@ -7,16 +7,11 @@ import 'package:lightmeter/screens/metering/components/shared/readings_container import 'package:mocktail/mocktail.dart'; import '../../../../../../application_mock.dart'; +import '../../../../../../function_mock.dart'; import '../utils.dart'; -class _ValueChanged { - void onChanged(T value) {} -} - -class _MockValueChanged extends Mock implements _ValueChanged {} - void main() { - final functions = _MockValueChanged(); + final functions = MockValueChanged(); group( 'onChanged', diff --git a/test/screens/metering/utils/listener_equipment_profiles_test.dart b/test/screens/metering/utils/listener_equipment_profiles_test.dart new file mode 100644 index 0000000..ae6cb87 --- /dev/null +++ b/test/screens/metering/utils/listener_equipment_profiles_test.dart @@ -0,0 +1,138 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/providers/equipment_profile_provider.dart'; +import 'package:lightmeter/screens/metering/utils/listener_equipment_profiles.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; +import 'package:mocktail/mocktail.dart'; + +import '../../../function_mock.dart'; + +class _MockIAPStorageService extends Mock implements IAPStorageService {} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final storageService = _MockIAPStorageService(); + final equipmentProfileProviderKey = GlobalKey(); + final onDidChangeDependencies = MockValueChanged(); + + tearDown(() { + reset(onDidChangeDependencies); + reset(storageService); + }); + + Future pumpTestWidget(WidgetTester tester) async { + await tester.pumpWidget( + IAPProducts( + products: [ + IAPProduct( + storeId: IAPProductType.paidFeatures.storeId, + status: IAPProductStatus.purchased, + ), + ], + child: EquipmentProfileProvider( + key: equipmentProfileProviderKey, + storageService: storageService, + child: MaterialApp( + home: EquipmentProfileListener( + onDidChangeDependencies: onDidChangeDependencies.onChanged, + child: Builder(builder: (context) => Text(EquipmentProfiles.selectedOf(context).name)), + ), + ), + ), + ), + ); + } + + testWidgets( + 'Trigger `onDidChangeDependencies` by selecting a new profile', + (tester) async { + when(() => storageService.equipmentProfiles).thenReturn(List.from(_customProfiles)); + when(() => storageService.selectedEquipmentProfileId).thenReturn(''); + await pumpTestWidget(tester); + + equipmentProfileProviderKey.currentState!.setProfile(_customProfiles[0]); + await tester.pump(); + verify(() => onDidChangeDependencies.onChanged(_customProfiles[0])).called(1); + }, + ); + + testWidgets( + 'Trigger `onDidChangeDependencies` by updating the selected profile', + (tester) async { + when(() => storageService.equipmentProfiles).thenReturn(List.from(_customProfiles)); + when(() => storageService.selectedEquipmentProfileId).thenReturn(_customProfiles[0].id); + await pumpTestWidget(tester); + + final updatedProfile1 = _customProfiles[0].copyWith(name: 'Test 1 updated'); + equipmentProfileProviderKey.currentState!.updateProfile(updatedProfile1); + await tester.pump(); + verify(() => onDidChangeDependencies.onChanged(updatedProfile1)).called(1); + + /// Verify that updating the not selected profile doesn't trigger the callback + final updatedProfile2 = _customProfiles[1].copyWith(name: 'Test 2 updated'); + equipmentProfileProviderKey.currentState!.updateProfile(updatedProfile2); + await tester.pump(); + verifyNever(() => onDidChangeDependencies.onChanged(updatedProfile2)); + }, + ); + + testWidgets( + "Don't trigger `onDidChangeDependencies` by updating the unselected profile", + (tester) async { + when(() => storageService.equipmentProfiles).thenReturn(List.from(_customProfiles)); + when(() => storageService.selectedEquipmentProfileId).thenReturn(_customProfiles[0].id); + await pumpTestWidget(tester); + + final updatedProfile2 = _customProfiles[1].copyWith(name: 'Test 2 updated'); + equipmentProfileProviderKey.currentState!.updateProfile(updatedProfile2); + await tester.pump(); + verifyNever(() => onDidChangeDependencies.onChanged(updatedProfile2)); + }, + ); +} + +final List _customProfiles = [ + const EquipmentProfile( + id: '1', + name: 'Test 1', + apertureValues: [ + ApertureValue(4.0, StopType.full), + ApertureValue(4.5, StopType.third), + ApertureValue(4.8, StopType.half), + ApertureValue(5.0, StopType.third), + ApertureValue(5.6, StopType.full), + ApertureValue(6.3, StopType.third), + ApertureValue(6.7, StopType.half), + ApertureValue(7.1, StopType.third), + ApertureValue(8, StopType.full), + ], + ndValues: [ + NdValue(0), + NdValue(2), + NdValue(4), + NdValue(8), + NdValue(16), + NdValue(32), + NdValue(64), + ], + shutterSpeedValues: ShutterSpeedValue.values, + isoValues: [ + IsoValue(100, StopType.full), + IsoValue(125, StopType.third), + IsoValue(160, StopType.third), + IsoValue(200, StopType.full), + IsoValue(250, StopType.third), + IsoValue(320, StopType.third), + IsoValue(400, StopType.full), + ], + ), + const EquipmentProfile( + id: '2', + name: 'Test 2', + apertureValues: ApertureValue.values, + ndValues: NdValue.values, + shutterSpeedValues: ShutterSpeedValue.values, + isoValues: IsoValue.values, + ), +]; diff --git a/test/screens/metering/utils/notifier_volume_keys_test.dart b/test/screens/metering/utils/notifier_volume_keys_test.dart new file mode 100644 index 0000000..7bb6458 --- /dev/null +++ b/test/screens/metering/utils/notifier_volume_keys_test.dart @@ -0,0 +1,46 @@ +import 'dart:async'; + +import 'package:lightmeter/data/models/volume_action.dart'; +import 'package:lightmeter/data/volume_events_service.dart'; +import 'package:lightmeter/screens/metering/utils/notifier_volume_keys.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:test/test.dart'; + +import '../../../function_mock.dart'; + +class _MockVolumeEventsService extends Mock implements VolumeEventsService {} + +void main() { + late _MockVolumeEventsService mockVolumeEventsService; + + setUp(() { + mockVolumeEventsService = _MockVolumeEventsService(); + }); + + test( + 'Listen to `volumeButtonsEventStream()`', + () async { + final StreamController volumeButtonsEvents = StreamController(); + when(() => mockVolumeEventsService.volumeButtonsEventStream()).thenAnswer((_) => volumeButtonsEvents.stream); + + final volumeKeysNotifier = VolumeKeysNotifier(mockVolumeEventsService); + final functions = MockValueChanged(); + volumeKeysNotifier.addListener(() => functions.onChanged(volumeKeysNotifier.value)); + expect(volumeKeysNotifier.value, VolumeKey.up); + + volumeButtonsEvents.add(25); + volumeButtonsEvents.add(25); + volumeButtonsEvents.add(25); + volumeButtonsEvents.add(24); + volumeButtonsEvents.add(24); + volumeButtonsEvents.add(25); + await Future.delayed(Duration.zero); + verify(() => functions.onChanged(VolumeKey.up)).called(2); + verify(() => functions.onChanged(VolumeKey.down)).called(4); + + volumeKeysNotifier.removeListener(() => functions.onChanged(volumeKeysNotifier.value)); + await volumeKeysNotifier.dispose(); + await volumeButtonsEvents.close(); + }, + ); +} diff --git a/test/screens/settings/utils/show_buy_pro_dialog_test.dart b/test/screens/settings/utils/show_buy_pro_dialog_test.dart new file mode 100644 index 0000000..16a8e19 --- /dev/null +++ b/test/screens/settings/utils/show_buy_pro_dialog_test.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/data/models/feature.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/remote_config_provider.dart'; +import 'package:lightmeter/screens/settings/utils/show_buy_pro_dialog.dart'; + +import '../../../application_mock.dart'; + +void main() { + Future pumpApplication(WidgetTester tester) async { + await tester.pumpWidget( + RemoteConfig( + config: const {Feature.unlockProFeaturesText: false}, + child: WidgetTestApplicationMock( + child: Builder( + builder: (context) => ElevatedButton( + onPressed: () => showBuyProDialog(context), + child: const SizedBox(), + ), + ), + ), + ), + ); + await tester.pumpAndSettle(); + } + + testWidgets( + '`showBuyProDialog` and buy', + (tester) async { + await pumpApplication(tester); + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text(S.current.lightmeterPro), findsOneWidget); + expect(find.text(S.current.cancel), findsOneWidget); + expect(find.text(S.current.buy), findsOneWidget); + + await tester.tap(find.text(S.current.buy)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsNothing); + }, + ); + + testWidgets( + '`showBuyProDialog` and cancel', + (tester) async { + await pumpApplication(tester); + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text(S.current.lightmeterPro), findsOneWidget); + expect(find.text(S.current.cancel), findsOneWidget); + expect(find.text(S.current.buy), findsOneWidget); + + await tester.tap(find.text(S.current.cancel)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsNothing); + }, + ); +} diff --git a/test/utils/selectable_provider_test.dart b/test/utils/selectable_provider_test.dart new file mode 100644 index 0000000..4ef2b96 --- /dev/null +++ b/test/utils/selectable_provider_test.dart @@ -0,0 +1,76 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/utils/selectable_provider.dart'; + +void main() { + group('SelectableInheritedModel.updateShouldNotifyDependent', () { + final model = SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 1, + child: const SizedBox(), + ); + + test( + '`{}`', + () { + expect( + model.updateShouldNotifyDependent( + SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 1, + child: const SizedBox(), + ), + {}, + ), + false, + ); + }, + ); + + test( + '`{SelectableAspect.list}`', + () { + expect( + model.updateShouldNotifyDependent( + SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 1, + child: const SizedBox(), + ), + {SelectableAspect.list}, + ), + true, + ); + }, + ); + + test( + '`{SelectableAspect.selected}`', + () { + expect( + model.updateShouldNotifyDependent( + SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 1, + child: const SizedBox(), + ), + {SelectableAspect.selected}, + ), + false, + ); + expect( + model.updateShouldNotifyDependent( + SelectableInheritedModel( + values: List.generate(25, (index) => index), + selected: 2, + child: const SizedBox(), + ), + {SelectableAspect.selected}, + ), + true, + ); + }, + ); + }); +} diff --git a/test/utils/to_string_signed_test.dart b/test/utils/to_string_signed_test.dart new file mode 100644 index 0000000..8611204 --- /dev/null +++ b/test/utils/to_string_signed_test.dart @@ -0,0 +1,16 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:lightmeter/utils/to_string_signed.dart'; + +void main() { + test('toStringSignedAsFixed(0)', () { + expect(1.5.toStringSignedAsFixed(0), '+2'); + expect((-1.5).toStringSignedAsFixed(0), '-2'); + expect(0.0.toStringSignedAsFixed(0), '0'); + }); + + test('toStringSignedAsFixed(1)', () { + expect(1.5.toStringSignedAsFixed(1), '+1.5'); + expect((-1.5).toStringSignedAsFixed(1), '-1.5'); + expect(0.0.toStringSignedAsFixed(1), '0.0'); + }); +}