diff --git a/lib/application.dart b/lib/application.dart index ed596a5..3d568c5 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -7,6 +7,7 @@ import 'package:light_sensor/light_sensor.dart'; import 'package:lightmeter/data/caffeine_service.dart'; import 'package:lightmeter/data/haptics_service.dart'; import 'package:lightmeter/data/models/supported_locale.dart'; +import 'package:lightmeter/providers/film_profile.dart'; import 'package:lightmeter/providers/supported_locale_provider.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -48,30 +49,32 @@ class Application extends StatelessWidget { Provider(create: (_) => const LightSensorService()), ], child: StopTypeProvider( - child: EquipmentProfileProvider( - child: EvSourceTypeProvider( - child: SupportedLocaleProvider( - child: ThemeProvider( - builder: (context, _) => _AnnotatedRegionWrapper( - child: MaterialApp( - theme: context.watch(), - locale: Locale(context.watch().intlName), - localizationsDelegates: const [ - S.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: S.delegate.supportedLocales, - builder: (context, child) => MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), - child: child!, + child: FilmProvider( + child: EquipmentProfileProvider( + child: EvSourceTypeProvider( + child: SupportedLocaleProvider( + child: ThemeProvider( + builder: (context, _) => _AnnotatedRegionWrapper( + child: MaterialApp( + theme: context.watch(), + locale: Locale(context.watch().intlName), + localizationsDelegates: const [ + S.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: S.delegate.supportedLocales, + builder: (context, child) => MediaQuery( + data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), + child: child!, + ), + initialRoute: "metering", + routes: { + "metering": (context) => const MeteringFlow(), + "settings": (context) => const SettingsFlow(), + }, ), - initialRoute: "metering", - routes: { - "metering": (context) => const MeteringFlow(), - "settings": (context) => const SettingsFlow(), - }, ), ), ), diff --git a/lib/data/models/film.dart b/lib/data/models/film.dart index b6340e0..5930196 100644 --- a/lib/data/models/film.dart +++ b/lib/data/models/film.dart @@ -23,13 +23,13 @@ double log10polynomian( /// do not have any reciprocity failure information, as these films are ment to be used in cinema /// with appropriate light and pretty short shutter speeds. /// -class Film { +class FilmData { final String name; final int iso; - const Film(this.name, this.iso); + const FilmData(this.name, this.iso); - const Film.other() + const FilmData.other() : name = 'Other', iso = 0; @@ -51,9 +51,8 @@ class Film { @protected double reciprocityFormula(double t) => t; - static const List values = [ - Film.other(), - FomapanFilm.creative100(), + static const List values = [ + FilmData.other(), FomapanFilm.creative100(), FomapanFilm.creative200(), FomapanFilm.action400(), @@ -79,7 +78,7 @@ class Film { /// https://www.tate.org.uk/documents/598/page_6_7_agfa_stocks_0.pdf /// https://www.filmwasters.com/forum/index.php?topic=5298.0 // {{1,1.87},{2,3.73},{3,8.06},{4,13.93},{5,21.28},{6,23.00},{7,30.12},{8,38.05},{9,44.75},{10,50.12},{20,117},{30,202},{40,293},{50,413},{60,547},{70,694},{80,853},{90,1022},{100,1202}}; -class AgfaFilm extends Film { +class AgfaFilm extends FilmData { final double a; final double b; final double c; @@ -100,7 +99,7 @@ class AgfaFilm extends Film { double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c); } -class FomapanFilm extends Film { +class FomapanFilm extends FilmData { final double a; final double b; final double c; @@ -127,7 +126,7 @@ class FomapanFilm extends Film { super('Fomapan ACTION 400', 400); } -class IlfordFilm extends Film { +class IlfordFilm extends FilmData { final double reciprocityPower; /// https://www.ilfordphoto.com/amfile/file/download/file/1948/product/1650/ @@ -189,7 +188,7 @@ class IlfordFilm extends Film { double reciprocityFormula(double t) => pow(t, reciprocityPower).toDouble(); } -class KodakFilm extends Film { +class KodakFilm extends FilmData { final double a; final double b; final double c; diff --git a/lib/data/shared_prefs_service.dart b/lib/data/shared_prefs_service.dart index ab8f115..b23c019 100644 --- a/lib/data/shared_prefs_service.dart +++ b/lib/data/shared_prefs_service.dart @@ -4,6 +4,7 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'models/ev_source_type.dart'; +import 'models/film.dart'; import 'models/theme_type.dart'; class UserPreferencesService { @@ -13,6 +14,7 @@ class UserPreferencesService { static const _evSourceTypeKey = "evSourceType"; static const _cameraEvCalibrationKey = "cameraEvCalibration"; static const _lightSensorEvCalibrationKey = "lightSensorEvCalibration"; + static const _filmKey = "film"; static const _caffeineKey = "caffeine"; static const _hapticsKey = "haptics"; @@ -63,16 +65,13 @@ class UserPreferencesService { } } - IsoValue get iso => - isoValues.firstWhere((v) => v.value == (_sharedPreferences.getInt(_isoKey) ?? 100)); + IsoValue get iso => isoValues.firstWhere((v) => v.value == (_sharedPreferences.getInt(_isoKey) ?? 100)); set iso(IsoValue value) => _sharedPreferences.setInt(_isoKey, value.value); - NdValue get ndFilter => - ndValues.firstWhere((v) => v.value == (_sharedPreferences.getInt(_ndFilterKey) ?? 0)); + NdValue get ndFilter => ndValues.firstWhere((v) => v.value == (_sharedPreferences.getInt(_ndFilterKey) ?? 0)); set ndFilter(NdValue value) => _sharedPreferences.setInt(_ndFilterKey, value.value); - EvSourceType get evSourceType => - EvSourceType.values[_sharedPreferences.getInt(_evSourceTypeKey) ?? 0]; + EvSourceType get evSourceType => EvSourceType.values[_sharedPreferences.getInt(_evSourceTypeKey) ?? 0]; set evSourceType(EvSourceType value) => _sharedPreferences.setInt(_evSourceTypeKey, value.index); bool get caffeine => _sharedPreferences.getBool(_caffeineKey) ?? false; @@ -88,13 +87,10 @@ class UserPreferencesService { set locale(SupportedLocale value) => _sharedPreferences.setString(_localeKey, value.toString()); double get cameraEvCalibration => _sharedPreferences.getDouble(_cameraEvCalibrationKey) ?? 0.0; - set cameraEvCalibration(double value) => - _sharedPreferences.setDouble(_cameraEvCalibrationKey, value); + set cameraEvCalibration(double value) => _sharedPreferences.setDouble(_cameraEvCalibrationKey, value); - double get lightSensorEvCalibration => - _sharedPreferences.getDouble(_lightSensorEvCalibrationKey) ?? 0.0; - set lightSensorEvCalibration(double value) => - _sharedPreferences.setDouble(_lightSensorEvCalibrationKey, value); + double get lightSensorEvCalibration => _sharedPreferences.getDouble(_lightSensorEvCalibrationKey) ?? 0.0; + set lightSensorEvCalibration(double value) => _sharedPreferences.setDouble(_lightSensorEvCalibrationKey, value); ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(_themeTypeKey) ?? 0]; set themeType(ThemeType value) => _sharedPreferences.setInt(_themeTypeKey, value.index); @@ -105,6 +101,12 @@ class UserPreferencesService { bool get dynamicColor => _sharedPreferences.getBool(_dynamicColorKey) ?? false; set dynamicColor(bool value) => _sharedPreferences.setBool(_dynamicColorKey, value); + FilmData get film => FilmData.values.firstWhere( + (e) => e.name == _sharedPreferences.getString(_filmKey), + orElse: () => FilmData.values.first, + ); + set film(FilmData value) => _sharedPreferences.setString(_filmKey, value.name); + String get selectedEquipmentProfileId => ''; set selectedEquipmentProfileId(String id) {} diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 5a6d06e..4a2b65a 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -34,6 +34,7 @@ "calibrationMessageCameraOnly": "The accuracy of the readings measured by this application depends entirely on the rear camera of the device. Therefore, consider testing this application and setting up an EV calibration value that will give you the desired measurement results.", "camera": "Camera", "lightSensor": "Light sensor", + "film": "Film", "equipment": "Equipment", "equipmentProfileName": "Equipment profile name", "equipmentProfileNameHint": "Praktica MTL5B", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 7e19d56..49debfb 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -34,6 +34,7 @@ "calibrationMessageCameraOnly": "La précision des lectures mesurées par cette application dépend entièrement de la caméra arrière de l'appareil. Par conséquent, envisagez de tester cette application et de configurer une valeur d'étalonnage EV qui vous donnera les résultats de mesure souhaités.", "camera": "Caméra", "lightSensor": "Capteur de lumière", + "film": "Pellicule", "equipment": "Équipement", "equipmentProfileName": "Nom du profil de l'équipement", "equipmentProfileNameHint": "Praktica MTL5B", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index f6d201f..dece4f7 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -34,6 +34,7 @@ "calibrationMessageCameraOnly": "Точность измерений данного приложения полностью зависит от точности камеры вашего устройства. Поэтому рекомендуется самостоятельно подобрать калибровочное значение, которое даст желаемый результат измерений.", "camera": "Камера", "lightSensor": "Датчик освещённости", + "film": "Пленка", "equipment": "Оборудование", "equipmentProfileName": "Название профиля", "equipmentProfileNameHint": "Praktica MTL5B", diff --git a/lib/providers/film_profile.dart b/lib/providers/film_profile.dart new file mode 100644 index 0000000..529ed1e --- /dev/null +++ b/lib/providers/film_profile.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/film.dart'; +import 'package:lightmeter/data/shared_prefs_service.dart'; +import 'package:provider/provider.dart'; + +class FilmProvider extends StatefulWidget { + final Widget child; + + const FilmProvider({required this.child, super.key}); + + static FilmProviderState of(BuildContext context) { + return context.findAncestorStateOfType()!; + } + + @override + State createState() => FilmProviderState(); +} + +class FilmProviderState extends State { + late FilmData _selectedFilm; + + @override + void initState() { + super.initState(); + _selectedFilm = context.read().film; + } + + @override + Widget build(BuildContext context) { + return Film( + data: _selectedFilm, + child: widget.child, + ); + } + + void setFilm(FilmData data) { + setState(() { + _selectedFilm = data; + }); + context.read().film = _selectedFilm; + } +} + +class Film extends InheritedWidget { + final FilmData data; + + const Film({ + required this.data, + required super.child, + super.key, + }); + + static FilmData of(BuildContext context, {bool listen = true}) { + if (listen) { + return context.dependOnInheritedWidgetOfExactType()!.data; + } else { + return context.findAncestorWidgetOfExactType()!.data; + } + } + + @override + bool updateShouldNotify(Film oldWidget) => true; +}