diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index dcacbe8..e39a45c 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -13,6 +13,10 @@ "cancel": "Cancel", "select": "Select", "settings": "Settings", + "fractionalStops": "Fractional stops", + "showFractionalStops": "Show fractional stops", + "halfStops": "1/2", + "thirdStops": "1/3", "caffeine": "Caffeine", "keepsScreenOn": "Keeps screen on", "haptics": "Haptics" diff --git a/lib/screens/metering/metering_bloc.dart b/lib/screens/metering/metering_bloc.dart index 49fa8c2..74a6fad 100644 --- a/lib/screens/metering/metering_bloc.dart +++ b/lib/screens/metering/metering_bloc.dart @@ -13,12 +13,12 @@ import 'metering_event.dart'; import 'metering_state.dart'; class MeteringBloc extends Bloc { - final StopType stopType; - late final _apertureValues = apertureValues.whereStopType(stopType); - late final _shutterSpeedValues = shutterSpeedValues.whereStopType(stopType); - late final _isoValues = isoValues.whereStopType(stopType); + List get _apertureValues => apertureValues.whereStopType(stopType); + List get _shutterSpeedValues => shutterSpeedValues.whereStopType(stopType); final _random = Random(); + StopType stopType; + MeteringBloc(this.stopType) : super( MeteringState( @@ -29,6 +29,7 @@ class MeteringBloc extends Bloc { exposurePairs: [], ), ) { + on(_onStopTypeChanged); on(_onIsoChanged); on(_onNdChanged); on(_onMeasure); @@ -36,6 +37,17 @@ class MeteringBloc extends Bloc { add(const MeasureEvent()); } + void _onStopTypeChanged(StopTypeChangedEvent event, Emitter emit) { + stopType = event.stopType; + emit(MeteringState( + iso: state.iso, + ev: state.ev, + evCompensation: state.evCompensation, + nd: state.nd, + exposurePairs: _buildExposureValues(state.ev), + )); + } + void _onIsoChanged(IsoChangedEvent event, Emitter emit) { final ev = state.ev + log2(event.isoValue.value / state.iso.value); emit(MeteringState( @@ -62,7 +74,7 @@ class MeteringBloc extends Bloc { void _onMeasure(_, Emitter emit) { final aperture = _apertureValues[_random.nextInt(_apertureValues.length)]; final shutterSpeed = _shutterSpeedValues[_random.nextInt(_shutterSpeedValues.thirdStops().length)]; - final iso = _isoValues[_random.nextInt(_isoValues.thirdStops().length)]; + final iso = isoValues[_random.nextInt(isoValues.thirdStops().length)]; final evAtSystemIso = log2(pow(aperture.value, 2).toDouble() / shutterSpeed.value); final ev = evAtSystemIso - log2(iso.value / state.iso.value); diff --git a/lib/screens/metering/metering_event.dart b/lib/screens/metering/metering_event.dart index 9576e16..40e4ae7 100644 --- a/lib/screens/metering/metering_event.dart +++ b/lib/screens/metering/metering_event.dart @@ -1,10 +1,17 @@ import 'package:lightmeter/models/iso_value.dart'; import 'package:lightmeter/models/nd_value.dart'; +import 'package:lightmeter/models/photography_value.dart'; abstract class MeteringEvent { const MeteringEvent(); } +class StopTypeChangedEvent extends MeteringEvent { + final StopType stopType; + + const StopTypeChangedEvent(this.stopType); +} + class IsoChangedEvent extends MeteringEvent { final IsoValue isoValue; diff --git a/lib/screens/metering/metering_screen.dart b/lib/screens/metering/metering_screen.dart index ab78803..c3452f2 100644 --- a/lib/screens/metering/metering_screen.dart +++ b/lib/screens/metering/metering_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:lightmeter/models/photography_value.dart'; import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/screens/settings/settings_page_route_builder.dart'; @@ -43,6 +44,12 @@ class _MeteringScreenState extends State { }); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + context.read().add(StopTypeChangedEvent(context.watch())); + } + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/screens/settings/components/fractional_stops/dialog_fractional_stops.dart b/lib/screens/settings/components/fractional_stops/dialog_fractional_stops.dart new file mode 100644 index 0000000..40b9a4a --- /dev/null +++ b/lib/screens/settings/components/fractional_stops/dialog_fractional_stops.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/models/photography_value.dart'; + +class FractionalStopsDialog extends StatefulWidget { + final StopType selectedType; + + const FractionalStopsDialog({required this.selectedType, super.key}); + + @override + State createState() => _FractionalStopsDialogState(); +} + +class _FractionalStopsDialogState extends State { + late StopType _selected = widget.selectedType; + + @override + Widget build(BuildContext context) { + return SimpleDialog( + title: Text(S.of(context).showFractionalStops), + children: [ + RadioListTile( + value: StopType.full, + groupValue: _selected, + title: Text(S.of(context).none), + onChanged: _onChanged, + ), + RadioListTile( + value: StopType.half, + groupValue: _selected, + title: Text(S.of(context).halfStops), + onChanged: _onChanged, + ), + RadioListTile( + value: StopType.third, + groupValue: _selected, + title: Text(S.of(context).thirdStops), + onChanged: _onChanged, + ), + ], + ); + } + + void _onChanged(StopType? value) { + setState(() { + _selected = value!; + }); + Navigator.of(context).pop(_selected); + } +} diff --git a/lib/screens/settings/components/fractional_stops/list_tile_fractional_stops.dart b/lib/screens/settings/components/fractional_stops/list_tile_fractional_stops.dart new file mode 100644 index 0000000..dac28af --- /dev/null +++ b/lib/screens/settings/components/fractional_stops/list_tile_fractional_stops.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/models/photography_value.dart'; +import 'package:lightmeter/utils/stop_type_provider.dart'; +import 'package:provider/provider.dart'; + +import 'dialog_fractional_stops.dart'; + +class FractionalStopsListTile extends StatefulWidget { + const FractionalStopsListTile({super.key}); + + @override + State createState() => _FractionalStopsListTileState(); +} + +class _FractionalStopsListTileState extends State { + @override + Widget build(BuildContext context) { + return ListTile( + title: Text(S.of(context).fractionalStops), + trailing: Text(selectedType), + onTap: () { + showDialog( + context: context, + builder: (_) => FractionalStopsDialog(selectedType: context.read()), + ).then((value) { + if (value != null) { + StopTypeProvider.of(context).set(value); + } + }); + }, + ); + } + + String get selectedType { + switch (context.watch()) { + case StopType.full: + return S.of(context).none; + case StopType.half: + return S.of(context).halfStops; + case StopType.third: + return S.of(context).thirdStops; + } + } +} diff --git a/lib/screens/settings/settings_screen.dart b/lib/screens/settings/settings_screen.dart index e4bd939..38b38b6 100644 --- a/lib/screens/settings/settings_screen.dart +++ b/lib/screens/settings/settings_screen.dart @@ -4,6 +4,7 @@ import 'package:lightmeter/res/dimens.dart'; import 'components/caffeine_tile.dart'; import 'components/haptics_tile.dart'; +import 'components/fractional_stops/list_tile_fractional_stops.dart'; class SettingsScreen extends StatelessWidget { const SettingsScreen({super.key}); @@ -36,6 +37,7 @@ class SettingsScreen extends StatelessWidget { SliverList( delegate: SliverChildListDelegate( [ + const FractionalStopsListTile(), const CaffeineListTile(), const HapticsListTile(), ], diff --git a/lib/utils/stop_type_provider.dart b/lib/utils/stop_type_provider.dart index b3b51c2..ae9f041 100644 --- a/lib/utils/stop_type_provider.dart +++ b/lib/utils/stop_type_provider.dart @@ -7,27 +7,30 @@ class StopTypeProvider extends StatefulWidget { const StopTypeProvider({this.child, super.key}); + static StopTypeProviderState of(BuildContext context) { + return context.findAncestorStateOfType()!; + } + @override State createState() => StopTypeProviderState(); } class StopTypeProviderState extends State { - StopType stopType = StopType.full; + StopType _stopType = StopType.third; + + StopType get stopType => _stopType; + + void set(StopType type) { + setState(() { + _stopType = type; + }); + } @override Widget build(BuildContext context) { return Provider.value( - value: stopType, - child: Provider.value( - value: this, - child: widget.child, - ), + value: _stopType, + child: widget.child, ); } - - void setStopType(StopType type) { - setState(() { - stopType = type; - }); - } }