migrated to new iap service

This commit is contained in:
Vadim 2025-07-17 23:02:07 +02:00
parent 91a1942191
commit c5ef878ddb
11 changed files with 51 additions and 63 deletions

View file

@ -7,9 +7,7 @@ import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:mocktail/mocktail.dart';
class _MockEquipmentProfilesStorageService extends Mock implements EquipmentProfilesStorageService {}
class _MockFilmsStorageService extends Mock implements FilmsStorageService {}
class _MockIapStorageService extends Mock implements IapStorageService {}
class MockIAPProviders extends StatefulWidget {
final TogglableMap<EquipmentProfile> equipmentProfiles;
@ -37,42 +35,38 @@ class MockIAPProviders extends StatefulWidget {
}
class _MockIAPProvidersState extends State<MockIAPProviders> {
late final _MockEquipmentProfilesStorageService mockEquipmentProfilesStorageService;
late final _MockFilmsStorageService mockFilmsStorageService;
late final _MockIapStorageService mockIapStorageService;
@override
void initState() {
super.initState();
registerFallbackValue(defaultEquipmentProfile);
mockEquipmentProfilesStorageService = _MockEquipmentProfilesStorageService();
when(() => mockEquipmentProfilesStorageService.init()).thenAnswer((_) async {});
when(() => mockEquipmentProfilesStorageService.getProfiles())
.thenAnswer((_) => Future.value(widget.equipmentProfiles));
when(() => mockEquipmentProfilesStorageService.selectedEquipmentProfileId)
.thenReturn(widget.selectedEquipmentProfileId);
when(() => mockEquipmentProfilesStorageService.addProfile(any<EquipmentProfile>())).thenAnswer((_) async {});
mockIapStorageService = _MockIapStorageService();
when(() => mockIapStorageService.init()).thenAnswer((_) async {});
when(() => mockIapStorageService.getEquipmentProfiles()).thenAnswer((_) => Future.value(widget.equipmentProfiles));
when(() => mockIapStorageService.selectedEquipmentProfileId).thenReturn(widget.selectedEquipmentProfileId);
when(() => mockIapStorageService.addEquipmentProfile(any<EquipmentProfile>())).thenAnswer((_) async {});
when(
() => mockEquipmentProfilesStorageService.updateProfile(
() => mockIapStorageService.updateEquipmentProfile(
id: any<String>(named: 'id'),
name: any<String>(named: 'name'),
isUsed: any<bool>(named: 'isUsed'),
),
).thenAnswer((_) async {});
when(() => mockEquipmentProfilesStorageService.deleteProfile(any<String>())).thenAnswer((_) async {});
when(() => mockIapStorageService.deleteEquipmentProfile(any<String>())).thenAnswer((_) async {});
mockFilmsStorageService = _MockFilmsStorageService();
when(() => mockFilmsStorageService.init()).thenAnswer((_) async {});
when(() => mockFilmsStorageService.getPredefinedFilms()).thenAnswer((_) => Future.value(widget.predefinedFilms));
when(() => mockFilmsStorageService.getCustomFilms()).thenAnswer((_) => Future.value(widget.customFilms));
when(() => mockFilmsStorageService.selectedFilmId).thenReturn(widget.selectedFilmId);
when(() => mockIapStorageService.getPredefinedFilms()).thenAnswer((_) => Future.value(widget.predefinedFilms));
when(() => mockIapStorageService.getCustomFilms()).thenAnswer((_) => Future.value(widget.customFilms));
when(() => mockIapStorageService.selectedFilmId).thenReturn(widget.selectedFilmId);
}
@override
Widget build(BuildContext context) {
return EquipmentProfilesProvider(
storageService: mockEquipmentProfilesStorageService,
storageService: mockIapStorageService,
child: FilmsProvider(
storageService: mockFilmsStorageService,
storageService: mockIapStorageService,
child: widget.child,
),
);

View file

@ -42,13 +42,9 @@ class _ApplicationWrapperState extends State<ApplicationWrapper> {
late final UserPreferencesService userPreferencesService;
late final bool hasLightSensor;
final equipmentProfilesStorageService = EquipmentProfilesStorageService();
final iapStorageService = IapStorageService();
final equipmentProfilesStorageServiceCompleter = Completer<void>();
final filmsStorageService = FilmsStorageService();
final filmsStorageServiceCompleter = Completer<void>();
final logbookPhotosStorageService = LogbookPhotosStorageService();
final logbookPhotosStorageServiceCompleter = Completer<void>();
late final Future<void> _initFuture;
@ -81,13 +77,13 @@ class _ApplicationWrapperState extends State<ApplicationWrapper> {
child: RemoteConfigProvider(
remoteConfigService: remoteConfigService,
child: EquipmentProfilesProvider(
storageService: equipmentProfilesStorageService,
storageService: iapStorageService,
onInitialized: equipmentProfilesStorageServiceCompleter.complete,
child: FilmsProvider(
storageService: filmsStorageService,
storageService: iapStorageService,
onInitialized: filmsStorageServiceCompleter.complete,
child: LogbookPhotosProvider(
storageService: logbookPhotosStorageService,
storageService: iapStorageService,
onInitialized: logbookPhotosStorageServiceCompleter.complete,
child: UserPreferencesProvider(
hasLightSensor: hasLightSensor,
@ -112,9 +108,7 @@ class _ApplicationWrapperState extends State<ApplicationWrapper> {
const LightSensorService(LocalPlatform()).hasSensor(),
const CameraInfoService(analytics).mainCameraEfl(),
remoteConfigService.activeAndFetchFeatures(),
equipmentProfilesStorageService.init(),
filmsStorageService.init(),
logbookPhotosStorageService.init(),
iapStorageService.init(),
]).then((value) {
userPreferencesService = UserPreferencesService((value[0] as SharedPreferences?)!)
..cameraFocalLength = value[2] as int?;

View file

@ -14,7 +14,7 @@ class EquipmentProfilesProvider extends StatefulWidget {
isoValues: IsoValue.values,
);
final EquipmentProfilesStorageService storageService;
final IapStorageService storageService;
final VoidCallback? onInitialized;
final Widget child;
@ -57,21 +57,21 @@ class EquipmentProfilesProviderState extends State<EquipmentProfilesProvider> {
Future<void> _init() async {
_selectedId = widget.storageService.selectedEquipmentProfileId;
_customProfiles.addAll(await widget.storageService.getProfiles());
_customProfiles.addAll(await widget.storageService.getEquipmentProfiles());
_discardSelectedIfNotIncluded();
if (mounted) setState(() {});
widget.onInitialized?.call();
}
Future<void> addProfile(EquipmentProfile profile) async {
await widget.storageService.addProfile(profile);
await widget.storageService.addEquipmentProfile(profile);
_customProfiles[profile.id] = (value: profile, isUsed: true);
setState(() {});
}
Future<void> updateProfile(EquipmentProfile profile) async {
final oldProfile = _customProfiles[profile.id]!.value;
await widget.storageService.updateProfile(
await widget.storageService.updateEquipmentProfile(
id: profile.id,
name: oldProfile.name != profile.name ? profile.name : null,
apertureValues: oldProfile.apertureValues != profile.apertureValues ? profile.apertureValues : null,
@ -86,7 +86,7 @@ class EquipmentProfilesProviderState extends State<EquipmentProfilesProvider> {
}
Future<void> deleteProfile(EquipmentProfile profile) async {
await widget.storageService.deleteProfile(profile.id);
await widget.storageService.deleteEquipmentProfile(profile.id);
if (profile.id == _selectedId) {
_selectedId = EquipmentProfilesProvider.defaultProfile.id;
widget.storageService.selectedEquipmentProfileId = EquipmentProfilesProvider.defaultProfile.id;
@ -111,7 +111,7 @@ class EquipmentProfilesProviderState extends State<EquipmentProfilesProvider> {
} else {
return;
}
await widget.storageService.updateProfile(id: profile.id, isUsed: enabled);
await widget.storageService.updateEquipmentProfile(id: profile.id, isUsed: enabled);
_discardSelectedIfNotIncluded();
setState(() {});
}

View file

@ -5,7 +5,7 @@ import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class FilmsProvider extends StatefulWidget {
final FilmsStorageService storageService;
final IapStorageService storageService;
final VoidCallback? onInitialized;
final Widget child;

View file

@ -9,7 +9,7 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:uuid/v8.dart';
class LogbookPhotosProvider extends StatefulWidget {
final LogbookPhotosStorageService storageService;
final IapStorageService storageService;
final VoidCallback? onInitialized;
final Widget child;

View file

@ -5,7 +5,7 @@ import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:mocktail/mocktail.dart';
class _MockEquipmentProfilesStorageService extends Mock implements EquipmentProfilesStorageService {}
class _MockEquipmentProfilesStorageService extends Mock implements IapStorageService {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@ -17,16 +17,16 @@ void main() {
setUp(() {
registerFallbackValue(_customProfiles.first);
when(() => storageService.addProfile(any<EquipmentProfile>())).thenAnswer((_) async {});
when(() => storageService.addEquipmentProfile(any<EquipmentProfile>())).thenAnswer((_) async {});
when(
() => storageService.updateProfile(
() => storageService.updateEquipmentProfile(
id: any<String>(named: 'id'),
name: any<String>(named: 'name'),
isUsed: any<bool>(named: 'isUsed'),
),
).thenAnswer((_) async {});
when(() => storageService.deleteProfile(any<String>())).thenAnswer((_) async {});
when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toTogglableMap()));
when(() => storageService.deleteEquipmentProfile(any<String>())).thenAnswer((_) async {});
when(() => storageService.getEquipmentProfiles()).thenAnswer((_) => Future.value(_customProfiles.toTogglableMap()));
});
tearDown(() {
@ -69,7 +69,7 @@ void main() {
() {
setUp(() {
when(() => storageService.selectedEquipmentProfileId).thenReturn(_customProfiles.first.id);
when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toTogglableMap()));
when(() => storageService.getEquipmentProfiles()).thenAnswer((_) => Future.value(_customProfiles.toTogglableMap()));
});
testWidgets(
@ -116,7 +116,7 @@ void main() {
expectEquipmentProfilesInUseCount(_customProfiles.length + 1 - 1);
expectSelectedEquipmentProfileName('');
verify(() => storageService.updateProfile(id: _customProfiles.first.id, isUsed: false)).called(1);
verify(() => storageService.updateEquipmentProfile(id: _customProfiles.first.id, isUsed: false)).called(1);
verify(() => storageService.selectedEquipmentProfileId = '').called(1);
},
);
@ -124,7 +124,7 @@ void main() {
testWidgets(
'EquipmentProfilesProvider CRUD',
(tester) async {
when(() => storageService.getProfiles()).thenAnswer((_) async => {});
when(() => storageService.getEquipmentProfiles()).thenAnswer((_) async => {});
when(() => storageService.selectedEquipmentProfileId).thenReturn('');
await pumpTestWidget(tester, IAPProductStatus.purchased);
@ -136,7 +136,7 @@ void main() {
await tester.pump();
expectEquipmentProfilesCount(2);
expectSelectedEquipmentProfileName('');
verify(() => storageService.addProfile(any<EquipmentProfile>())).called(1);
verify(() => storageService.addEquipmentProfile(any<EquipmentProfile>())).called(1);
/// Add the other profiles and select the 1st one
for (final profile in _customProfiles.skip(1)) {
@ -153,7 +153,7 @@ void main() {
await tester.pump();
expectEquipmentProfilesCount(1 + _customProfiles.length);
expectSelectedEquipmentProfileName(updatedName);
verify(() => storageService.updateProfile(id: _customProfiles.first.id, name: updatedName)).called(1);
verify(() => storageService.updateEquipmentProfile(id: _customProfiles.first.id, name: updatedName)).called(1);
/// Delete a non-selected profile
await tester.equipmentProfilesProvider.deleteProfile(_customProfiles.last);
@ -161,7 +161,7 @@ void main() {
expectEquipmentProfilesCount(1 + _customProfiles.length - 1);
expectSelectedEquipmentProfileName(updatedName);
verifyNever(() => storageService.selectedEquipmentProfileId = '');
verify(() => storageService.deleteProfile(_customProfiles.last.id)).called(1);
verify(() => storageService.deleteEquipmentProfile(_customProfiles.last.id)).called(1);
/// Delete the selected profile
await tester.equipmentProfilesProvider.deleteProfile(_customProfiles.first);
@ -169,7 +169,7 @@ void main() {
expectEquipmentProfilesCount(1 + _customProfiles.length - 2);
expectSelectedEquipmentProfileName('');
verify(() => storageService.selectedEquipmentProfileId = '').called(1);
verify(() => storageService.deleteProfile(_customProfiles.first.id)).called(1);
verify(() => storageService.deleteEquipmentProfile(_customProfiles.first.id)).called(1);
},
);
}

View file

@ -5,7 +5,7 @@ import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:mocktail/mocktail.dart';
class _MockFilmsStorageService extends Mock implements FilmsStorageService {}
class _MockFilmsStorageService extends Mock implements IapStorageService {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();

View file

@ -5,7 +5,7 @@ import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:mocktail/mocktail.dart';
class _MockLogbookPhotosStorageService extends Mock implements LogbookPhotosStorageService {}
class _MockLogbookPhotosStorageService extends Mock implements IapStorageService {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();

View file

@ -12,14 +12,14 @@ import 'package:mocktail/mocktail.dart';
import '../../../../../application_mock.dart';
import 'utils.dart';
class _MockEquipmentProfilesStorageService extends Mock implements EquipmentProfilesStorageService {}
class _MockEquipmentProfilesStorageService extends Mock implements IapStorageService {}
void main() {
late final _MockEquipmentProfilesStorageService storageService;
setUpAll(() {
storageService = _MockEquipmentProfilesStorageService();
when(() => storageService.getProfiles()).thenAnswer((_) async => _mockEquipmentProfiles.toTogglableMap());
when(() => storageService.getEquipmentProfiles()).thenAnswer((_) async => _mockEquipmentProfiles.toTogglableMap());
when(() => storageService.selectedEquipmentProfileId).thenReturn('');
});
@ -88,7 +88,7 @@ void main() {
testWidgets(
'Equipment profile picker shows only profiles in use',
(tester) async {
when(() => storageService.getProfiles())
when(() => storageService.getEquipmentProfiles())
.thenAnswer((_) async => _mockEquipmentProfiles.skip(1).toList().toTogglableMap());
await pumpApplication(tester);
await tester.openAnimatedPicker<EquipmentProfilePicker>();

View file

@ -10,7 +10,7 @@ import 'package:mocktail/mocktail.dart';
import '../../../../../application_mock.dart';
import 'utils.dart';
class _MockFilmsStorageService extends Mock implements FilmsStorageService {}
class _MockFilmsStorageService extends Mock implements IapStorageService {}
void main() {
late final _MockFilmsStorageService mockFilmsStorageService;

View file

@ -8,7 +8,7 @@ import 'package:mocktail/mocktail.dart';
import '../../../function_mock.dart';
class _MockEquipmentProfilesStorageService extends Mock implements EquipmentProfilesStorageService {}
class _MockEquipmentProfilesStorageService extends Mock implements IapStorageService {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@ -17,15 +17,15 @@ void main() {
setUp(() {
registerFallbackValue(_customProfiles.first);
when(() => storageService.addProfile(any<EquipmentProfile>())).thenAnswer((_) async {});
when(() => storageService.addEquipmentProfile(any<EquipmentProfile>())).thenAnswer((_) async {});
when(
() => storageService.updateProfile(
() => storageService.updateEquipmentProfile(
id: any<String>(named: 'id'),
name: any<String>(named: 'name'),
),
).thenAnswer((_) async {});
when(() => storageService.deleteProfile(any<String>())).thenAnswer((_) async {});
when(() => storageService.getProfiles()).thenAnswer((_) => Future.value(_customProfiles.toTogglableMap()));
when(() => storageService.deleteEquipmentProfile(any<String>())).thenAnswer((_) async {});
when(() => storageService.getEquipmentProfiles()).thenAnswer((_) => Future.value(_customProfiles.toTogglableMap()));
});
tearDown(() {