mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 15:00: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"),
|
||||
"keepsScreenOn":
|
||||
MessageLookupByLibrary.simpleMessage("Keeps screen on"),
|
||||
"nd": MessageLookupByLibrary.simpleMessage("ND"),
|
||||
"none": MessageLookupByLibrary.simpleMessage("None"),
|
||||
"openSettings": MessageLookupByLibrary.simpleMessage("Open settings"),
|
||||
"permissionNeeded":
|
||||
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`
|
||||
String get cancel {
|
||||
return Intl.message(
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
"fastestExposurePair": "Fastest",
|
||||
"slowestExposurePair": "Slowest",
|
||||
"iso": "ISO",
|
||||
"nd": "ND",
|
||||
"none": "None",
|
||||
"cancel": "Cancel",
|
||||
"select": "Select",
|
||||
"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);
|
||||
|
||||
@override
|
||||
double get value => rawValue;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer("f/");
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'photography_value.dart';
|
||||
import 'aperture_value.dart';
|
||||
import 'shutter_speed_value.dart';
|
||||
|
||||
class ExposurePair {
|
||||
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);
|
||||
|
||||
@override
|
||||
int get value => rawValue;
|
||||
|
||||
@override
|
||||
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 }
|
||||
|
||||
abstract class PhotographyValue<T> {
|
||||
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) {
|
||||
switch (stopType) {
|
||||
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;
|
||||
|
||||
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/res/dimens.dart';
|
||||
|
||||
class ExposurePaitListItem<T extends PhotographyValue> extends StatelessWidget {
|
||||
class ExposurePaitListItem<T extends PhotographyStopValue> extends StatelessWidget {
|
||||
final T value;
|
||||
final bool tickOnTheLeft;
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.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/res/dimens.dart';
|
||||
|
||||
|
@ -12,13 +14,15 @@ import 'models/reading_value.dart';
|
|||
class MeteringTopBar extends StatelessWidget {
|
||||
static const _columnsCount = 3;
|
||||
final _isoDialogKey = GlobalKey<AnimatedDialogState>();
|
||||
final _ndDialogKey = GlobalKey<AnimatedDialogState>();
|
||||
|
||||
final ExposurePair? fastest;
|
||||
final ExposurePair? slowest;
|
||||
final double ev;
|
||||
final IsoValue iso;
|
||||
final double nd;
|
||||
final NdValue nd;
|
||||
final ValueChanged<IsoValue> onIsoChanged;
|
||||
final ValueChanged<NdValue> onNdChanged;
|
||||
|
||||
MeteringTopBar({
|
||||
required this.fastest,
|
||||
|
@ -27,6 +31,7 @@ class MeteringTopBar extends StatelessWidget {
|
|||
required this.iso,
|
||||
required this.nd,
|
||||
required this.onIsoChanged,
|
||||
required this.onNdChanged,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
@ -137,10 +142,28 @@ class MeteringTopBar extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
const _InnerPadding(),
|
||||
ReadingContainer.singleValue(
|
||||
value: ReadingValue(
|
||||
label: 'ND',
|
||||
value: nd.toString(),
|
||||
AnimatedDialog(
|
||||
key: _ndDialogKey,
|
||||
closedChild: ReadingContainer.singleValue(
|
||||
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 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:lightmeter/models/aperture_value.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/shutter_speed_value.dart';
|
||||
import 'package:lightmeter/utils/log_2.dart';
|
||||
|
||||
import 'metering_event.dart';
|
||||
|
@ -21,11 +25,12 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
|||
iso: isoValues.where((element) => element.value == 100).first,
|
||||
ev: 21.3,
|
||||
evCompensation: 0.0,
|
||||
nd: 0.0,
|
||||
nd: ndValues.first,
|
||||
exposurePairs: [],
|
||||
),
|
||||
) {
|
||||
on<IsoChangedEvent>(_onIsoChanged);
|
||||
on<NdChangedEvent>(_onNdChanged);
|
||||
on<MeasureEvent>(_onMeasure);
|
||||
|
||||
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
|
||||
void _onMeasure(_, Emitter emit) {
|
||||
double log2(double x) => log(x) / log(2);
|
||||
|
||||
final aperture = _apertureValues[_random.nextInt(_apertureValues.length)];
|
||||
final shutterSpeed = _shutterSpeedValues[_random.nextInt(_shutterSpeedValues.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 {
|
||||
const MeteringEvent();
|
||||
|
@ -10,6 +11,12 @@ class IsoChangedEvent extends MeteringEvent {
|
|||
const IsoChangedEvent(this.isoValue);
|
||||
}
|
||||
|
||||
class NdChangedEvent extends MeteringEvent {
|
||||
final NdValue ndValue;
|
||||
|
||||
const NdChangedEvent(this.ndValue);
|
||||
}
|
||||
|
||||
class MeasureEvent extends MeteringEvent {
|
||||
const MeasureEvent();
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ class _MeteringScreenState extends State<MeteringScreen> {
|
|||
iso: state.iso,
|
||||
nd: state.nd,
|
||||
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/photography_value.dart';
|
||||
import 'package:lightmeter/models/iso_value.dart';
|
||||
import 'package:lightmeter/models/nd_value.dart';
|
||||
|
||||
class MeteringState {
|
||||
final double ev;
|
||||
final double evCompensation;
|
||||
final IsoValue iso;
|
||||
final double nd;
|
||||
final NdValue nd;
|
||||
final List<ExposurePair> exposurePairs;
|
||||
|
||||
const MeteringState({
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
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/shutter_speed_value.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
|
|
Loading…
Reference in a new issue