diff --git a/lib/application_wrapper.dart b/lib/application_wrapper.dart index 9f824d4..2a523e5 100644 --- a/lib/application_wrapper.dart +++ b/lib/application_wrapper.dart @@ -29,11 +29,13 @@ class ApplicationWrapper extends StatelessWidget { final remoteConfigService = env.buildType != BuildType.dev ? const RemoteConfigService(LightmeterAnalytics(api: LightmeterAnalyticsFirebase())) : const MockRemoteConfigService(); + final filmsStorageService = FilmsStorageService(); return FutureBuilder( future: Future.wait([ SharedPreferences.getInstance(), const LightSensorService(LocalPlatform()).hasSensor(), remoteConfigService.activeAndFetchFeatures(), + filmsStorageService.init(), ]), builder: (_, snapshot) { if (snapshot.data != null) { @@ -49,11 +51,13 @@ class ApplicationWrapper extends StatelessWidget { permissionsService: const PermissionsService(), userPreferencesService: userPreferencesService, volumeEventsService: const VolumeEventsService(LocalPlatform()), + filmsStorageService: filmsStorageService, child: RemoteConfigProvider( remoteConfigService: remoteConfigService, child: EquipmentProfileProvider( storageService: iapService, child: FilmsProvider( + filmsStorageService: filmsStorageService, storageService: iapService, child: UserPreferencesProvider( hasLightSensor: hasLightSensor, diff --git a/lib/providers/films_provider.dart b/lib/providers/films_provider.dart index b4d6e8b..004b224 100644 --- a/lib/providers/films_provider.dart +++ b/lib/providers/films_provider.dart @@ -4,13 +4,13 @@ import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class FilmsProvider extends StatefulWidget { + final FilmsStorageService filmsStorageService; final IAPStorageService storageService; - final List? availableFilms; final Widget child; const FilmsProvider({ + required this.filmsStorageService, required this.storageService, - this.availableFilms, required this.child, super.key, }); @@ -24,25 +24,16 @@ class FilmsProvider extends StatefulWidget { } class FilmsProviderState extends State { - late final Map> predefinedFilms = Map.fromEntries( - (widget.availableFilms ?? films).map( - (film) => MapEntry( - film.id, - ( - film: film, - selected: widget.storageService.filmsInUse.contains(film), - ), - ), - ), - ); - final Map> customFilms = {}; - late Film _selected; + final Map> predefinedFilms = {}; + final Map> customFilms = {}; + late String _selectedId; + + Film get _selectedFilm => customFilms[_selectedId]?.film ?? predefinedFilms[_selectedId]?.film ?? const FilmStub(); @override void initState() { super.initState(); - _selected = widget.storageService.selectedFilm; - _discardSelectedIfNotIncluded(); + _init(); } @override @@ -50,69 +41,75 @@ class FilmsProviderState extends State { return Films( predefinedFilms: predefinedFilms, customFilms: customFilms, - selected: context.isPro ? _selected : const FilmStub(), + selected: context.isPro ? _selectedFilm : const FilmStub(), child: widget.child, ); } /* Both type of films **/ - void toggleFilm(Film film, bool enabled) { - Film? targetFilm = predefinedFilms[film.id]?.film; - if (targetFilm != null) { - predefinedFilms[film.id] = (film: film, selected: enabled); - _discardSelectedIfNotIncluded(); - setState(() {}); - return; - } - - targetFilm = customFilms[film.id]?.film; - if (targetFilm != null) { - customFilms[film.id] = (film: film as FilmExponential, selected: enabled); - _discardSelectedIfNotIncluded(); - setState(() {}); + Future toggleFilm(Film film, bool enabled) async { + if (predefinedFilms.containsKey(film.id)) { + predefinedFilms[film.id] = (film: film, isUsed: enabled); + } else if (customFilms.containsKey(film.id)) { + customFilms[film.id] = (film: film as FilmExponential, isUsed: enabled); + } else { return; } + await widget.filmsStorageService.toggleFilm(film, enabled); + _discardSelectedIfNotIncluded(); + setState(() {}); } void selectFilm(Film film) { - if (_selected != film) { - _selected = film; - widget.storageService.selectedFilm = film; + if (_selectedFilm != film) { + _selectedId = film.id; + widget.storageService.selectedFilmId = _selectedId; setState(() {}); } } /* Custom films **/ - void addCustomFilm(FilmExponential film) { - customFilms[film.id] = (film: film, selected: false); + Future addCustomFilm(FilmExponential film) async { + await widget.filmsStorageService.addFilm(film); + customFilms[film.id] = (film: film, isUsed: false); setState(() {}); } - void updateCustomFilm(FilmExponential film) { - customFilms[film.id] = (film: film, selected: customFilms[film.id]!.selected); + Future updateCustomFilm(FilmExponential film) async { + await widget.filmsStorageService.updateFilm(film); + customFilms[film.id] = (film: film, isUsed: customFilms[film.id]!.isUsed); setState(() {}); } - void deleteCustomFilm(FilmExponential film) { + Future deleteCustomFilm(FilmExponential film) async { + await widget.filmsStorageService.deleteFilm(film); customFilms.remove(film.id); _discardSelectedIfNotIncluded(); setState(() {}); } + Future _init() async { + _selectedId = widget.storageService.selectedFilmId; + predefinedFilms.addAll(await widget.filmsStorageService.getPredefinedFilms()); + customFilms.addAll(await widget.filmsStorageService.getCustomFilms()); + _discardSelectedIfNotIncluded(); + if (mounted) setState(() {}); + } + void _discardSelectedIfNotIncluded() { - if (_selected != const FilmStub() && - !predefinedFilms.values.any((e) => e.film == _selected) && - !customFilms.values.any((e) => e.film == _selected)) { - _selected = const FilmStub(); - widget.storageService.selectedFilm = const FilmStub(); + if (_selectedId == const FilmStub().id) { + return; + } + final isSelectedUsed = predefinedFilms[_selectedId]?.isUsed ?? customFilms[_selectedId]?.isUsed ?? false; + if (!isSelectedUsed) { + _selectedId = const FilmStub().id; + widget.storageService.selectedFilmId = _selectedId; } } } -typedef _SelectableFilm = ({T film, bool selected}); - enum _FilmsModelAspect { customFilmsList, predefinedFilmsList, @@ -121,10 +118,10 @@ enum _FilmsModelAspect { } class Films extends InheritedModel<_FilmsModelAspect> { - final Map> predefinedFilms; + final Map> predefinedFilms; @protected - final Map> customFilms; + final Map> customFilms; final Film selected; const Films({ @@ -155,8 +152,8 @@ class Films extends InheritedModel<_FilmsModelAspect> { final model = InheritedModel.inheritFrom(context, aspect: _FilmsModelAspect.filmsInUse)!; return [ const FilmStub(), - ...model.customFilms.values.where((e) => e.selected).map((e) => e.film), - ...model.predefinedFilms.values.where((e) => e.selected).map((e) => e.film), + ...model.customFilms.values.where((e) => e.isUsed).map((e) => e.film), + ...model.predefinedFilms.values.where((e) => e.isUsed).map((e) => e.film), ]; } diff --git a/lib/providers/services_provider.dart b/lib/providers/services_provider.dart index 1db019e..c388b6d 100644 --- a/lib/providers/services_provider.dart +++ b/lib/providers/services_provider.dart @@ -7,6 +7,7 @@ import 'package:lightmeter/data/permissions_service.dart'; import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/data/volume_events_service.dart'; import 'package:lightmeter/environment.dart'; +import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; // coverage:ignore-start class ServicesProvider extends InheritedWidget { @@ -19,6 +20,9 @@ class ServicesProvider extends InheritedWidget { final UserPreferencesService userPreferencesService; final VolumeEventsService volumeEventsService; + // IAP + final FilmsStorageService filmsStorageService; + const ServicesProvider({ required this.analytics, required this.caffeineService, @@ -28,6 +32,7 @@ class ServicesProvider extends InheritedWidget { required this.permissionsService, required this.userPreferencesService, required this.volumeEventsService, + required this.filmsStorageService, required super.child, });