mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 23:10:40 +00:00
Recalculate EV on ND change
Recalculate EV on ND change `PhotographyValue` -> `PhotographyStopValue`
This commit is contained in:
parent
dbbc5738ce
commit
1c344da29f
17 changed files with 134 additions and 34 deletions
|
@ -29,6 +29,8 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"iso": MessageLookupByLibrary.simpleMessage("ISO"),
|
"iso": MessageLookupByLibrary.simpleMessage("ISO"),
|
||||||
"keepsScreenOn":
|
"keepsScreenOn":
|
||||||
MessageLookupByLibrary.simpleMessage("Keeps screen on"),
|
MessageLookupByLibrary.simpleMessage("Keeps screen on"),
|
||||||
|
"nd": MessageLookupByLibrary.simpleMessage("ND"),
|
||||||
|
"none": MessageLookupByLibrary.simpleMessage("None"),
|
||||||
"openSettings": MessageLookupByLibrary.simpleMessage("Open settings"),
|
"openSettings": MessageLookupByLibrary.simpleMessage("Open settings"),
|
||||||
"permissionNeeded":
|
"permissionNeeded":
|
||||||
MessageLookupByLibrary.simpleMessage("Permission needed"),
|
MessageLookupByLibrary.simpleMessage("Permission needed"),
|
||||||
|
|
|
@ -110,6 +110,26 @@ class S {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `ND`
|
||||||
|
String get nd {
|
||||||
|
return Intl.message(
|
||||||
|
'ND',
|
||||||
|
name: 'nd',
|
||||||
|
desc: '',
|
||||||
|
args: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `None`
|
||||||
|
String get none {
|
||||||
|
return Intl.message(
|
||||||
|
'None',
|
||||||
|
name: 'none',
|
||||||
|
desc: '',
|
||||||
|
args: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// `Cancel`
|
/// `Cancel`
|
||||||
String get cancel {
|
String get cancel {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
"fastestExposurePair": "Fastest",
|
"fastestExposurePair": "Fastest",
|
||||||
"slowestExposurePair": "Slowest",
|
"slowestExposurePair": "Slowest",
|
||||||
"iso": "ISO",
|
"iso": "ISO",
|
||||||
|
"nd": "ND",
|
||||||
|
"none": "None",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
part of 'photography_value.dart';
|
import 'photography_value.dart';
|
||||||
|
|
||||||
class ApertureValue extends PhotographyValue<double> {
|
class ApertureValue extends PhotographyStopValue<double> {
|
||||||
const ApertureValue(super.rawValue, super.stopType);
|
const ApertureValue(super.rawValue, super.stopType);
|
||||||
|
|
||||||
@override
|
|
||||||
double get value => rawValue;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
final buffer = StringBuffer("f/");
|
final buffer = StringBuffer("f/");
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'photography_value.dart';
|
import 'aperture_value.dart';
|
||||||
|
import 'shutter_speed_value.dart';
|
||||||
|
|
||||||
class ExposurePair {
|
class ExposurePair {
|
||||||
final ApertureValue aperture;
|
final ApertureValue aperture;
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
part of 'photography_value.dart';
|
import 'photography_value.dart';
|
||||||
|
|
||||||
class IsoValue extends PhotographyValue<int> {
|
class IsoValue extends PhotographyStopValue<int> {
|
||||||
const IsoValue(super.rawValue, super.stopType);
|
const IsoValue(super.rawValue, super.stopType);
|
||||||
|
|
||||||
@override
|
|
||||||
int get value => rawValue;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => value.toString();
|
String toString() => value.toString();
|
||||||
}
|
}
|
||||||
|
|
31
lib/models/nd_value.dart
Normal file
31
lib/models/nd_value.dart
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import 'package:lightmeter/utils/log_2.dart';
|
||||||
|
|
||||||
|
import 'photography_value.dart';
|
||||||
|
|
||||||
|
class NdValue extends PhotographyValue<int> {
|
||||||
|
const NdValue(super.rawValue);
|
||||||
|
|
||||||
|
double get stopReduction => value == 0 ? 0.0 : log2(value);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => 'ND$value';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://shuttermuse.com/neutral-density-filter-numbers-names/
|
||||||
|
const List<NdValue> ndValues = [
|
||||||
|
NdValue(0),
|
||||||
|
NdValue(2),
|
||||||
|
NdValue(4),
|
||||||
|
NdValue(8),
|
||||||
|
NdValue(16),
|
||||||
|
NdValue(32),
|
||||||
|
NdValue(64),
|
||||||
|
NdValue(128),
|
||||||
|
NdValue(256),
|
||||||
|
NdValue(512),
|
||||||
|
NdValue(1024),
|
||||||
|
NdValue(2048),
|
||||||
|
NdValue(4096),
|
||||||
|
NdValue(8192),
|
||||||
|
NdValue(10000),
|
||||||
|
];
|
|
@ -1,19 +1,20 @@
|
||||||
part 'aperture_value.dart';
|
|
||||||
part 'iso_value.dart';
|
|
||||||
part 'shutter_speed_value.dart';
|
|
||||||
|
|
||||||
enum StopType { full, half, third }
|
enum StopType { full, half, third }
|
||||||
|
|
||||||
abstract class PhotographyValue<T> {
|
abstract class PhotographyValue<T> {
|
||||||
final T rawValue;
|
final T rawValue;
|
||||||
final StopType stopType;
|
|
||||||
|
|
||||||
const PhotographyValue(this.rawValue, this.stopType);
|
const PhotographyValue(this.rawValue);
|
||||||
|
|
||||||
T get value;
|
T get value => rawValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PhotographyValues<T extends PhotographyValue> on List<T> {
|
abstract class PhotographyStopValue<T> extends PhotographyValue<T> {
|
||||||
|
final StopType stopType;
|
||||||
|
|
||||||
|
const PhotographyStopValue(super.rawValue, this.stopType);
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PhotographyStopValues<T extends PhotographyStopValue> on List<T> {
|
||||||
List<T> whereStopType(StopType stopType) {
|
List<T> whereStopType(StopType stopType) {
|
||||||
switch (stopType) {
|
switch (stopType) {
|
||||||
case StopType.full:
|
case StopType.full:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
part of 'photography_value.dart';
|
import 'photography_value.dart';
|
||||||
|
|
||||||
class ShutterSpeedValue extends PhotographyValue<double> {
|
class ShutterSpeedValue extends PhotographyStopValue<double> {
|
||||||
final bool isFraction;
|
final bool isFraction;
|
||||||
|
|
||||||
const ShutterSpeedValue(super.rawValue, this.isFraction, super.stopType);
|
const ShutterSpeedValue(super.rawValue, this.isFraction, super.stopType);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/models/photography_value.dart';
|
import 'package:lightmeter/models/photography_value.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
|
|
||||||
class ExposurePaitListItem<T extends PhotographyValue> extends StatelessWidget {
|
class ExposurePaitListItem<T extends PhotographyStopValue> extends StatelessWidget {
|
||||||
final T value;
|
final T value;
|
||||||
final bool tickOnTheLeft;
|
final bool tickOnTheLeft;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/models/exposure_pair.dart';
|
import 'package:lightmeter/models/exposure_pair.dart';
|
||||||
|
import 'package:lightmeter/models/iso_value.dart';
|
||||||
|
import 'package:lightmeter/models/nd_value.dart';
|
||||||
import 'package:lightmeter/models/photography_value.dart';
|
import 'package:lightmeter/models/photography_value.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
|
|
||||||
|
@ -12,13 +14,15 @@ import 'models/reading_value.dart';
|
||||||
class MeteringTopBar extends StatelessWidget {
|
class MeteringTopBar extends StatelessWidget {
|
||||||
static const _columnsCount = 3;
|
static const _columnsCount = 3;
|
||||||
final _isoDialogKey = GlobalKey<AnimatedDialogState>();
|
final _isoDialogKey = GlobalKey<AnimatedDialogState>();
|
||||||
|
final _ndDialogKey = GlobalKey<AnimatedDialogState>();
|
||||||
|
|
||||||
final ExposurePair? fastest;
|
final ExposurePair? fastest;
|
||||||
final ExposurePair? slowest;
|
final ExposurePair? slowest;
|
||||||
final double ev;
|
final double ev;
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final double nd;
|
final NdValue nd;
|
||||||
final ValueChanged<IsoValue> onIsoChanged;
|
final ValueChanged<IsoValue> onIsoChanged;
|
||||||
|
final ValueChanged<NdValue> onNdChanged;
|
||||||
|
|
||||||
MeteringTopBar({
|
MeteringTopBar({
|
||||||
required this.fastest,
|
required this.fastest,
|
||||||
|
@ -27,6 +31,7 @@ class MeteringTopBar extends StatelessWidget {
|
||||||
required this.iso,
|
required this.iso,
|
||||||
required this.nd,
|
required this.nd,
|
||||||
required this.onIsoChanged,
|
required this.onIsoChanged,
|
||||||
|
required this.onNdChanged,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -137,10 +142,28 @@ class MeteringTopBar extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const _InnerPadding(),
|
const _InnerPadding(),
|
||||||
ReadingContainer.singleValue(
|
AnimatedDialog(
|
||||||
value: ReadingValue(
|
key: _ndDialogKey,
|
||||||
label: 'ND',
|
closedChild: ReadingContainer.singleValue(
|
||||||
value: nd.toString(),
|
value: ReadingValue(
|
||||||
|
label: S.of(context).nd,
|
||||||
|
value: nd.value.toString(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
openedChild: MeteringScreenDialogPicker(
|
||||||
|
title: S.of(context).nd,
|
||||||
|
initialValue: nd,
|
||||||
|
values: ndValues,
|
||||||
|
itemTitleBuilder: (context, value) => Text(
|
||||||
|
value.value == 0 ? S.of(context).none : value.value.toString(),
|
||||||
|
style: Theme.of(context).textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
onCancel: () {
|
||||||
|
_ndDialogKey.currentState?.close();
|
||||||
|
},
|
||||||
|
onSelect: (value) {
|
||||||
|
_ndDialogKey.currentState?.close().then((_) => onNdChanged(value));
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:lightmeter/models/aperture_value.dart';
|
||||||
import 'package:lightmeter/models/exposure_pair.dart';
|
import 'package:lightmeter/models/exposure_pair.dart';
|
||||||
|
import 'package:lightmeter/models/iso_value.dart';
|
||||||
|
import 'package:lightmeter/models/nd_value.dart';
|
||||||
import 'package:lightmeter/models/photography_value.dart';
|
import 'package:lightmeter/models/photography_value.dart';
|
||||||
|
import 'package:lightmeter/models/shutter_speed_value.dart';
|
||||||
import 'package:lightmeter/utils/log_2.dart';
|
import 'package:lightmeter/utils/log_2.dart';
|
||||||
|
|
||||||
import 'metering_event.dart';
|
import 'metering_event.dart';
|
||||||
|
@ -21,11 +25,12 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
iso: isoValues.where((element) => element.value == 100).first,
|
iso: isoValues.where((element) => element.value == 100).first,
|
||||||
ev: 21.3,
|
ev: 21.3,
|
||||||
evCompensation: 0.0,
|
evCompensation: 0.0,
|
||||||
nd: 0.0,
|
nd: ndValues.first,
|
||||||
exposurePairs: [],
|
exposurePairs: [],
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
on<IsoChangedEvent>(_onIsoChanged);
|
on<IsoChangedEvent>(_onIsoChanged);
|
||||||
|
on<NdChangedEvent>(_onNdChanged);
|
||||||
on<MeasureEvent>(_onMeasure);
|
on<MeasureEvent>(_onMeasure);
|
||||||
|
|
||||||
add(const MeasureEvent());
|
add(const MeasureEvent());
|
||||||
|
@ -42,10 +47,19 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onNdChanged(NdChangedEvent event, Emitter emit) {
|
||||||
|
final ev = state.ev - event.ndValue.stopReduction + state.nd.stopReduction;
|
||||||
|
emit(MeteringState(
|
||||||
|
iso: state.iso,
|
||||||
|
ev: ev,
|
||||||
|
evCompensation: state.evCompensation,
|
||||||
|
nd: event.ndValue,
|
||||||
|
exposurePairs: _buildExposureValues(ev),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/// https://www.scantips.com/lights/exposurecalc.html
|
/// https://www.scantips.com/lights/exposurecalc.html
|
||||||
void _onMeasure(_, Emitter emit) {
|
void _onMeasure(_, Emitter emit) {
|
||||||
double log2(double x) => log(x) / log(2);
|
|
||||||
|
|
||||||
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)];
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:lightmeter/models/photography_value.dart';
|
import 'package:lightmeter/models/iso_value.dart';
|
||||||
|
import 'package:lightmeter/models/nd_value.dart';
|
||||||
|
|
||||||
abstract class MeteringEvent {
|
abstract class MeteringEvent {
|
||||||
const MeteringEvent();
|
const MeteringEvent();
|
||||||
|
@ -10,6 +11,12 @@ class IsoChangedEvent extends MeteringEvent {
|
||||||
const IsoChangedEvent(this.isoValue);
|
const IsoChangedEvent(this.isoValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NdChangedEvent extends MeteringEvent {
|
||||||
|
final NdValue ndValue;
|
||||||
|
|
||||||
|
const NdChangedEvent(this.ndValue);
|
||||||
|
}
|
||||||
|
|
||||||
class MeasureEvent extends MeteringEvent {
|
class MeasureEvent extends MeteringEvent {
|
||||||
const MeasureEvent();
|
const MeasureEvent();
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,7 @@ class _MeteringScreenState extends State<MeteringScreen> {
|
||||||
iso: state.iso,
|
iso: state.iso,
|
||||||
nd: state.nd,
|
nd: state.nd,
|
||||||
onIsoChanged: (value) => context.read<MeteringBloc>().add(IsoChangedEvent(value)),
|
onIsoChanged: (value) => context.read<MeteringBloc>().add(IsoChangedEvent(value)),
|
||||||
|
onNdChanged: (value) => context.read<MeteringBloc>().add(NdChangedEvent(value)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import 'package:lightmeter/models/exposure_pair.dart';
|
import 'package:lightmeter/models/exposure_pair.dart';
|
||||||
import 'package:lightmeter/models/photography_value.dart';
|
import 'package:lightmeter/models/iso_value.dart';
|
||||||
|
import 'package:lightmeter/models/nd_value.dart';
|
||||||
|
|
||||||
class MeteringState {
|
class MeteringState {
|
||||||
final double ev;
|
final double ev;
|
||||||
final double evCompensation;
|
final double evCompensation;
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final double nd;
|
final NdValue nd;
|
||||||
final List<ExposurePair> exposurePairs;
|
final List<ExposurePair> exposurePairs;
|
||||||
|
|
||||||
const MeteringState({
|
const MeteringState({
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
double log2(double x) => log(x) / log(2);
|
double log2(num x) => log(x) / log(2);
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
import 'package:lightmeter/models/aperture_value.dart';
|
||||||
|
import 'package:lightmeter/models/iso_value.dart';
|
||||||
import 'package:lightmeter/models/photography_value.dart';
|
import 'package:lightmeter/models/photography_value.dart';
|
||||||
|
import 'package:lightmeter/models/shutter_speed_value.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
Loading…
Reference in a new issue