diff --git a/lib/data/models/camera_feature.dart b/lib/data/models/camera_feature.dart index 3265dd3..20193bf 100644 --- a/lib/data/models/camera_feature.dart +++ b/lib/data/models/camera_feature.dart @@ -1,6 +1,6 @@ enum CameraFeature { - histogram, spotMetering, + histogram, } typedef CameraFeaturesConfig = Map; diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 57e91d2..bd61598 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -40,6 +40,9 @@ "meteringScreenFeatureExtremeExposurePairs": "Fastest & shortest exposure pairs", "meteringScreenFeatureFilmPicker": "Film picker", "meteringScreenFeatureHistogram": "Histogram", + "cameraFeatures": "Camera features", + "cameraFeatureSpotMetering": "Spot metering", + "cameraFeatureHistogram": "Histogram", "film": "Film", "filmPush": "Film (push)", "filmPull": "Film (pull)", diff --git a/lib/providers/user_preferences_provider.dart b/lib/providers/user_preferences_provider.dart index 3a4111c..764f282 100644 --- a/lib/providers/user_preferences_provider.dart +++ b/lib/providers/user_preferences_provider.dart @@ -1,6 +1,7 @@ import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; +import 'package:lightmeter/data/models/camera_feature.dart'; import 'package:lightmeter/data/models/dynamic_colors_state.dart'; import 'package:lightmeter/data/models/ev_source_type.dart'; import 'package:lightmeter/data/models/metering_screen_layout_config.dart'; @@ -9,6 +10,7 @@ import 'package:lightmeter/data/models/theme_type.dart'; import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/res/theme.dart'; +import 'package:lightmeter/utils/map_model.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class UserPreferencesProvider extends StatefulWidget { @@ -51,6 +53,14 @@ class UserPreferencesProvider extends StatefulWidget { return _inheritFromEnumsModel(context, _Aspect.stopType).stopType; } + static CameraFeaturesConfig cameraConfigOf(BuildContext context) { + return context.findAncestorWidgetOfExactType<_CameraFeaturesModel>()!.data; + } + + static bool cameraFeatureOf(BuildContext context, CameraFeature feature) { + return InheritedModel.inheritFrom<_CameraFeaturesModel>(context, aspect: feature)!.data[feature]!; + } + static ThemeData themeOf(BuildContext context) { return _inheritFromEnumsModel(context, _Aspect.theme).theme; } @@ -74,6 +84,7 @@ class _UserPreferencesProviderState extends State with late EvSourceType _evSourceType; late StopType _stopType = widget.userPreferencesService.stopType; late MeteringScreenLayoutConfig _meteringScreenLayout = widget.userPreferencesService.meteringScreenLayout; + late CameraFeaturesConfig _cameraFeatures = widget.userPreferencesService.cameraFeatures; late SupportedLocale _locale = widget.userPreferencesService.locale; late ThemeType _themeType = widget.userPreferencesService.themeType; late Color _primaryColor = widget.userPreferencesService.primaryColor; @@ -83,7 +94,8 @@ class _UserPreferencesProviderState extends State with void initState() { super.initState(); _evSourceType = widget.userPreferencesService.evSourceType; - _evSourceType = _evSourceType == EvSourceType.sensor && !widget.hasLightSensor ? EvSourceType.camera : _evSourceType; + _evSourceType = + _evSourceType == EvSourceType.sensor && !widget.hasLightSensor ? EvSourceType.camera : _evSourceType; WidgetsBinding.instance.addObserver(this); } @@ -127,7 +139,10 @@ class _UserPreferencesProviderState extends State with themeType: _themeType, child: _MeteringScreenLayoutModel( data: _meteringScreenLayout, - child: widget.child, + child: _CameraFeaturesModel( + data: _cameraFeatures, + child: widget.child, + ), ), ); }, @@ -172,6 +187,13 @@ class _UserPreferencesProviderState extends State with widget.userPreferencesService.meteringScreenLayout = _meteringScreenLayout; } + void setCameraFeature(CameraFeaturesConfig config) { + setState(() { + _cameraFeatures = config; + }); + widget.userPreferencesService.cameraFeatures = _cameraFeatures; + } + void setPrimaryColor(Color primaryColor) { setState(() { _primaryColor = primaryColor; @@ -264,27 +286,16 @@ class _UserPreferencesModel extends InheritedModel<_Aspect> { } } -class _MeteringScreenLayoutModel extends InheritedModel { - final Map data; - +class _MeteringScreenLayoutModel extends MapModel { const _MeteringScreenLayoutModel({ - required this.data, + required super.data, + required super.child, + }); +} + +class _CameraFeaturesModel extends MapModel { + const _CameraFeaturesModel({ + required super.data, required super.child, }); - - @override - bool updateShouldNotify(_MeteringScreenLayoutModel oldWidget) => oldWidget.data != data; - - @override - bool updateShouldNotifyDependent( - _MeteringScreenLayoutModel oldWidget, - Set dependencies, - ) { - for (final dependecy in dependencies) { - if (oldWidget.data[dependecy] != data[dependecy]) { - return true; - } - } - return false; - } } diff --git a/lib/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart b/lib/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart new file mode 100644 index 0000000..9790d30 --- /dev/null +++ b/lib/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/data/models/camera_feature.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/user_preferences_provider.dart'; +import 'package:lightmeter/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart'; + +class CameraFeaturesListTile extends StatelessWidget { + const CameraFeaturesListTile({super.key}); + + @override + Widget build(BuildContext context) { + return ListTile( + leading: const Icon(Icons.camera_alt), + title: Text(S.of(context).cameraFeatures), + onTap: () { + showDialog( + context: context, + builder: (_) => DialogSwitch( + icon: Icons.layers_outlined, + title: S.of(context).cameraFeatures, + values: UserPreferencesProvider.cameraConfigOf(context), + titleAdapter: _toStringLocalized, + onSave: UserPreferencesProvider.of(context).setCameraFeature, + ), + ); + }, + ); + } + + String _toStringLocalized(BuildContext context, CameraFeature feature) { + switch (feature) { + case CameraFeature.spotMetering: + return S.of(context).cameraFeatureSpotMetering; + case CameraFeature.histogram: + return S.of(context).cameraFeatureHistogram; + } + } +} diff --git a/lib/screens/settings/components/metering/widget_settings_section_metering.dart b/lib/screens/settings/components/metering/widget_settings_section_metering.dart index 90de68d..0c6c07d 100644 --- a/lib/screens/settings/components/metering/widget_settings_section_metering.dart +++ b/lib/screens/settings/components/metering/widget_settings_section_metering.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/screens/settings/components/metering/components/calibration/widget_list_tile_calibration.dart'; +import 'package:lightmeter/screens/settings/components/metering/components/camera_features/widget_list_tile_camera_features.dart'; import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/widget_list_tile_equipment_profiles.dart'; import 'package:lightmeter/screens/settings/components/metering/components/films/widget_list_tile_films.dart'; import 'package:lightmeter/screens/settings/components/metering/components/fractional_stops/widget_list_tile_fractional_stops.dart'; @@ -20,6 +21,7 @@ class MeteringSettingsSection extends StatelessWidget { MeteringScreenLayoutListTile(), EquipmentProfilesListTile(), FilmsListTile(), + CameraFeaturesListTile(), ], ); } diff --git a/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart b/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart index d067092..4f7b58a 100644 --- a/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart +++ b/lib/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart @@ -5,7 +5,7 @@ import 'package:lightmeter/res/dimens.dart'; class DialogSwitch extends StatefulWidget { final IconData icon; final String title; - final String description; + final String? description; final Map values; final String Function(BuildContext context, T value) titleAdapter; final ValueChanged> onSave; @@ -13,7 +13,7 @@ class DialogSwitch extends StatefulWidget { const DialogSwitch({ required this.icon, required this.title, - required this.description, + this.description, required this.values, required this.titleAdapter, required this.onSave, @@ -39,11 +39,13 @@ class _DialogSwitchState extends State> { child: Column( mainAxisSize: MainAxisSize.min, children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), - child: Text(widget.description), - ), - const SizedBox(height: Dimens.grid16), + if (widget.description != null) ...[ + Padding( + padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), + child: Text(widget.description!), + ), + const SizedBox(height: Dimens.grid16) + ], ListView( shrinkWrap: true, children: _features.entries diff --git a/lib/utils/map_model.dart b/lib/utils/map_model.dart new file mode 100644 index 0000000..1f5ea09 --- /dev/null +++ b/lib/utils/map_model.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class MapModel extends InheritedModel { + final Map data; + + const MapModel({ + required this.data, + required super.child, + }); + + @override + bool updateShouldNotify(MapModel oldWidget) => oldWidget.data != data; + + @override + bool updateShouldNotifyDependent( + MapModel oldWidget, + Set dependencies, + ) { + for (final dependecy in dependencies) { + if (oldWidget.data[dependecy] != data[dependecy]) { + return true; + } + } + return false; + } +}