mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-25 00:40:39 +00:00
Added stop fraction picker
TODO: fix `MeteringScreen` double build on fraction change
This commit is contained in:
parent
9143701b76
commit
10764086ad
8 changed files with 147 additions and 17 deletions
|
@ -13,6 +13,10 @@
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
|
"fractionalStops": "Fractional stops",
|
||||||
|
"showFractionalStops": "Show fractional stops",
|
||||||
|
"halfStops": "1/2",
|
||||||
|
"thirdStops": "1/3",
|
||||||
"caffeine": "Caffeine",
|
"caffeine": "Caffeine",
|
||||||
"keepsScreenOn": "Keeps screen on",
|
"keepsScreenOn": "Keeps screen on",
|
||||||
"haptics": "Haptics"
|
"haptics": "Haptics"
|
||||||
|
|
|
@ -13,12 +13,12 @@ import 'metering_event.dart';
|
||||||
import 'metering_state.dart';
|
import 'metering_state.dart';
|
||||||
|
|
||||||
class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
final StopType stopType;
|
List<ApertureValue> get _apertureValues => apertureValues.whereStopType(stopType);
|
||||||
late final _apertureValues = apertureValues.whereStopType(stopType);
|
List<ShutterSpeedValue> get _shutterSpeedValues => shutterSpeedValues.whereStopType(stopType);
|
||||||
late final _shutterSpeedValues = shutterSpeedValues.whereStopType(stopType);
|
|
||||||
late final _isoValues = isoValues.whereStopType(stopType);
|
|
||||||
final _random = Random();
|
final _random = Random();
|
||||||
|
|
||||||
|
StopType stopType;
|
||||||
|
|
||||||
MeteringBloc(this.stopType)
|
MeteringBloc(this.stopType)
|
||||||
: super(
|
: super(
|
||||||
MeteringState(
|
MeteringState(
|
||||||
|
@ -29,6 +29,7 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
exposurePairs: [],
|
exposurePairs: [],
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
|
on<StopTypeChangedEvent>(_onStopTypeChanged);
|
||||||
on<IsoChangedEvent>(_onIsoChanged);
|
on<IsoChangedEvent>(_onIsoChanged);
|
||||||
on<NdChangedEvent>(_onNdChanged);
|
on<NdChangedEvent>(_onNdChanged);
|
||||||
on<MeasureEvent>(_onMeasure);
|
on<MeasureEvent>(_onMeasure);
|
||||||
|
@ -36,6 +37,17 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
add(const MeasureEvent());
|
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) {
|
void _onIsoChanged(IsoChangedEvent event, Emitter emit) {
|
||||||
final ev = state.ev + log2(event.isoValue.value / state.iso.value);
|
final ev = state.ev + log2(event.isoValue.value / state.iso.value);
|
||||||
emit(MeteringState(
|
emit(MeteringState(
|
||||||
|
@ -62,7 +74,7 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
void _onMeasure(_, Emitter emit) {
|
void _onMeasure(_, Emitter emit) {
|
||||||
final aperture = _apertureValues[_random.nextInt(_apertureValues.length)];
|
final aperture = _apertureValues[_random.nextInt(_apertureValues.length)];
|
||||||
final shutterSpeed = _shutterSpeedValues[_random.nextInt(_shutterSpeedValues.thirdStops().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 evAtSystemIso = log2(pow(aperture.value, 2).toDouble() / shutterSpeed.value);
|
||||||
final ev = evAtSystemIso - log2(iso.value / state.iso.value);
|
final ev = evAtSystemIso - log2(iso.value / state.iso.value);
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
import 'package:lightmeter/models/iso_value.dart';
|
import 'package:lightmeter/models/iso_value.dart';
|
||||||
import 'package:lightmeter/models/nd_value.dart';
|
import 'package:lightmeter/models/nd_value.dart';
|
||||||
|
import 'package:lightmeter/models/photography_value.dart';
|
||||||
|
|
||||||
abstract class MeteringEvent {
|
abstract class MeteringEvent {
|
||||||
const MeteringEvent();
|
const MeteringEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StopTypeChangedEvent extends MeteringEvent {
|
||||||
|
final StopType stopType;
|
||||||
|
|
||||||
|
const StopTypeChangedEvent(this.stopType);
|
||||||
|
}
|
||||||
|
|
||||||
class IsoChangedEvent extends MeteringEvent {
|
class IsoChangedEvent extends MeteringEvent {
|
||||||
final IsoValue isoValue;
|
final IsoValue isoValue;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:lightmeter/models/photography_value.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
import 'package:lightmeter/screens/settings/settings_page_route_builder.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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import 'package:lightmeter/res/dimens.dart';
|
||||||
|
|
||||||
import 'components/caffeine_tile.dart';
|
import 'components/caffeine_tile.dart';
|
||||||
import 'components/haptics_tile.dart';
|
import 'components/haptics_tile.dart';
|
||||||
|
import 'components/fractional_stops/list_tile_fractional_stops.dart';
|
||||||
|
|
||||||
class SettingsScreen extends StatelessWidget {
|
class SettingsScreen extends StatelessWidget {
|
||||||
const SettingsScreen({super.key});
|
const SettingsScreen({super.key});
|
||||||
|
@ -36,6 +37,7 @@ class SettingsScreen extends StatelessWidget {
|
||||||
SliverList(
|
SliverList(
|
||||||
delegate: SliverChildListDelegate(
|
delegate: SliverChildListDelegate(
|
||||||
[
|
[
|
||||||
|
const FractionalStopsListTile(),
|
||||||
const CaffeineListTile(),
|
const CaffeineListTile(),
|
||||||
const HapticsListTile(),
|
const HapticsListTile(),
|
||||||
],
|
],
|
||||||
|
|
|
@ -7,27 +7,30 @@ class StopTypeProvider extends StatefulWidget {
|
||||||
|
|
||||||
const StopTypeProvider({this.child, super.key});
|
const StopTypeProvider({this.child, super.key});
|
||||||
|
|
||||||
|
static StopTypeProviderState of(BuildContext context) {
|
||||||
|
return context.findAncestorStateOfType<StopTypeProviderState>()!;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StopTypeProvider> createState() => StopTypeProviderState();
|
State<StopTypeProvider> createState() => StopTypeProviderState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class StopTypeProviderState extends State<StopTypeProvider> {
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Provider.value(
|
return Provider.value(
|
||||||
value: stopType,
|
value: _stopType,
|
||||||
child: Provider.value(
|
child: widget.child,
|
||||||
value: this,
|
|
||||||
child: widget.child,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStopType(StopType type) {
|
|
||||||
setState(() {
|
|
||||||
stopType = type;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue