diff --git a/.vscode/launch.json b/.vscode/launch.json index db52a43..fb960be 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,6 @@ "name": "dev (android)", "request": "launch", "type": "dart", - //"flutterMode": "profile", "args": [ "--flavor", "dev", @@ -21,7 +20,6 @@ "name": "dev (ios)", "request": "launch", "type": "dart", - //"flutterMode": "release", "args": [ "--flavor", "dev", diff --git a/android/app/build.gradle b/android/app/build.gradle index 76d7f8b..08105f1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') @@ -33,6 +33,10 @@ apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +gradle.beforeProject({ project-> + project.setProperty("target-platform", "android-arm,android-arm64") +}) + android { compileSdkVersion 33 ndkVersion flutter.ndkVersion @@ -53,8 +57,7 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion 33 - ndk.abiFilters 'arm64-v8a', 'armeabi-v7a' - targetSdkVersion flutter.targetSdkVersion + ndk.abiFilters 'armeabi-v7a', 'arm64-v8a' /// legacy material-lightmeter ap stopped updating after 60022 /// 7xxxx means that it is a new app versionCode 70000 + flutterVersionCode.toInteger() @@ -92,7 +95,7 @@ android { signingConfig signingConfigs.release minifyEnabled true shrinkResources true - ndk.abiFilters 'arm64-v8a', 'armeabi-v7a' + ndk.abiFilters 'armeabi-v7a', 'arm64-v8a' } } } diff --git a/android/build.gradle b/android/build.gradle index e0630bc..2a1e6ed 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -28,6 +28,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/lib/data/haptics_service.dart b/lib/data/haptics_service.dart index 8d36e32..e27a6aa 100644 --- a/lib/data/haptics_service.dart +++ b/lib/data/haptics_service.dart @@ -7,9 +7,11 @@ class HapticsService { Future responseVibration() async => _tryVibrate(duration: 50, amplitude: 128); + Future errorVibration() async => _tryVibrate(duration: 100, amplitude: 128); + Future _tryVibrate({required int duration, required int amplitude}) async { if (await _canVibrate()) { - Vibration.vibrate( + await Vibration.vibrate( duration: duration, amplitude: amplitude, ); diff --git a/lib/interactors/metering_interactor.dart b/lib/interactors/metering_interactor.dart index 0134b34..2cf1fc9 100644 --- a/lib/interactors/metering_interactor.dart +++ b/lib/interactors/metering_interactor.dart @@ -4,8 +4,10 @@ import 'package:app_settings/app_settings.dart'; import 'package:lightmeter/data/caffeine_service.dart'; import 'package:lightmeter/data/haptics_service.dart'; import 'package:lightmeter/data/light_sensor_service.dart'; +import 'package:lightmeter/data/models/film.dart'; import 'package:lightmeter/data/permissions_service.dart'; import 'package:lightmeter/data/shared_prefs_service.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:permission_handler/permission_handler.dart'; class MeteringInteractor { @@ -30,16 +32,28 @@ class MeteringInteractor { double get cameraEvCalibration => _userPreferencesService.cameraEvCalibration; double get lightSensorEvCalibration => _userPreferencesService.lightSensorEvCalibration; - bool get isHapticsEnabled => _userPreferencesService.haptics; + IsoValue get iso => _userPreferencesService.iso; + set iso(IsoValue value) => _userPreferencesService.iso = value; + + NdValue get ndFilter => _userPreferencesService.ndFilter; + set ndFilter(NdValue value) => _userPreferencesService.ndFilter = value; + + Film get film => _userPreferencesService.film; + set film(Film value) => _userPreferencesService.film = value; /// Executes vibration if haptics are enabled in settings - void quickVibration() { - if (_userPreferencesService.haptics) _hapticsService.quickVibration(); + Future quickVibration() async { + if (_userPreferencesService.haptics) await _hapticsService.quickVibration(); } /// Executes vibration if haptics are enabled in settings - void responseVibration() { - if (_userPreferencesService.haptics) _hapticsService.responseVibration(); + Future responseVibration() async { + if (_userPreferencesService.haptics) await _hapticsService.responseVibration(); + } + + /// Executes vibration if haptics are enabled in settings + Future errorVibration() async { + if (_userPreferencesService.haptics) await _hapticsService.errorVibration(); } Future checkCameraPermission() async { diff --git a/lib/screens/metering/bloc_metering.dart b/lib/screens/metering/bloc_metering.dart index 902f6af..1b52882 100644 --- a/lib/screens/metering/bloc_metering.dart +++ b/lib/screens/metering/bloc_metering.dart @@ -4,7 +4,6 @@ import 'dart:math'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lightmeter/data/models/exposure_pair.dart'; import 'package:lightmeter/data/models/film.dart'; -import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/interactors/metering_interactor.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' @@ -17,7 +16,6 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; class MeteringBloc extends Bloc { final MeteringCommunicationBloc _communicationBloc; - final UserPreferencesService _userPreferencesService; final MeteringInteractor _meteringInteractor; late final StreamSubscription _communicationSubscription; @@ -29,25 +27,25 @@ class MeteringBloc extends Bloc { EquipmentProfileData _equipmentProfileData; StopType stopType; - late IsoValue _iso = _userPreferencesService.iso; - late NdValue _nd = _userPreferencesService.ndFilter; - late Film _film = _userPreferencesService.film; - double _ev100 = 0.0; + late IsoValue _iso = _meteringInteractor.iso; + late NdValue _nd = _meteringInteractor.ndFilter; + late Film _film = _meteringInteractor.film; + double? _ev100 = 0.0; bool _isMeteringInProgress = false; MeteringBloc( this._communicationBloc, - this._userPreferencesService, this._meteringInteractor, this._equipmentProfileData, this.stopType, ) : super( - MeteringEndedState( + MeteringDataState( ev: 0.0, - film: _userPreferencesService.film, - iso: _userPreferencesService.iso, - nd: _userPreferencesService.ndFilter, + film: _meteringInteractor.film, + iso: _meteringInteractor.iso, + nd: _meteringInteractor.ndFilter, exposurePairs: const [], + continuousMetering: false, ), ) { _communicationSubscription = _communicationBloc.stream @@ -62,6 +60,7 @@ class MeteringBloc extends Bloc { on(_onNdChanged); on(_onMeasure); on(_onMeasured); + on(_onMeasureError); } @override @@ -73,13 +72,13 @@ class MeteringBloc extends Bloc { void _onCommunicationState(communication_states.ScreenState communicationState) { if (communicationState is communication_states.MeasuredState) { _isMeteringInProgress = communicationState is communication_states.MeteringInProgressState; - add(MeasuredEvent(communicationState.ev100)); + _handleEv100(communicationState.ev100); } } void _onStopTypeChanged(StopTypeChangedEvent event, Emitter emit) { stopType = event.stopType; - _emitMeasuredState(emit); + _updateMeasurements(); } void _onEquipmentProfileChanged(EquipmentProfileChangedEvent event, Emitter emit) { @@ -88,17 +87,17 @@ class MeteringBloc extends Bloc { /// Update selected ISO value, if selected equipment profile /// doesn't contain currently selected value if (!event.equipmentProfileData.isoValues.any((v) => _iso.value == v.value)) { - _userPreferencesService.iso = event.equipmentProfileData.isoValues.first; + _meteringInteractor.iso = event.equipmentProfileData.isoValues.first; _iso = event.equipmentProfileData.isoValues.first; } /// The same for ND filter if (!event.equipmentProfileData.ndValues.any((v) => _nd.value == v.value)) { - _userPreferencesService.ndFilter = event.equipmentProfileData.ndValues.first; + _meteringInteractor.ndFilter = event.equipmentProfileData.ndValues.first; _nd = event.equipmentProfileData.ndValues.first; } - _emitMeasuredState(emit); + _updateMeasurements(); } void _onFilmChanged(FilmChangedEvent event, Emitter emit) { @@ -110,56 +109,76 @@ class MeteringBloc extends Bloc { add(IsoChangedEvent(newIso)); } _film = event.data; - _userPreferencesService.film = event.data; - _emitMeasuredState(emit); + _meteringInteractor.film = event.data; + _updateMeasurements(); } void _onIsoChanged(IsoChangedEvent event, Emitter emit) { if (event.isoValue.value != _film.iso) { _film = Film.values.first; } - _userPreferencesService.iso = event.isoValue; + _meteringInteractor.iso = event.isoValue; _iso = event.isoValue; - _emitMeasuredState(emit); + _updateMeasurements(); } void _onNdChanged(NdChangedEvent event, Emitter emit) { - _userPreferencesService.ndFilter = event.ndValue; + _meteringInteractor.ndFilter = event.ndValue; _nd = event.ndValue; - _emitMeasuredState(emit); + _updateMeasurements(); } - void _onMeasure(_, Emitter emit) { + void _onMeasure(MeasureEvent _, Emitter emit) { _meteringInteractor.quickVibration(); _communicationBloc.add(const communication_events.MeasureEvent()); _isMeteringInProgress = true; - emit(const LoadingState()); + emit( + LoadingState( + film: _film, + iso: _iso, + nd: _nd, + ), + ); + } + + void _updateMeasurements() => _handleEv100(_ev100); + + void _handleEv100(double? ev100) { + if (ev100 == null || ev100.isNaN || ev100.isInfinite) { + add(const MeasureErrorEvent()); + } else { + add(MeasuredEvent(ev100)); + } } void _onMeasured(MeasuredEvent event, Emitter emit) { _meteringInteractor.responseVibration(); _ev100 = event.ev100; - _emitMeasuredState(emit); + final ev = event.ev100 + log2(_iso.value / 100) - _nd.stopReduction; + emit( + MeteringDataState( + ev: ev, + film: _film, + iso: _iso, + nd: _nd, + exposurePairs: _buildExposureValues(ev), + continuousMetering: _isMeteringInProgress, + ), + ); } - void _emitMeasuredState(Emitter emit) { - final ev = _ev100 + log2(_iso.value / 100) - _nd.stopReduction; + void _onMeasureError(MeasureErrorEvent _, Emitter emit) { + _meteringInteractor.errorVibration(); + _ev100 = null; emit( - _isMeteringInProgress - ? MeteringInProgressState( - ev: ev, - film: _film, - iso: _iso, - nd: _nd, - exposurePairs: _buildExposureValues(ev), - ) - : MeteringEndedState( - ev: ev, - film: _film, - iso: _iso, - nd: _nd, - exposurePairs: _buildExposureValues(ev), - ), + MeteringDataState( + ev: null, + film: _film, + iso: _iso, + nd: _nd, + exposurePairs: const [], + continuousMetering: _isMeteringInProgress, + ), ); } diff --git a/lib/screens/metering/communication/event_communication_metering.dart b/lib/screens/metering/communication/event_communication_metering.dart index 6c4ce11..7c00173 100644 --- a/lib/screens/metering/communication/event_communication_metering.dart +++ b/lib/screens/metering/communication/event_communication_metering.dart @@ -15,7 +15,7 @@ class MeasureEvent extends ScreenEvent { } abstract class MeasuredEvent extends SourceEvent { - final double ev100; + final double? ev100; const MeasuredEvent(this.ev100); } diff --git a/lib/screens/metering/communication/state_communication_metering.dart b/lib/screens/metering/communication/state_communication_metering.dart index e60ed67..06bedaf 100644 --- a/lib/screens/metering/communication/state_communication_metering.dart +++ b/lib/screens/metering/communication/state_communication_metering.dart @@ -19,7 +19,7 @@ class MeasureState extends SourceState { } abstract class MeasuredState extends ScreenState { - final double ev100; + final double? ev100; const MeasuredState(this.ev100); } diff --git a/lib/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart b/lib/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart index 3ea6d1f..80819ca 100644 --- a/lib/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart +++ b/lib/screens/metering/components/bottom_controls/components/measure_button/widget_button_measure.dart @@ -6,11 +6,13 @@ import 'package:lightmeter/screens/shared/filled_circle/widget_circle_filled.dar class MeteringMeasureButton extends StatefulWidget { final double? ev; final bool isMetering; + final bool hasError; final VoidCallback onTap; const MeteringMeasureButton({ required this.ev, required this.isMetering, + required this.hasError, required this.onTap, super.key, }); @@ -33,7 +35,7 @@ class _MeteringMeasureButtonState extends State { @override Widget build(BuildContext context) { return IgnorePointer( - ignoring: widget.isMetering && widget.ev == null, + ignoring: widget.isMetering && widget.ev == null && !widget.hasError, child: GestureDetector( onTap: widget.onTap, onTapDown: (_) { @@ -63,7 +65,13 @@ class _MeteringMeasureButtonState extends State { color: Theme.of(context).colorScheme.onSurface, size: Dimens.grid72 - Dimens.grid8, child: Center( - child: widget.ev != null ? _EvValueText(ev: widget.ev!) : null, + child: widget.hasError + ? Icon( + Icons.error_outline, + color: Theme.of(context).colorScheme.surface, + size: Dimens.grid24, + ) + : (widget.ev != null ? _EvValueText(ev: widget.ev!) : null), ), ), ), @@ -91,13 +99,6 @@ class _EvValueText extends StatelessWidget { @override Widget build(BuildContext context) { - if (ev.isNaN || ev.isInfinite) { - return Icon( - Icons.error, - color: Theme.of(context).colorScheme.surface, - ); - } - final theme = Theme.of(context); return Text( '${ev.toStringAsFixed(1)}\n${S.of(context).ev}', diff --git a/lib/screens/metering/components/bottom_controls/provider_bottom_controls.dart b/lib/screens/metering/components/bottom_controls/provider_bottom_controls.dart index dd4a9be..4d07889 100644 --- a/lib/screens/metering/components/bottom_controls/provider_bottom_controls.dart +++ b/lib/screens/metering/components/bottom_controls/provider_bottom_controls.dart @@ -6,6 +6,7 @@ import 'package:lightmeter/screens/metering/components/bottom_controls/widget_bo class MeteringBottomControlsProvider extends StatelessWidget { final double? ev; final bool isMetering; + final bool hasError; final VoidCallback? onSwitchEvSourceType; final VoidCallback onMeasure; final VoidCallback onSettings; @@ -13,6 +14,7 @@ class MeteringBottomControlsProvider extends StatelessWidget { const MeteringBottomControlsProvider({ required this.ev, required this.isMetering, + required this.hasError, required this.onSwitchEvSourceType, required this.onMeasure, required this.onSettings, @@ -36,6 +38,7 @@ class MeteringBottomControlsProvider extends StatelessWidget { child: MeteringBottomControls( ev: ev, isMetering: isMetering, + hasError: hasError, onSwitchEvSourceType: onSwitchEvSourceType, onMeasure: onMeasure, onSettings: onSettings, diff --git a/lib/screens/metering/components/bottom_controls/widget_bottom_controls.dart b/lib/screens/metering/components/bottom_controls/widget_bottom_controls.dart index f059b8f..13a3892 100644 --- a/lib/screens/metering/components/bottom_controls/widget_bottom_controls.dart +++ b/lib/screens/metering/components/bottom_controls/widget_bottom_controls.dart @@ -7,6 +7,7 @@ import 'package:provider/provider.dart'; class MeteringBottomControls extends StatelessWidget { final double? ev; final bool isMetering; + final bool hasError; final VoidCallback? onSwitchEvSourceType; final VoidCallback onMeasure; final VoidCallback onSettings; @@ -14,6 +15,7 @@ class MeteringBottomControls extends StatelessWidget { const MeteringBottomControls({ required this.ev, required this.isMetering, + required this.hasError, required this.onSwitchEvSourceType, required this.onMeasure, required this.onSettings, @@ -54,6 +56,7 @@ class MeteringBottomControls extends StatelessWidget { MeteringMeasureButton( ev: ev, isMetering: isMetering, + hasError: hasError, onTap: onMeasure, ), Expanded( diff --git a/lib/screens/metering/components/camera_container/bloc_container_camera.dart b/lib/screens/metering/components/camera_container/bloc_container_camera.dart index 6d0f88a..0d5fb63 100644 --- a/lib/screens/metering/components/camera_container/bloc_container_camera.dart +++ b/lib/screens/metering/components/camera_container/bloc_container_camera.dart @@ -1,6 +1,7 @@ import 'dart:async'; +import 'dart:developer'; import 'dart:io'; -import 'dart:math'; +import 'dart:math' as math; import 'dart:typed_data'; import 'package:camera/camera.dart'; @@ -34,7 +35,7 @@ class CameraContainerBloc extends EvSourceBlocBase([ _cameraController!.getMinZoomLevel(), _cameraController!.getMaxZoomLevel(), - ]).then((levels) => RangeValues(levels[0], min(_maxZoom, levels[1]))); + ]).then((levels) => RangeValues(levels[0], math.min(_maxZoom, levels[1]))); _currentZoom = _zoomRange!.start; _exposureOffsetRange = await Future.wait([ @@ -126,8 +132,8 @@ class CameraContainerBloc extends EvSourceBlocBase RangeValues( - max(_exposureMaxRange.start, levels[0]), - min(_exposureMaxRange.end, levels[1]), + math.max(_exposureMaxRange.start, levels[0]), + math.min(_exposureMaxRange.end, levels[1]), ), ); await _cameraController!.getExposureOffsetStepSize().then((value) { @@ -172,28 +178,31 @@ class CameraContainerBloc extends EvSourceBlocBase _takePhoto() async { - if (_cameraController == null || - !_cameraController!.value.isInitialized || - _cameraController!.value.isTakingPicture) { - return null; - } + bool get _canTakePhoto => !(_cameraController == null || + !_cameraController!.value.isInitialized || + _cameraController!.value.isTakingPicture); + Future _takePhoto() async { try { final file = await _cameraController!.takePicture(); final Uint8List bytes = await file.readAsBytes(); Directory(file.path).deleteSync(recursive: true); final tags = await readExifFromBytes(bytes); - final iso = double.parse("${tags["EXIF ISOSpeedRatings"]}"); - final apertureValueRatio = (tags["EXIF FNumber"]!.values as IfdRatios).ratios.first; + final iso = double.tryParse("${tags["EXIF ISOSpeedRatings"]}"); + final apertureValueRatio = (tags["EXIF FNumber"]?.values as IfdRatios?)?.ratios.first; + final speedValueRatio = (tags["EXIF ExposureTime"]?.values as IfdRatios?)?.ratios.first; + if (iso == null || apertureValueRatio == null || speedValueRatio == null) { + log('Error parsing EXIF: ${tags.keys}'); + return null; + } + final aperture = apertureValueRatio.numerator / apertureValueRatio.denominator; - final speedValueRatio = (tags["EXIF ExposureTime"]!.values as IfdRatios).ratios.first; final speed = speedValueRatio.numerator / speedValueRatio.denominator; - return log2(pow(aperture, 2)) - log2(speed) - log2(iso / 100); + return log2(math.pow(aperture, 2)) - log2(speed) - log2(iso / 100); } on CameraException catch (e) { - debugPrint('Error: ${e.code}\nError Message: ${e.description}'); + log('Error: ${e.code}\nError Message: ${e.description}'); return null; } } diff --git a/lib/screens/metering/components/shared/readings_container/components/animated_dialog_picker/widget_picker_dialog_animated.dart b/lib/screens/metering/components/shared/readings_container/components/animated_dialog_picker/widget_picker_dialog_animated.dart index 55923c8..d123d99 100644 --- a/lib/screens/metering/components/shared/readings_container/components/animated_dialog_picker/widget_picker_dialog_animated.dart +++ b/lib/screens/metering/components/shared/readings_container/components/animated_dialog_picker/widget_picker_dialog_animated.dart @@ -3,8 +3,9 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart'; import 'package:lightmeter/screens/metering/components/shared/readings_container/components/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.dart'; -class AnimatedDialogPicker extends StatelessWidget { - final _key = GlobalKey(); +// Has to be stateful, so that [GlobalKey] is not recreated. +// Otherwise use will no be able to close the dialog after EV value has changed. +class AnimatedDialogPicker extends StatefulWidget { final IconData icon; final String title; final String? subtitle; @@ -15,7 +16,7 @@ class AnimatedDialogPicker extends StatelessWidget { final ValueChanged onChanged; final Widget closedChild; - AnimatedDialogPicker({ + const AnimatedDialogPicker({ required this.icon, required this.title, this.subtitle, @@ -28,24 +29,31 @@ class AnimatedDialogPicker extends StatelessWidget { super.key, }); + @override + State> createState() => _AnimatedDialogPickerState(); +} + +class _AnimatedDialogPickerState extends State> { + final _key = GlobalKey(); + @override Widget build(BuildContext context) { return AnimatedDialog( key: _key, - closedChild: closedChild, + closedChild: widget.closedChild, openedChild: DialogPicker( - icon: icon, - title: title, - subtitle: subtitle, - initialValue: selectedValue, - values: values, - itemTitleBuilder: itemTitleBuilder, - itemTrailingBuilder: itemTrailingBuilder, + icon: widget.icon, + title: widget.title, + subtitle: widget.subtitle, + initialValue: widget.selectedValue, + values: widget.values, + itemTitleBuilder: widget.itemTitleBuilder, + itemTrailingBuilder: widget.itemTrailingBuilder, onCancel: () { _key.currentState?.close(); }, onSelect: (value) { - _key.currentState?.close().then((_) => onChanged(value)); + _key.currentState?.close().then((_) => widget.onChanged(value)); }, ), ); diff --git a/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart b/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart index 0e517f7..9edf2e7 100644 --- a/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart +++ b/lib/screens/metering/components/shared/readings_container/widget_container_readings.dart @@ -11,7 +11,6 @@ import 'package:lightmeter/screens/metering/components/shared/readings_container import 'package:lightmeter/screens/metering/components/shared/readings_container/components/reading_value_container/widget_container_reading_value.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; -/// Contains a column of fastest & slowest exposure pairs + a row of ISO and ND pickers class ReadingsContainer extends StatelessWidget { final ExposurePair? fastest; final ExposurePair? slowest; diff --git a/lib/screens/metering/event_metering.dart b/lib/screens/metering/event_metering.dart index 6a9abc6..888bea1 100644 --- a/lib/screens/metering/event_metering.dart +++ b/lib/screens/metering/event_metering.dart @@ -44,3 +44,7 @@ class MeasuredEvent extends MeteringEvent { const MeasuredEvent(this.ev100); } + +class MeasureErrorEvent extends MeteringEvent { + const MeasureErrorEvent(); +} diff --git a/lib/screens/metering/flow_metering.dart b/lib/screens/metering/flow_metering.dart index 88b38ad..3f830c2 100644 --- a/lib/screens/metering/flow_metering.dart +++ b/lib/screens/metering/flow_metering.dart @@ -37,7 +37,6 @@ class _MeteringFlowState extends State { BlocProvider( create: (context) => MeteringBloc( context.read(), - context.read(), context.read(), EquipmentProfile.of(context, listen: false), context.read(), diff --git a/lib/screens/metering/screen_metering.dart b/lib/screens/metering/screen_metering.dart index b1a2d9c..f3c6b22 100644 --- a/lib/screens/metering/screen_metering.dart +++ b/lib/screens/metering/screen_metering.dart @@ -44,26 +44,25 @@ class _MeteringScreenState extends State { children: [ Expanded( child: BlocBuilder( - buildWhen: (_, current) => current is MeteringDataState, - builder: (_, state) => state is MeteringDataState - ? _MeteringContainerBuidler( - fastest: state.fastest, - slowest: state.slowest, - film: state.film, - iso: state.iso, - nd: state.nd, - onFilmChanged: (value) => _bloc.add(FilmChangedEvent(value)), - onIsoChanged: (value) => _bloc.add(IsoChangedEvent(value)), - onNdChanged: (value) => _bloc.add(NdChangedEvent(value)), - exposurePairs: state.exposurePairs, - ) - : const SizedBox.shrink(), + builder: (_, state) => _MeteringContainerBuidler( + fastest: state is MeteringDataState ? state.fastest : null, + slowest: state is MeteringDataState ? state.slowest : null, + exposurePairs: state is MeteringDataState ? state.exposurePairs : [], + film: state.film, + iso: state.iso, + nd: state.nd, + onFilmChanged: (value) => _bloc.add(FilmChangedEvent(value)), + onIsoChanged: (value) => _bloc.add(IsoChangedEvent(value)), + onNdChanged: (value) => _bloc.add(NdChangedEvent(value)), + ), ), ), BlocBuilder( builder: (context, state) => MeteringBottomControlsProvider( ev: state is MeteringDataState ? state.ev : null, - isMetering: state is LoadingState || state is MeteringInProgressState, + isMetering: + state is LoadingState || state is MeteringDataState && state.continuousMetering, + hasError: state is MeteringDataState && state.hasError, onSwitchEvSourceType: context.read().hasLightSensor ? EvSourceTypeProvider.of(context).toggleType : null, diff --git a/lib/screens/metering/state_metering.dart b/lib/screens/metering/state_metering.dart index 7016374..52dcf7a 100644 --- a/lib/screens/metering/state_metering.dart +++ b/lib/screens/metering/state_metering.dart @@ -5,48 +5,40 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; @immutable abstract class MeteringState { - const MeteringState(); -} - -class LoadingState extends MeteringState { - const LoadingState(); -} - -abstract class MeteringDataState extends MeteringState { - final double ev; final Film film; final IsoValue iso; final NdValue nd; - final List exposurePairs; - const MeteringDataState({ - required this.ev, + const MeteringState({ required this.film, required this.iso, required this.nd, + }); +} + +class LoadingState extends MeteringState { + const LoadingState({ + required super.film, + required super.iso, + required super.nd, + }); +} + +class MeteringDataState extends MeteringState { + final double? ev; + final List exposurePairs; + final bool continuousMetering; + + const MeteringDataState({ + required this.ev, + required super.film, + required super.iso, + required super.nd, required this.exposurePairs, + required this.continuousMetering, }); ExposurePair? get fastest => exposurePairs.isEmpty ? null : exposurePairs.first; ExposurePair? get slowest => exposurePairs.isEmpty ? null : exposurePairs.last; -} - -class MeteringInProgressState extends MeteringDataState { - const MeteringInProgressState({ - required super.ev, - required super.film, - required super.iso, - required super.nd, - required super.exposurePairs, - }); -} - -class MeteringEndedState extends MeteringDataState { - const MeteringEndedState({ - required super.ev, - required super.film, - required super.iso, - required super.nd, - required super.exposurePairs, - }); + bool get hasError => ev == null; } diff --git a/pubspec.yaml b/pubspec.yaml index 742dde6..85e08b9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: url: "https://github.com/vodemn/m3_lightmeter_resources" ref: main material_color_utilities: 0.2.0 - package_info_plus: 3.0.2 + package_info_plus: 4.0.0 permission_handler: 10.2.0 provider: 6.0.4 shared_preferences: 2.0.15