m3_lightmeter/lib/providers/films_provider.dart

175 lines
5.2 KiB
Dart
Raw Normal View History

import 'package:flutter/material.dart';
import 'package:lightmeter/utils/context_utils.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class FilmsProvider extends StatefulWidget {
2024-10-28 13:44:48 +00:00
final FilmsStorageService filmsStorageService;
2024-11-03 16:07:25 +00:00
final VoidCallback? onInitialized;
final Widget child;
const FilmsProvider({
2024-10-28 13:44:48 +00:00
required this.filmsStorageService,
2024-11-03 16:07:25 +00:00
this.onInitialized,
required this.child,
super.key,
});
static FilmsProviderState of(BuildContext context) {
return context.findAncestorStateOfType<FilmsProviderState>()!;
}
@override
State<FilmsProvider> createState() => FilmsProviderState();
}
class FilmsProviderState extends State<FilmsProvider> {
2024-10-28 13:44:48 +00:00
final Map<String, SelectableFilm<Film>> predefinedFilms = {};
final Map<String, SelectableFilm<FilmExponential>> customFilms = {};
2024-11-01 09:42:41 +00:00
String _selectedId = '';
2024-10-28 13:44:48 +00:00
Film get _selectedFilm => customFilms[_selectedId]?.film ?? predefinedFilms[_selectedId]?.film ?? const FilmStub();
2024-11-03 16:07:25 +00:00
@override
void initState() {
super.initState();
_init();
}
@override
Widget build(BuildContext context) {
return Films(
2024-10-29 09:20:55 +00:00
predefinedFilms: context.isPro ? predefinedFilms : {},
customFilms: context.isPro ? customFilms : {},
2024-10-28 13:44:48 +00:00
selected: context.isPro ? _selectedFilm : const FilmStub(),
child: widget.child,
);
}
2024-11-03 16:07:25 +00:00
Future<void> _init() async {
2024-11-01 09:42:41 +00:00
_selectedId = widget.filmsStorageService.selectedFilmId;
predefinedFilms.addAll(await widget.filmsStorageService.getPredefinedFilms());
customFilms.addAll(await widget.filmsStorageService.getCustomFilms());
_discardSelectedIfNotIncluded();
if (mounted) setState(() {});
2024-11-03 16:07:25 +00:00
widget.onInitialized?.call();
2024-11-01 09:42:41 +00:00
}
2024-10-25 11:01:37 +00:00
/* Both type of films **/
2024-10-28 13:44:48 +00:00
Future<void> 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 {
2024-10-25 11:01:37 +00:00
return;
}
2024-10-28 13:44:48 +00:00
await widget.filmsStorageService.toggleFilm(film, enabled);
_discardSelectedIfNotIncluded();
setState(() {});
2024-10-25 11:01:37 +00:00
}
void selectFilm(Film film) {
2024-10-28 13:44:48 +00:00
if (_selectedFilm != film) {
_selectedId = film.id;
2024-10-29 09:20:55 +00:00
widget.filmsStorageService.selectedFilmId = _selectedId;
setState(() {});
}
}
2024-10-25 11:01:37 +00:00
/* Custom films **/
2024-10-28 13:44:48 +00:00
Future<void> addCustomFilm(FilmExponential film) async {
2024-10-31 16:17:31 +00:00
// ignore: avoid_redundant_argument_values
await widget.filmsStorageService.addFilm(film, isUsed: true);
customFilms[film.id] = (film: film, isUsed: true);
2024-10-25 11:01:37 +00:00
setState(() {});
}
2024-10-28 13:44:48 +00:00
Future<void> updateCustomFilm(FilmExponential film) async {
await widget.filmsStorageService.updateFilm(film);
customFilms[film.id] = (film: film, isUsed: customFilms[film.id]!.isUsed);
2024-10-25 11:01:37 +00:00
setState(() {});
}
2024-10-28 13:44:48 +00:00
Future<void> deleteCustomFilm(FilmExponential film) async {
await widget.filmsStorageService.deleteFilm(film);
2024-10-25 11:01:37 +00:00
customFilms.remove(film.id);
_discardSelectedIfNotIncluded();
setState(() {});
}
void _discardSelectedIfNotIncluded() {
2024-10-28 13:44:48 +00:00
if (_selectedId == const FilmStub().id) {
return;
}
final isSelectedUsed = predefinedFilms[_selectedId]?.isUsed ?? customFilms[_selectedId]?.isUsed ?? false;
if (!isSelectedUsed) {
_selectedId = const FilmStub().id;
2024-10-29 09:20:55 +00:00
widget.filmsStorageService.selectedFilmId = _selectedId;
}
}
}
2024-10-25 11:01:37 +00:00
enum _FilmsModelAspect {
customFilmsList,
predefinedFilmsList,
filmsInUse,
selected,
}
class Films extends InheritedModel<_FilmsModelAspect> {
2024-10-28 13:44:48 +00:00
final Map<String, SelectableFilm<Film>> predefinedFilms;
2024-10-25 11:01:37 +00:00
@protected
2024-10-28 13:44:48 +00:00
final Map<String, SelectableFilm<FilmExponential>> customFilms;
2024-10-25 11:01:37 +00:00
final Film selected;
const Films({
2024-10-25 11:01:37 +00:00
required this.predefinedFilms,
required this.customFilms,
required this.selected,
required super.child,
});
2024-10-25 11:01:37 +00:00
static List<Film> predefinedFilmsOf<T>(BuildContext context) {
return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.predefinedFilmsList)!
.predefinedFilms
.values
.map((value) => value.film)
.toList();
}
static List<FilmExponential> customFilmsOf<T>(BuildContext context) {
return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.customFilmsList)!
.customFilms
.values
.map((value) => value.film)
.toList();
}
2024-10-06 18:26:40 +00:00
/// [FilmStub()] + films in use selected by user
static List<Film> inUseOf<T>(BuildContext context) {
2024-10-25 11:01:37 +00:00
final model = InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.filmsInUse)!;
return [
const FilmStub(),
2024-10-28 13:44:48 +00:00
...model.customFilms.values.where((e) => e.isUsed).map((e) => e.film),
...model.predefinedFilms.values.where((e) => e.isUsed).map((e) => e.film),
2024-10-25 11:01:37 +00:00
];
}
static Film selectedOf(BuildContext context) {
2024-10-25 11:01:37 +00:00
return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.selected)!.selected;
}
@override
bool updateShouldNotify(Films _) => true;
@override
bool updateShouldNotifyDependent(Films oldWidget, Set<_FilmsModelAspect> dependencies) {
// TODO: reduce unnecessary notifications
return true;
}
}