added FilmsStorageService

This commit is contained in:
Vadim 2024-10-28 14:44:48 +01:00
parent 45d7728c85
commit 09d04c665f
3 changed files with 57 additions and 51 deletions

View file

@ -29,11 +29,13 @@ class ApplicationWrapper extends StatelessWidget {
final remoteConfigService = env.buildType != BuildType.dev final remoteConfigService = env.buildType != BuildType.dev
? const RemoteConfigService(LightmeterAnalytics(api: LightmeterAnalyticsFirebase())) ? const RemoteConfigService(LightmeterAnalytics(api: LightmeterAnalyticsFirebase()))
: const MockRemoteConfigService(); : const MockRemoteConfigService();
final filmsStorageService = FilmsStorageService();
return FutureBuilder( return FutureBuilder(
future: Future.wait<dynamic>([ future: Future.wait<dynamic>([
SharedPreferences.getInstance(), SharedPreferences.getInstance(),
const LightSensorService(LocalPlatform()).hasSensor(), const LightSensorService(LocalPlatform()).hasSensor(),
remoteConfigService.activeAndFetchFeatures(), remoteConfigService.activeAndFetchFeatures(),
filmsStorageService.init(),
]), ]),
builder: (_, snapshot) { builder: (_, snapshot) {
if (snapshot.data != null) { if (snapshot.data != null) {
@ -49,11 +51,13 @@ class ApplicationWrapper extends StatelessWidget {
permissionsService: const PermissionsService(), permissionsService: const PermissionsService(),
userPreferencesService: userPreferencesService, userPreferencesService: userPreferencesService,
volumeEventsService: const VolumeEventsService(LocalPlatform()), volumeEventsService: const VolumeEventsService(LocalPlatform()),
filmsStorageService: filmsStorageService,
child: RemoteConfigProvider( child: RemoteConfigProvider(
remoteConfigService: remoteConfigService, remoteConfigService: remoteConfigService,
child: EquipmentProfileProvider( child: EquipmentProfileProvider(
storageService: iapService, storageService: iapService,
child: FilmsProvider( child: FilmsProvider(
filmsStorageService: filmsStorageService,
storageService: iapService, storageService: iapService,
child: UserPreferencesProvider( child: UserPreferencesProvider(
hasLightSensor: hasLightSensor, hasLightSensor: hasLightSensor,

View file

@ -4,13 +4,13 @@ import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class FilmsProvider extends StatefulWidget { class FilmsProvider extends StatefulWidget {
final FilmsStorageService filmsStorageService;
final IAPStorageService storageService; final IAPStorageService storageService;
final List<Film>? availableFilms;
final Widget child; final Widget child;
const FilmsProvider({ const FilmsProvider({
required this.filmsStorageService,
required this.storageService, required this.storageService,
this.availableFilms,
required this.child, required this.child,
super.key, super.key,
}); });
@ -24,25 +24,16 @@ class FilmsProvider extends StatefulWidget {
} }
class FilmsProviderState extends State<FilmsProvider> { class FilmsProviderState extends State<FilmsProvider> {
late final Map<String, _SelectableFilm<Film>> predefinedFilms = Map.fromEntries( final Map<String, SelectableFilm<Film>> predefinedFilms = {};
(widget.availableFilms ?? films).map( final Map<String, SelectableFilm<FilmExponential>> customFilms = {};
(film) => MapEntry( late String _selectedId;
film.id,
( Film get _selectedFilm => customFilms[_selectedId]?.film ?? predefinedFilms[_selectedId]?.film ?? const FilmStub();
film: film,
selected: widget.storageService.filmsInUse.contains(film),
),
),
),
);
final Map<String, _SelectableFilm<FilmExponential>> customFilms = {};
late Film _selected;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_selected = widget.storageService.selectedFilm; _init();
_discardSelectedIfNotIncluded();
} }
@override @override
@ -50,68 +41,74 @@ class FilmsProviderState extends State<FilmsProvider> {
return Films( return Films(
predefinedFilms: predefinedFilms, predefinedFilms: predefinedFilms,
customFilms: customFilms, customFilms: customFilms,
selected: context.isPro ? _selected : const FilmStub(), selected: context.isPro ? _selectedFilm : const FilmStub(),
child: widget.child, child: widget.child,
); );
} }
/* Both type of films **/ /* Both type of films **/
void toggleFilm(Film film, bool enabled) { Future<void> toggleFilm(Film film, bool enabled) async {
Film? targetFilm = predefinedFilms[film.id]?.film; if (predefinedFilms.containsKey(film.id)) {
if (targetFilm != null) { predefinedFilms[film.id] = (film: film, isUsed: enabled);
predefinedFilms[film.id] = (film: film, selected: enabled); } else if (customFilms.containsKey(film.id)) {
_discardSelectedIfNotIncluded(); customFilms[film.id] = (film: film as FilmExponential, isUsed: enabled);
setState(() {}); } else {
return; return;
} }
await widget.filmsStorageService.toggleFilm(film, enabled);
targetFilm = customFilms[film.id]?.film;
if (targetFilm != null) {
customFilms[film.id] = (film: film as FilmExponential, selected: enabled);
_discardSelectedIfNotIncluded(); _discardSelectedIfNotIncluded();
setState(() {}); setState(() {});
return;
}
} }
void selectFilm(Film film) { void selectFilm(Film film) {
if (_selected != film) { if (_selectedFilm != film) {
_selected = film; _selectedId = film.id;
widget.storageService.selectedFilm = film; widget.storageService.selectedFilmId = _selectedId;
setState(() {}); setState(() {});
} }
} }
/* Custom films **/ /* Custom films **/
void addCustomFilm(FilmExponential film) { Future<void> addCustomFilm(FilmExponential film) async {
customFilms[film.id] = (film: film, selected: false); await widget.filmsStorageService.addFilm(film);
customFilms[film.id] = (film: film, isUsed: false);
setState(() {}); setState(() {});
} }
void updateCustomFilm(FilmExponential film) { Future<void> updateCustomFilm(FilmExponential film) async {
customFilms[film.id] = (film: film, selected: customFilms[film.id]!.selected); await widget.filmsStorageService.updateFilm(film);
customFilms[film.id] = (film: film, isUsed: customFilms[film.id]!.isUsed);
setState(() {}); setState(() {});
} }
void deleteCustomFilm(FilmExponential film) { Future<void> deleteCustomFilm(FilmExponential film) async {
await widget.filmsStorageService.deleteFilm(film);
customFilms.remove(film.id); customFilms.remove(film.id);
_discardSelectedIfNotIncluded(); _discardSelectedIfNotIncluded();
setState(() {}); setState(() {});
} }
void _discardSelectedIfNotIncluded() { Future<void> _init() async {
if (_selected != const FilmStub() && _selectedId = widget.storageService.selectedFilmId;
!predefinedFilms.values.any((e) => e.film == _selected) && predefinedFilms.addAll(await widget.filmsStorageService.getPredefinedFilms());
!customFilms.values.any((e) => e.film == _selected)) { customFilms.addAll(await widget.filmsStorageService.getCustomFilms());
_selected = const FilmStub(); _discardSelectedIfNotIncluded();
widget.storageService.selectedFilm = const FilmStub(); if (mounted) setState(() {});
}
}
} }
typedef _SelectableFilm<T extends Film> = ({T film, bool selected}); void _discardSelectedIfNotIncluded() {
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;
}
}
}
enum _FilmsModelAspect { enum _FilmsModelAspect {
customFilmsList, customFilmsList,
@ -121,10 +118,10 @@ enum _FilmsModelAspect {
} }
class Films extends InheritedModel<_FilmsModelAspect> { class Films extends InheritedModel<_FilmsModelAspect> {
final Map<String, _SelectableFilm<Film>> predefinedFilms; final Map<String, SelectableFilm<Film>> predefinedFilms;
@protected @protected
final Map<String, _SelectableFilm<FilmExponential>> customFilms; final Map<String, SelectableFilm<FilmExponential>> customFilms;
final Film selected; final Film selected;
const Films({ const Films({
@ -155,8 +152,8 @@ class Films extends InheritedModel<_FilmsModelAspect> {
final model = InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.filmsInUse)!; final model = InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.filmsInUse)!;
return [ return [
const FilmStub(), const FilmStub(),
...model.customFilms.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.selected).map((e) => e.film), ...model.predefinedFilms.values.where((e) => e.isUsed).map((e) => e.film),
]; ];
} }

View file

@ -7,6 +7,7 @@ import 'package:lightmeter/data/permissions_service.dart';
import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/data/shared_prefs_service.dart';
import 'package:lightmeter/data/volume_events_service.dart'; import 'package:lightmeter/data/volume_events_service.dart';
import 'package:lightmeter/environment.dart'; import 'package:lightmeter/environment.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
// coverage:ignore-start // coverage:ignore-start
class ServicesProvider extends InheritedWidget { class ServicesProvider extends InheritedWidget {
@ -19,6 +20,9 @@ class ServicesProvider extends InheritedWidget {
final UserPreferencesService userPreferencesService; final UserPreferencesService userPreferencesService;
final VolumeEventsService volumeEventsService; final VolumeEventsService volumeEventsService;
// IAP
final FilmsStorageService filmsStorageService;
const ServicesProvider({ const ServicesProvider({
required this.analytics, required this.analytics,
required this.caffeineService, required this.caffeineService,
@ -28,6 +32,7 @@ class ServicesProvider extends InheritedWidget {
required this.permissionsService, required this.permissionsService,
required this.userPreferencesService, required this.userPreferencesService,
required this.volumeEventsService, required this.volumeEventsService,
required this.filmsStorageService,
required super.child, required super.child,
}); });