Compare commits

...

6 commits

Author SHA1 Message Date
Vadim
2accf9f2b3 covered films model updateShouldNotifyDependent 2024-11-03 18:05:17 +01:00
Vadim
d1b96399bb fixed select film discard notify 2024-11-03 17:56:25 +01:00
Vadim
ae2216ae3a typo 2024-11-03 17:52:53 +01:00
Vadim
e7512e47c2 added conditions to films model updateShouldNotifyDependent 2024-11-03 17:43:18 +01:00
Vadim
e29920b757 fixed films initialization 2024-11-03 17:07:25 +01:00
Vadim
f22086e578 migrated to iap 1.1.1 2024-11-03 16:54:09 +01:00
4 changed files with 109 additions and 47 deletions

View file

@ -39,7 +39,6 @@ class _ApplicationWrapperState extends State<ApplicationWrapper> {
late final bool hasLightSensor; late final bool hasLightSensor;
final filmsStorageService = FilmsStorageService(); final filmsStorageService = FilmsStorageService();
final filmsProviderKey = GlobalKey<FilmsProviderState>();
late final Future<void> _initFuture; late final Future<void> _initFuture;
@ -51,28 +50,28 @@ class _ApplicationWrapperState extends State<ApplicationWrapper> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FilmsProvider( return FutureBuilder(
key: filmsProviderKey, future: _initFuture,
filmsStorageService: filmsStorageService, builder: (context, snapshot) {
child: FutureBuilder( if (snapshot.error != null) {
future: _initFuture, return Center(child: Text(snapshot.error!.toString()));
builder: (context, snapshot) { } else if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.error != null) { return ServicesProvider(
return Center(child: Text(snapshot.error!.toString())); analytics: const LightmeterAnalytics(api: LightmeterAnalyticsFirebase()),
} else if (snapshot.connectionState == ConnectionState.done) { caffeineService: const CaffeineService(),
return ServicesProvider( environment: widget.env.copyWith(hasLightSensor: hasLightSensor),
analytics: const LightmeterAnalytics(api: LightmeterAnalyticsFirebase()), hapticsService: const HapticsService(),
caffeineService: const CaffeineService(), lightSensorService: const LightSensorService(LocalPlatform()),
environment: widget.env.copyWith(hasLightSensor: hasLightSensor), permissionsService: const PermissionsService(),
hapticsService: const HapticsService(), userPreferencesService: userPreferencesService,
lightSensorService: const LightSensorService(LocalPlatform()), volumeEventsService: const VolumeEventsService(LocalPlatform()),
permissionsService: const PermissionsService(), child: RemoteConfigProvider(
userPreferencesService: userPreferencesService, remoteConfigService: remoteConfigService,
volumeEventsService: const VolumeEventsService(LocalPlatform()), child: EquipmentProfileProvider(
child: RemoteConfigProvider( storageService: iapStorageService,
remoteConfigService: remoteConfigService, child: FilmsProvider(
child: EquipmentProfileProvider( filmsStorageService: filmsStorageService,
storageService: iapStorageService, onInitialized: _onFilmsProviderInitialized,
child: UserPreferencesProvider( child: UserPreferencesProvider(
hasLightSensor: hasLightSensor, hasLightSensor: hasLightSensor,
userPreferencesService: userPreferencesService, userPreferencesService: userPreferencesService,
@ -80,12 +79,12 @@ class _ApplicationWrapperState extends State<ApplicationWrapper> {
), ),
), ),
), ),
); ),
} );
}
return const SizedBox(); return const SizedBox();
}, },
),
); );
} }
@ -94,13 +93,16 @@ class _ApplicationWrapperState extends State<ApplicationWrapper> {
SharedPreferences.getInstance(), SharedPreferences.getInstance(),
const LightSensorService(LocalPlatform()).hasSensor(), const LightSensorService(LocalPlatform()).hasSensor(),
remoteConfigService.activeAndFetchFeatures(), remoteConfigService.activeAndFetchFeatures(),
filmsStorageService.init().then((_) => filmsProviderKey.currentState?.init()), filmsStorageService.init(),
]).then((value) { ]).then((value) {
final sharedPrefs = (value[0] as SharedPreferences?)!; final sharedPrefs = (value[0] as SharedPreferences?)!;
iapStorageService = IAPStorageService(sharedPrefs); iapStorageService = IAPStorageService(sharedPrefs);
userPreferencesService = UserPreferencesService(sharedPrefs); userPreferencesService = UserPreferencesService(sharedPrefs);
hasLightSensor = value[1] as bool? ?? false; hasLightSensor = value[1] as bool? ?? false;
FlutterNativeSplash.remove();
}); });
} }
void _onFilmsProviderInitialized() {
FlutterNativeSplash.remove();
}
} }

View file

@ -1,3 +1,4 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:lightmeter/utils/context_utils.dart'; import 'package:lightmeter/utils/context_utils.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
@ -5,10 +6,12 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class FilmsProvider extends StatefulWidget { class FilmsProvider extends StatefulWidget {
final FilmsStorageService filmsStorageService; final FilmsStorageService filmsStorageService;
final VoidCallback? onInitialized;
final Widget child; final Widget child;
const FilmsProvider({ const FilmsProvider({
required this.filmsStorageService, required this.filmsStorageService,
this.onInitialized,
required this.child, required this.child,
super.key, super.key,
}); });
@ -28,6 +31,12 @@ class FilmsProviderState extends State<FilmsProvider> {
Film get _selectedFilm => customFilms[_selectedId]?.film ?? predefinedFilms[_selectedId]?.film ?? const FilmStub(); Film get _selectedFilm => customFilms[_selectedId]?.film ?? predefinedFilms[_selectedId]?.film ?? const FilmStub();
@override
void initState() {
super.initState();
_init();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Films( return Films(
@ -38,12 +47,13 @@ class FilmsProviderState extends State<FilmsProvider> {
); );
} }
Future<void> init() async { Future<void> _init() async {
_selectedId = widget.filmsStorageService.selectedFilmId; _selectedId = widget.filmsStorageService.selectedFilmId;
predefinedFilms.addAll(await widget.filmsStorageService.getPredefinedFilms()); predefinedFilms.addAll(await widget.filmsStorageService.getPredefinedFilms());
customFilms.addAll(await widget.filmsStorageService.getCustomFilms()); customFilms.addAll(await widget.filmsStorageService.getCustomFilms());
_discardSelectedIfNotIncluded(); _discardSelectedIfNotIncluded();
if (mounted) setState(() {}); if (mounted) setState(() {});
widget.onInitialized?.call();
} }
/* Both type of films **/ /* Both type of films **/
@ -104,8 +114,8 @@ class FilmsProviderState extends State<FilmsProvider> {
} }
enum _FilmsModelAspect { enum _FilmsModelAspect {
customFilmsList, customFilms,
predefinedFilmsList, predefinedFilms,
filmsInUse, filmsInUse,
selected, selected,
} }
@ -125,7 +135,7 @@ class Films extends InheritedModel<_FilmsModelAspect> {
}); });
static List<Film> predefinedFilmsOf<T>(BuildContext context) { static List<Film> predefinedFilmsOf<T>(BuildContext context) {
return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.predefinedFilmsList)! return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.predefinedFilms)!
.predefinedFilms .predefinedFilms
.values .values
.map((value) => value.film) .map((value) => value.film)
@ -133,7 +143,7 @@ class Films extends InheritedModel<_FilmsModelAspect> {
} }
static List<FilmExponential> customFilmsOf<T>(BuildContext context) { static List<FilmExponential> customFilmsOf<T>(BuildContext context) {
return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.customFilmsList)! return InheritedModel.inheritFrom<Films>(context, aspect: _FilmsModelAspect.customFilms)!
.customFilms .customFilms
.values .values
.map((value) => value.film) .map((value) => value.film)
@ -159,7 +169,12 @@ class Films extends InheritedModel<_FilmsModelAspect> {
@override @override
bool updateShouldNotifyDependent(Films oldWidget, Set<_FilmsModelAspect> dependencies) { bool updateShouldNotifyDependent(Films oldWidget, Set<_FilmsModelAspect> dependencies) {
// TODO: reduce unnecessary notifications return (dependencies.contains(_FilmsModelAspect.selected) && oldWidget.selected != selected) ||
return true; ((dependencies.contains(_FilmsModelAspect.predefinedFilms) ||
dependencies.contains(_FilmsModelAspect.filmsInUse)) &&
const DeepCollectionEquality().equals(oldWidget.predefinedFilms, predefinedFilms)) ||
((dependencies.contains(_FilmsModelAspect.customFilms) ||
dependencies.contains(_FilmsModelAspect.filmsInUse)) &&
const DeepCollectionEquality().equals(oldWidget.customFilms, customFilms));
} }
} }

View file

@ -13,6 +13,7 @@ dependencies:
camera: 0.10.5+2 camera: 0.10.5+2
camera_android_camerax: 0.6.1+1 camera_android_camerax: 0.6.1+1
clipboard: 0.1.3 clipboard: 0.1.3
collection: any
dynamic_color: 1.7.0 dynamic_color: 1.7.0
exif: 3.1.4 exif: 3.1.4
firebase_analytics: 10.6.2 firebase_analytics: 10.6.2
@ -31,7 +32,7 @@ dependencies:
m3_lightmeter_iap: m3_lightmeter_iap:
git: git:
url: "https://github.com/vodemn/m3_lightmeter_iap" url: "https://github.com/vodemn/m3_lightmeter_iap"
ref: v1.1.0 ref: v1.1.1
m3_lightmeter_resources: m3_lightmeter_resources:
git: git:
url: "https://github.com/vodemn/m3_lightmeter_resources" url: "https://github.com/vodemn/m3_lightmeter_resources"

View file

@ -50,19 +50,19 @@ void main() {
} }
void expectPredefinedFilmsCount(int count) { void expectPredefinedFilmsCount(int count) {
expect(find.text('Predefined films count: $count'), findsOneWidget); expect(find.text(_PredefinedFilmsCount.text(count)), findsOneWidget);
} }
void expectCustomFilmsCount(int count) { void expectCustomFilmsCount(int count) {
expect(find.text('Custom films count: $count'), findsOneWidget); expect(find.text(_CustomFilmsCount.text(count)), findsOneWidget);
} }
void expectFilmsInUseCount(int count) { void expectFilmsInUseCount(int count) {
expect(find.text('Films in use count: $count'), findsOneWidget); expect(find.text(_FilmsInUseCount.text(count)), findsOneWidget);
} }
void expectSelectedFilmName(String name) { void expectSelectedFilmName(String name) {
expect(find.text('Selected film: $name'), findsOneWidget); expect(find.text(_SelectedFilm.text(name)), findsOneWidget);
} }
group( group(
@ -234,15 +234,15 @@ class _Application extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return const MaterialApp(
home: Scaffold( home: Scaffold(
body: Center( body: Center(
child: Column( child: Column(
children: [ children: [
Text("Predefined films count: ${Films.predefinedFilmsOf(context).length}"), _PredefinedFilmsCount(),
Text("Custom films count: ${Films.customFilmsOf(context).length}"), _CustomFilmsCount(),
Text("Films in use count: ${Films.inUseOf(context).length}"), _FilmsInUseCount(),
Text("Selected film: ${Films.selectedOf(context).name}"), _SelectedFilm(),
], ],
), ),
), ),
@ -251,6 +251,50 @@ class _Application extends StatelessWidget {
} }
} }
class _PredefinedFilmsCount extends StatelessWidget {
static String text(int count) => "Predefined films count: $count";
const _PredefinedFilmsCount();
@override
Widget build(BuildContext context) {
return Text(text(Films.predefinedFilmsOf(context).length));
}
}
class _CustomFilmsCount extends StatelessWidget {
static String text(int count) => "Custom films count: $count";
const _CustomFilmsCount();
@override
Widget build(BuildContext context) {
return Text(text(Films.customFilmsOf(context).length));
}
}
class _FilmsInUseCount extends StatelessWidget {
static String text(int count) => "Films in use count: $count";
const _FilmsInUseCount();
@override
Widget build(BuildContext context) {
return Text(text(Films.inUseOf(context).length));
}
}
class _SelectedFilm extends StatelessWidget {
static String text(String name) => "Selected film: $name}";
const _SelectedFilm();
@override
Widget build(BuildContext context) {
return Text(text(Films.selectedOf(context).name));
}
}
const mockPredefinedFilms = [ const mockPredefinedFilms = [
FilmExponential(id: '1', name: 'Mock film 2x', iso: 400, exponent: 1.34), FilmExponential(id: '1', name: 'Mock film 2x', iso: 400, exponent: 1.34),
FilmExponential(id: '2', name: 'Mock film 3x', iso: 800, exponent: 1.34), FilmExponential(id: '2', name: 'Mock film 3x', iso: 800, exponent: 1.34),