Added stop fraction picker

TODO: fix `MeteringScreen` double build on fraction change
This commit is contained in:
Vadim 2022-12-11 17:04:08 +03:00
parent 9143701b76
commit 10764086ad
8 changed files with 147 additions and 17 deletions

View file

@ -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"

View file

@ -13,12 +13,12 @@ import 'metering_event.dart';
import 'metering_state.dart';
class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
final StopType stopType;
late final _apertureValues = apertureValues.whereStopType(stopType);
late final _shutterSpeedValues = shutterSpeedValues.whereStopType(stopType);
late final _isoValues = isoValues.whereStopType(stopType);
List<ApertureValue> get _apertureValues => apertureValues.whereStopType(stopType);
List<ShutterSpeedValue> get _shutterSpeedValues => shutterSpeedValues.whereStopType(stopType);
final _random = Random();
StopType stopType;
MeteringBloc(this.stopType)
: super(
MeteringState(
@ -29,6 +29,7 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
exposurePairs: [],
),
) {
on<StopTypeChangedEvent>(_onStopTypeChanged);
on<IsoChangedEvent>(_onIsoChanged);
on<NdChangedEvent>(_onNdChanged);
on<MeasureEvent>(_onMeasure);
@ -36,6 +37,17 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
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<MeteringEvent, MeteringState> {
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);

View file

@ -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;

View file

@ -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<MeteringScreen> {
});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
context.read<MeteringBloc>().add(StopTypeChangedEvent(context.watch<StopType>()));
}
@override
Widget build(BuildContext context) {
return Scaffold(

View file

@ -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<FractionalStopsDialog> createState() => _FractionalStopsDialogState();
}
class _FractionalStopsDialogState extends State<FractionalStopsDialog> {
late StopType _selected = widget.selectedType;
@override
Widget build(BuildContext context) {
return SimpleDialog(
title: Text(S.of(context).showFractionalStops),
children: [
RadioListTile<StopType>(
value: StopType.full,
groupValue: _selected,
title: Text(S.of(context).none),
onChanged: _onChanged,
),
RadioListTile<StopType>(
value: StopType.half,
groupValue: _selected,
title: Text(S.of(context).halfStops),
onChanged: _onChanged,
),
RadioListTile<StopType>(
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);
}
}

View file

@ -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<FractionalStopsListTile> createState() => _FractionalStopsListTileState();
}
class _FractionalStopsListTileState extends State<FractionalStopsListTile> {
@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<StopType>()),
).then((value) {
if (value != null) {
StopTypeProvider.of(context).set(value);
}
});
},
);
}
String get selectedType {
switch (context.watch<StopType>()) {
case StopType.full:
return S.of(context).none;
case StopType.half:
return S.of(context).halfStops;
case StopType.third:
return S.of(context).thirdStops;
}
}
}

View file

@ -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(),
],

View file

@ -7,27 +7,30 @@ class StopTypeProvider extends StatefulWidget {
const StopTypeProvider({this.child, super.key});
static StopTypeProviderState of(BuildContext context) {
return context.findAncestorStateOfType<StopTypeProviderState>()!;
}
@override
State<StopTypeProvider> createState() => StopTypeProviderState();
}
class StopTypeProviderState extends State<StopTypeProvider> {
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;
});
}
}