added calibration for light sensor

This commit is contained in:
Vadim 2023-01-29 19:01:15 +03:00
parent c777bdb68e
commit 2dc96e5c17
16 changed files with 95 additions and 29 deletions

View file

@ -11,6 +11,7 @@ class UserPreferencesService {
static const _evSourceTypeKey = "evSourceType"; static const _evSourceTypeKey = "evSourceType";
static const _cameraEvCalibrationKey = "cameraEvCalibration"; static const _cameraEvCalibrationKey = "cameraEvCalibration";
static const _lightSensorEvCalibrationKey = "lightSensorEvCalibration";
static const _hapticsKey = "haptics"; static const _hapticsKey = "haptics";
static const _themeTypeKey = "themeType"; static const _themeTypeKey = "themeType";
@ -35,6 +36,9 @@ class UserPreferencesService {
double get cameraEvCalibration => _sharedPreferences.getDouble(_cameraEvCalibrationKey) ?? 0.0; double get cameraEvCalibration => _sharedPreferences.getDouble(_cameraEvCalibrationKey) ?? 0.0;
set cameraEvCalibration(double value) => _sharedPreferences.setDouble(_cameraEvCalibrationKey, value); set cameraEvCalibration(double value) => _sharedPreferences.setDouble(_cameraEvCalibrationKey, value);
double get lightSensorEvCalibration => _sharedPreferences.getDouble(_lightSensorEvCalibrationKey) ?? 0.0;
set lightSensorEvCalibration(double value) => _sharedPreferences.setDouble(_lightSensorEvCalibrationKey, value);
ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(_themeTypeKey) ?? 0]; ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(_themeTypeKey) ?? 0];
set themeType(ThemeType value) => _sharedPreferences.setInt(_themeTypeKey, value.index); set themeType(ThemeType value) => _sharedPreferences.setInt(_themeTypeKey, value.index);

View file

@ -16,6 +16,7 @@ class MeteringInteractor {
); );
double get cameraEvCalibration => _userPreferencesService.cameraEvCalibration; double get cameraEvCalibration => _userPreferencesService.cameraEvCalibration;
double get lightSensorEvCalibration => _userPreferencesService.lightSensorEvCalibration;
bool get isHapticsEnabled => _userPreferencesService.haptics; bool get isHapticsEnabled => _userPreferencesService.haptics;

View file

@ -13,6 +13,9 @@ class SettingsInteractor {
double get cameraEvCalibration => _userPreferencesService.cameraEvCalibration; double get cameraEvCalibration => _userPreferencesService.cameraEvCalibration;
void setCameraEvCalibration(double value) => _userPreferencesService.cameraEvCalibration = value; void setCameraEvCalibration(double value) => _userPreferencesService.cameraEvCalibration = value;
double get lightSensorEvCalibration => _userPreferencesService.lightSensorEvCalibration;
void setLightSensorEvCalibration(double value) => _userPreferencesService.lightSensorEvCalibration = value;
bool get isHapticsEnabled => _userPreferencesService.haptics; bool get isHapticsEnabled => _userPreferencesService.haptics;
/// Executes vibration if haptics are enabled in settings /// Executes vibration if haptics are enabled in settings

View file

@ -30,6 +30,7 @@
"calibration": "Calibration", "calibration": "Calibration",
"calibrationMessage": "The accuracy of the readings measured by this application depends entirely on the hardware of the device. Therefore, consider testing this application and setting up an EV calibration value that will give you the desired measurement results.", "calibrationMessage": "The accuracy of the readings measured by this application depends entirely on the hardware of the device. Therefore, consider testing this application and setting up an EV calibration value that will give you the desired measurement results.",
"camera": "Camera", "camera": "Camera",
"lightSensor": "Light sensor",
"general": "General", "general": "General",
"haptics": "Haptics", "haptics": "Haptics",
"theme": "Theme", "theme": "Theme",

View file

@ -6,7 +6,9 @@ import 'state_communication_metering.dart';
class MeteringCommunicationBloc class MeteringCommunicationBloc
extends Bloc<MeteringCommunicationEvent, MeteringCommunicationState> { extends Bloc<MeteringCommunicationEvent, MeteringCommunicationState> {
MeteringCommunicationBloc() : super(const InitState()) { MeteringCommunicationBloc() : super(const InitState()) {
on<MeasureEvent>((_, emit) => emit(const MeasureState())); // `MeasureState` is not const, so that `Bloc` treats each state as new and updates state stream
// ignore: prefer_const_constructors
on<MeasureEvent>((_, emit) => emit(MeasureState()));
on<MeasuredEvent>((event, emit) => emit(MeasuredState(event.ev100))); on<MeasuredEvent>((event, emit) => emit(MeasuredState(event.ev100)));
} }
} }

View file

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:lightmeter/data/models/ev_source_type.dart';
import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/res/dimens.dart';
import 'package:provider/provider.dart';
import 'components/widget_button_measure.dart'; import 'components/widget_button_measure.dart';
import 'components/widget_button_secondary.dart'; import 'components/widget_button_secondary.dart';
@ -36,7 +38,9 @@ class MeteringBottomControls extends StatelessWidget {
Expanded( Expanded(
child: MeteringSecondaryButton( child: MeteringSecondaryButton(
onPressed: onSwitchEvSourceType!, onPressed: onSwitchEvSourceType!,
icon: Icons.sync, icon: context.watch<EvSourceType>() != EvSourceType.camera
? Icons.camera_rear
: Icons.wb_incandescent,
), ),
) )
else else

View file

@ -34,8 +34,8 @@ class CameraContainerBloc extends EvSourceBlocBase<CameraContainerEvent, CameraC
double _currentExposureOffset = 0.0; double _currentExposureOffset = 0.0;
CameraContainerBloc( CameraContainerBloc(
MeteringCommunicationBloc communicationBloc,
this._meteringInteractor, this._meteringInteractor,
MeteringCommunicationBloc communicationBloc,
) : super( ) : super(
communicationBloc, communicationBloc,
const CameraInitState(), const CameraInitState(),

View file

@ -33,8 +33,8 @@ class CameraContainerProvider extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => CameraContainerBloc( create: (context) => CameraContainerBloc(
context.read<MeteringCommunicationBloc>(),
context.read<MeteringInteractor>(), context.read<MeteringInteractor>(),
context.read<MeteringCommunicationBloc>(),
), ),
child: CameraContainer( child: CameraContainer(
fastest: fastest, fastest: fastest,

View file

@ -15,7 +15,6 @@ import 'components/camera_controls/widget_camera_controls.dart';
import 'event_container_camera.dart'; import 'event_container_camera.dart';
import 'state_container_camera.dart'; import 'state_container_camera.dart';
// TODO: add stepHeight calculation based on Text
class CameraContainer extends StatelessWidget { class CameraContainer extends StatelessWidget {
final ExposurePair? fastest; final ExposurePair? fastest;
final ExposurePair? slowest; final ExposurePair? slowest;

View file

@ -18,8 +18,8 @@ class LightSensorContainerBloc
StreamSubscription<int>? _luxSubscriptions; StreamSubscription<int>? _luxSubscriptions;
LightSensorContainerBloc( LightSensorContainerBloc(
MeteringCommunicationBloc communicationBloc,
this._meteringInteractor, this._meteringInteractor,
MeteringCommunicationBloc communicationBloc,
) : super( ) : super(
communicationBloc, communicationBloc,
const LightSensorInitState(), const LightSensorInitState(),
@ -30,7 +30,9 @@ class LightSensorContainerBloc
if (communicationState is communication_states.MeasureState) { if (communicationState is communication_states.MeasureState) {
if (_luxSubscriptions == null) { if (_luxSubscriptions == null) {
_luxSubscriptions = _meteringInteractor.luxStream().listen((event) { _luxSubscriptions = _meteringInteractor.luxStream().listen((event) {
communicationBloc.add(communication_event.MeasuredEvent(log2(event.toDouble() / 2.5))); communicationBloc.add(communication_event.MeasuredEvent(
log2(event.toDouble() / 2.5) + _meteringInteractor.lightSensorEvCalibration,
));
}); });
} else { } else {
_luxSubscriptions?.cancel().then((_) => _luxSubscriptions = null); _luxSubscriptions?.cancel().then((_) => _luxSubscriptions = null);

View file

@ -32,9 +32,10 @@ class LightSensorContainerProvider extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
lazy: false,
create: (context) => LightSensorContainerBloc( create: (context) => LightSensorContainerBloc(
context.read<MeteringCommunicationBloc>(),
context.read<MeteringInteractor>(), context.read<MeteringInteractor>(),
context.read<MeteringCommunicationBloc>(),
), ),
child: LightSensorContainer( child: LightSensorContainer(
fastest: fastest, fastest: fastest,

View file

@ -1,4 +1,3 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';

View file

@ -8,26 +8,47 @@ class CalibrationDialogBloc extends Bloc<CalibrationDialogEvent, CalibrationDial
final SettingsInteractor _settingsInteractor; final SettingsInteractor _settingsInteractor;
late double _cameraEvCalibration = _settingsInteractor.cameraEvCalibration; late double _cameraEvCalibration = _settingsInteractor.cameraEvCalibration;
late double _lightSensorEvCalibration = _settingsInteractor.lightSensorEvCalibration;
CalibrationDialogBloc(this._settingsInteractor) CalibrationDialogBloc(this._settingsInteractor)
: super(CalibrationDialogState(_settingsInteractor.cameraEvCalibration)) { : super(
CalibrationDialogState(
_settingsInteractor.cameraEvCalibration,
_settingsInteractor.lightSensorEvCalibration,
),
) {
on<CameraEvCalibrationChangedEvent>(_onCameraEvCalibrationChanged); on<CameraEvCalibrationChangedEvent>(_onCameraEvCalibrationChanged);
on<CameraEvCalibrationResetEvent>(_onCameraEvCalibrationReset); on<CameraEvCalibrationResetEvent>(_onCameraEvCalibrationReset);
on<LightSensorEvCalibrationChangedEvent>(_onLightSensorEvCalibrationChanged);
on<LightSensorEvCalibrationResetEvent>(_onLightSensorEvCalibrationReset);
on<SaveCalibrationDialogEvent>(_onSaveCalibration); on<SaveCalibrationDialogEvent>(_onSaveCalibration);
} }
void _onCameraEvCalibrationChanged(CameraEvCalibrationChangedEvent event, Emitter emit) { void _onCameraEvCalibrationChanged(CameraEvCalibrationChangedEvent event, Emitter emit) {
_cameraEvCalibration = event.value; _cameraEvCalibration = event.value;
emit(CalibrationDialogState(event.value)); emit(CalibrationDialogState(_cameraEvCalibration, _lightSensorEvCalibration));
} }
void _onCameraEvCalibrationReset(CameraEvCalibrationResetEvent event, Emitter emit) { void _onCameraEvCalibrationReset(CameraEvCalibrationResetEvent event, Emitter emit) {
_settingsInteractor.quickVibration(); _settingsInteractor.quickVibration();
_cameraEvCalibration = 0; _cameraEvCalibration = 0;
emit(CalibrationDialogState(_cameraEvCalibration)); emit(CalibrationDialogState(_cameraEvCalibration, _lightSensorEvCalibration));
}
void _onLightSensorEvCalibrationChanged(
LightSensorEvCalibrationChangedEvent event, Emitter emit) {
_lightSensorEvCalibration = event.value;
emit(CalibrationDialogState(_cameraEvCalibration, _lightSensorEvCalibration));
}
void _onLightSensorEvCalibrationReset(LightSensorEvCalibrationResetEvent event, Emitter emit) {
_settingsInteractor.quickVibration();
_lightSensorEvCalibration = 0;
emit(CalibrationDialogState(_cameraEvCalibration, _lightSensorEvCalibration));
} }
void _onSaveCalibration(SaveCalibrationDialogEvent event, __) { void _onSaveCalibration(SaveCalibrationDialogEvent event, __) {
_settingsInteractor.setCameraEvCalibration(_cameraEvCalibration); _settingsInteractor.setCameraEvCalibration(_cameraEvCalibration);
_settingsInteractor.setLightSensorEvCalibration(_lightSensorEvCalibration);
} }
} }

View file

@ -12,6 +12,16 @@ class CameraEvCalibrationResetEvent extends CalibrationDialogEvent {
const CameraEvCalibrationResetEvent(); const CameraEvCalibrationResetEvent();
} }
class LightSensorEvCalibrationChangedEvent extends CalibrationDialogEvent {
final double value;
const LightSensorEvCalibrationChangedEvent(this.value);
}
class LightSensorEvCalibrationResetEvent extends CalibrationDialogEvent {
const LightSensorEvCalibrationResetEvent();
}
class SaveCalibrationDialogEvent extends CalibrationDialogEvent { class SaveCalibrationDialogEvent extends CalibrationDialogEvent {
const SaveCalibrationDialogEvent(); const SaveCalibrationDialogEvent();
} }

View file

@ -1,5 +1,9 @@
class CalibrationDialogState { class CalibrationDialogState {
final double cameraEvCalibration; final double cameraEvCalibration;
final double lightSensorEvCalibration;
const CalibrationDialogState(this.cameraEvCalibration); const CalibrationDialogState(
this.cameraEvCalibration,
this.lightSensorEvCalibration,
);
} }

View file

@ -9,16 +9,9 @@ import 'package:lightmeter/utils/to_string_signed.dart';
import 'bloc_dialog_calibration.dart'; import 'bloc_dialog_calibration.dart';
import 'state_dialog_calibration.dart'; import 'state_dialog_calibration.dart';
class CalibrationDialog extends StatefulWidget { class CalibrationDialog extends StatelessWidget {
const CalibrationDialog({super.key}); const CalibrationDialog({super.key});
@override
State<CalibrationDialog> createState() => _CalibrationDialogState();
}
class _CalibrationDialogState extends State<CalibrationDialog> {
CalibrationDialogBloc get bloc => context.read<CalibrationDialogBloc>();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
@ -30,17 +23,39 @@ class _CalibrationDialogState extends State<CalibrationDialog> {
), ),
title: Text(S.of(context).calibration), title: Text(S.of(context).calibration),
contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
content: BlocBuilder<CalibrationDialogBloc, CalibrationDialogState>( content: SingleChildScrollView(
builder: (context, state) => Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text(S.of(context).calibrationMessage), Text(S.of(context).calibrationMessage),
const SizedBox(height: Dimens.grid16), const SizedBox(height: Dimens.grid16),
_CalibrationUnit( BlocBuilder<CalibrationDialogBloc, CalibrationDialogState>(
title: S.of(context).camera, buildWhen: (previous, current) =>
value: state.cameraEvCalibration, previous.cameraEvCalibration != current.cameraEvCalibration,
onChanged: (value) => bloc.add(CameraEvCalibrationChangedEvent(value)), builder: (context, state) => _CalibrationUnit(
onReset: () => bloc.add(const CameraEvCalibrationResetEvent()), title: S.of(context).camera,
value: state.cameraEvCalibration,
onChanged: (value) => context
.read<CalibrationDialogBloc>()
.add(CameraEvCalibrationChangedEvent(value)),
onReset: () => context
.read<CalibrationDialogBloc>()
.add(const CameraEvCalibrationResetEvent()),
),
),
BlocBuilder<CalibrationDialogBloc, CalibrationDialogState>(
buildWhen: (previous, current) =>
previous.lightSensorEvCalibration != current.lightSensorEvCalibration,
builder: (context, state) => _CalibrationUnit(
title: S.of(context).lightSensor,
value: state.lightSensorEvCalibration,
onChanged: (value) => context
.read<CalibrationDialogBloc>()
.add(LightSensorEvCalibrationChangedEvent(value)),
onReset: () => context
.read<CalibrationDialogBloc>()
.add(const LightSensorEvCalibrationResetEvent()),
),
), ),
], ],
), ),
@ -58,7 +73,7 @@ class _CalibrationDialogState extends State<CalibrationDialog> {
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
bloc.add(const SaveCalibrationDialogEvent()); context.read<CalibrationDialogBloc>().add(const SaveCalibrationDialogEvent());
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: Text(S.of(context).save), child: Text(S.of(context).save),