diff --git a/.gitignore b/.gitignore index 89b551b..4fbcff0 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,6 @@ app.*.map.json /ios/Runner.xcodeproj/project.pbxproj pubspec.lock -/ios/Podfile.lock \ No newline at end of file +/ios/Podfile.lock + +.fvm/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a770516 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,24 @@ +{ + "task.slowProviderWarning": true, + "dart.flutterSdkPaths": [ + "fvm" + ], + "dart.lineLength": 100, + "[dart]": { + "editor.formatOnSave": true, + "editor.formatOnType": true, + "editor.rulers": [ + 100, + 120, + ], + "editor.selectionHighlight": true, + "editor.suggest.snippetsPreventQuickSuggestions": false, + "editor.suggestSelection": "first", + "editor.tabCompletion": "onlySnippets", + "editor.wordBasedSuggestions": false + }, + "dart.doNotFormat": [ + "**/generated/**", + "lib/data/**" + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..8615437 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,53 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "fvm_build_android_dev", + "type": "shell", + "command": ".fvm/flutter_sdk/bin/flutter", + "args": [ + "build", + "apk", + "--flavor", + "dev", + "--release", + "--dart-define", + "cameraPreviewAspectRatio=2/3", + "-t", + "lib/main_dev.dart", + ], + }, + { + "label": "fvm_build_android_prod", + "type": "shell", + "command": ".fvm/flutter_sdk/bin/flutter", + "args": [ + "build", + "apk", + "--flavor", + "prod", + "--release", + "--dart-define", + "cameraPreviewAspectRatio=2/3", + "-t", + "lib/main_prod.dart", + ], + }, + { + "label": "fvm_build_appbundle", + "type": "shell", + "command": ".fvm/flutter_sdk/bin/flutter", + "args": [ + "build", + "appbundle", + "--flavor", + "prod", + "--release", + "--dart-define", + "cameraPreviewAspectRatio=2/3", + "-t", + "lib/main_prod.dart", + ], + }, + ] +} \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 5f0c906..aedfc58 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -49,6 +49,18 @@ android { versionName flutterVersionName } + signingConfigs { + debug {} + /* + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + */ + } + flavorDimensions "app" productFlavors { dev { @@ -62,6 +74,17 @@ android { signingConfig signingConfigs.debug } } + + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + signingConfig signingConfigs.debug + minifyEnabled true + shrinkResources true + } + } } flutter { diff --git a/lib/application.dart b/lib/application.dart index 9c4c86b..b68b8ca 100644 --- a/lib/application.dart +++ b/lib/application.dart @@ -39,13 +39,15 @@ class Application extends StatelessWidget { child: StopTypeProvider( child: ThemeProvider( builder: (context, _) { - final systemIconsBrightness = - ThemeData.estimateBrightnessForColor(context.watch().colorScheme.onSurface); + final systemIconsBrightness = ThemeData.estimateBrightnessForColor( + context.watch().colorScheme.onSurface, + ); return AnnotatedRegion( value: SystemUiOverlayStyle( statusBarColor: Colors.transparent, - statusBarBrightness: - systemIconsBrightness == Brightness.light ? Brightness.dark : Brightness.light, + statusBarBrightness: systemIconsBrightness == Brightness.light + ? Brightness.dark + : Brightness.light, statusBarIconBrightness: systemIconsBrightness, systemNavigationBarColor: context.watch().colorScheme.surface, systemNavigationBarIconBrightness: systemIconsBrightness, diff --git a/lib/data/haptics_service.dart b/lib/data/haptics_service.dart index aa7511b..8d36e32 100644 --- a/lib/data/haptics_service.dart +++ b/lib/data/haptics_service.dart @@ -2,7 +2,7 @@ import 'package:vibration/vibration.dart'; class HapticsService { const HapticsService(); - + Future quickVibration() async => _tryVibrate(duration: 25, amplitude: 96); Future responseVibration() async => _tryVibrate(duration: 50, amplitude: 128); diff --git a/lib/data/models/theme_type.dart b/lib/data/models/theme_type.dart index 94488f7..a14f200 100644 --- a/lib/data/models/theme_type.dart +++ b/lib/data/models/theme_type.dart @@ -1 +1 @@ -enum ThemeType {light, dark, systemDefault} \ No newline at end of file +enum ThemeType { light, dark, systemDefault } diff --git a/lib/platform_config.dart b/lib/platform_config.dart index ee1c294..2b9612c 100644 --- a/lib/platform_config.dart +++ b/lib/platform_config.dart @@ -1,6 +1,6 @@ class PlatformConfig { static double get cameraPreviewAspectRatio { - final rational = const String.fromEnvironment('cameraPreviewAspectRatio', defaultValue: "3/4").split('/'); + final rational = const String.fromEnvironment('cameraPreviewAspectRatio').split('/'); return int.parse(rational[0]) / int.parse(rational[1]); } } diff --git a/lib/res/theme.dart b/lib/res/theme.dart index ce41b56..9eedad7 100644 --- a/lib/res/theme.dart +++ b/lib/res/theme.dart @@ -25,8 +25,10 @@ class ThemeProvider extends StatefulWidget { } class ThemeProviderState extends State { - late final _themeTypeNotifier = ValueNotifier(context.read().themeType); - late final _dynamicColorNotifier = ValueNotifier(context.read().dynamicColor); + UserPreferencesService get _prefs => context.read(); + + late final _themeTypeNotifier = ValueNotifier(_prefs.themeType); + late final _dynamicColorNotifier = ValueNotifier(_prefs.dynamicColor); late final _primaryColorNotifier = ValueNotifier(const Color(0xFF2196f3)); @override @@ -64,7 +66,7 @@ class ThemeProviderState extends State { void setThemeType(ThemeType themeType) { _themeTypeNotifier.value = themeType; - context.read().themeType = themeType; + _prefs.themeType = themeType; } Brightness get _themeBrightness { @@ -80,7 +82,7 @@ class ThemeProviderState extends State { void enableDynamicColor(bool enable) { _dynamicColorNotifier.value = enable; - context.read().dynamicColor = enable; + _prefs.dynamicColor = enable; } } @@ -103,7 +105,8 @@ class _DynamicColorProvider extends StatelessWidget { late final Color? dynamicPrimaryColor; if (lightDynamic != null && darkDynamic != null) { if (useDynamicColor) { - dynamicPrimaryColor = (themeBrightness == Brightness.light ? lightDynamic : darkDynamic).primary; + dynamicPrimaryColor = + (themeBrightness == Brightness.light ? lightDynamic : darkDynamic).primary; state = DynamicColorState.enabled; } else { dynamicPrimaryColor = null; @@ -153,7 +156,9 @@ class _ThemeDataProvider extends StatelessWidget { } ColorScheme _colorSchemeFromColor() { - final scheme = brightness == Brightness.light ? Scheme.light(primaryColor.value) : Scheme.dark(primaryColor.value); + final scheme = brightness == Brightness.light + ? Scheme.light(primaryColor.value) + : Scheme.dark(primaryColor.value); return ColorScheme( brightness: brightness, primary: Color(scheme.primary), @@ -168,7 +173,8 @@ class _ThemeDataProvider extends StatelessWidget { onBackground: Color(scheme.onBackground), surface: Color.alphaBlend(Color(scheme.primary).withOpacity(0.05), Color(scheme.background)), onSurface: Color(scheme.onSurface), - surfaceVariant: Color.alphaBlend(Color(scheme.primary).withOpacity(0.5), Color(scheme.background)), + surfaceVariant: + Color.alphaBlend(Color(scheme.primary).withOpacity(0.5), Color(scheme.background)), onSurfaceVariant: Color(scheme.onSurfaceVariant), ); } diff --git a/lib/screens/metering/bloc_metering.dart b/lib/screens/metering/bloc_metering.dart index 722a1c6..f9d49bb 100644 --- a/lib/screens/metering/bloc_metering.dart +++ b/lib/screens/metering/bloc_metering.dart @@ -8,8 +8,10 @@ import 'package:lightmeter/data/models/photography_values/photography_value.dart import 'package:lightmeter/data/models/photography_values/shutter_speed_value.dart'; import 'package:lightmeter/data/shared_prefs_service.dart'; import 'package:lightmeter/interactors/metering_interactor.dart'; -import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' as communication_events; -import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; +import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' + as communication_events; +import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' + as communication_states; import 'package:lightmeter/utils/log_2.dart'; import 'communication/bloc_communication_metering.dart'; @@ -132,7 +134,8 @@ class MeteringBloc extends Bloc { evSteps = (ev / 0.3).floor(); break; } - final evOffset = _shutterSpeedValues.indexOf(const ShutterSpeedValue(1, false, StopType.full)) - evSteps; + final evOffset = + _shutterSpeedValues.indexOf(const ShutterSpeedValue(1, false, StopType.full)) - evSteps; late final int apertureOffset; late final int shutterSpeedOffset; @@ -144,7 +147,8 @@ class MeteringBloc extends Bloc { shutterSpeedOffset = 0; } - int itemsCount = min(_apertureValues.length + shutterSpeedOffset, _shutterSpeedValues.length + apertureOffset) - + int itemsCount = min(_apertureValues.length + shutterSpeedOffset, + _shutterSpeedValues.length + apertureOffset) - max(apertureOffset, shutterSpeedOffset); if (itemsCount < 0) { diff --git a/lib/screens/metering/communication/bloc_communication_metering.dart b/lib/screens/metering/communication/bloc_communication_metering.dart index b6fa04c..b317c01 100644 --- a/lib/screens/metering/communication/bloc_communication_metering.dart +++ b/lib/screens/metering/communication/bloc_communication_metering.dart @@ -3,7 +3,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'event_communication_metering.dart'; import 'state_communication_metering.dart'; -class MeteringCommunicationBloc extends Bloc { +class MeteringCommunicationBloc + extends Bloc { MeteringCommunicationBloc() : super(const InitState()) { on((_, emit) => emit(const MeasureState())); on((event, emit) => emit(MeasuredState(event.ev100))); diff --git a/lib/screens/metering/communication/state_communication_metering.dart b/lib/screens/metering/communication/state_communication_metering.dart index a41bef8..3a03e58 100644 --- a/lib/screens/metering/communication/state_communication_metering.dart +++ b/lib/screens/metering/communication/state_communication_metering.dart @@ -22,4 +22,4 @@ class MeasuredState extends ScreenState { final double ev100; const MeasuredState(this.ev100); -} \ No newline at end of file +} diff --git a/lib/screens/metering/components/exposure_pairs_list/components/widget_item_list_exposure_pairs.dart b/lib/screens/metering/components/exposure_pairs_list/components/widget_item_list_exposure_pairs.dart index 358b0b9..1b0fc02 100644 --- a/lib/screens/metering/components/exposure_pairs_list/components/widget_item_list_exposure_pairs.dart +++ b/lib/screens/metering/components/exposure_pairs_list/components/widget_item_list_exposure_pairs.dart @@ -6,7 +6,11 @@ class ExposurePairsListItem extends StatelessWid final T value; final bool tickOnTheLeft; - const ExposurePairsListItem(this.value, {required this.tickOnTheLeft, super.key}); + const ExposurePairsListItem( + this.value, { + required this.tickOnTheLeft, + super.key, + }); @override Widget build(BuildContext context) { diff --git a/lib/screens/metering/components/exposure_pairs_list/widget_list_exposure_pairs.dart b/lib/screens/metering/components/exposure_pairs_list/widget_list_exposure_pairs.dart index d1533f4..4bca49c 100644 --- a/lib/screens/metering/components/exposure_pairs_list/widget_list_exposure_pairs.dart +++ b/lib/screens/metering/components/exposure_pairs_list/widget_list_exposure_pairs.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/data/models/exposure_pair.dart'; import 'package:lightmeter/res/dimens.dart'; -import 'package:lightmeter/screens/metering/components/exposure_pairs_list/components/widget_item_list_exposure_pairs.dart'; + +import 'components/widget_item_list_exposure_pairs.dart'; class ExposurePairsList extends StatelessWidget { final List exposurePairs; @@ -51,7 +52,9 @@ class ExposurePairsList extends StatelessWidget { builder: (context, constraints) => Align( alignment: index == 0 ? Alignment.bottomCenter - : (index == exposurePairs.length - 1 ? Alignment.topCenter : Alignment.center), + : (index == exposurePairs.length - 1 + ? Alignment.topCenter + : Alignment.center), child: SizedBox( height: index == 0 || index == exposurePairs.length - 1 ? constraints.maxHeight / 2 diff --git a/lib/screens/metering/components/topbar/components/container_reading_value.dart b/lib/screens/metering/components/topbar/components/container_reading_value.dart index e61460f..66ed30f 100644 --- a/lib/screens/metering/components/topbar/components/container_reading_value.dart +++ b/lib/screens/metering/components/topbar/components/container_reading_value.dart @@ -60,18 +60,19 @@ class _ReadingValueBuilder extends StatelessWidget { @override Widget build(BuildContext context) { final textTheme = Theme.of(context).textTheme; + final textColor = Theme.of(context).colorScheme.onPrimaryContainer; return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( reading.label, - style: textTheme.labelMedium?.copyWith(color: Theme.of(context).colorScheme.onPrimaryContainer), + style: textTheme.labelMedium?.copyWith(color: textColor), ), const SizedBox(height: Dimens.grid4), Text( reading.value, - style: textTheme.titleMedium?.copyWith(color: Theme.of(context).colorScheme.onPrimaryContainer), + style: textTheme.titleMedium?.copyWith(color: textColor), ), ], ); diff --git a/lib/screens/metering/components/topbar/components/shared/widget_dialog_animated.dart b/lib/screens/metering/components/topbar/components/shared/widget_dialog_animated.dart index 04de475..820e933 100644 --- a/lib/screens/metering/components/topbar/components/shared/widget_dialog_animated.dart +++ b/lib/screens/metering/components/topbar/components/shared/widget_dialog_animated.dart @@ -47,7 +47,10 @@ class AnimatedDialogState extends State with SingleTickerProvide reverseDuration: Dimens.durationML, vsync: this, ); - _defaultCurvedAnimation = CurvedAnimation(parent: _animationController, curve: Curves.easeInOut); + _defaultCurvedAnimation = CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOut, + ); _barrierColorAnimation = ColorTween( begin: Colors.transparent, end: Colors.black54, diff --git a/lib/screens/metering/components/topbar/components/widget_camera_preview.dart b/lib/screens/metering/components/topbar/components/widget_camera_preview.dart index d67ecce..a47f6cd 100644 --- a/lib/screens/metering/components/topbar/components/widget_camera_preview.dart +++ b/lib/screens/metering/components/topbar/components/widget_camera_preview.dart @@ -55,6 +55,8 @@ class CameraView extends StatelessWidget { DeviceOrientation _getApplicableOrientation(CameraValue value) { return value.isRecordingVideo ? value.recordingOrientation! - : (value.previewPauseOrientation ?? value.lockedCaptureOrientation ?? value.deviceOrientation); + : (value.previewPauseOrientation ?? + value.lockedCaptureOrientation ?? + value.deviceOrientation); } } diff --git a/lib/screens/metering/components/topbar/components/widget_dialog_picker.dart b/lib/screens/metering/components/topbar/components/widget_dialog_picker.dart index 168e628..9f8efb4 100644 --- a/lib/screens/metering/components/topbar/components/widget_dialog_picker.dart +++ b/lib/screens/metering/components/topbar/components/widget_dialog_picker.dart @@ -4,7 +4,8 @@ import 'package:lightmeter/data/models/photography_values/photography_value.dart import 'package:lightmeter/res/dimens.dart'; typedef DialogPickerItemBuilder = Widget Function(BuildContext, T); -typedef DialogPickerEvDifferenceBuilder = String Function(T selected, T other); +typedef DialogPickerEvDifferenceBuilder = String Function( + T selected, T other); class MeteringScreenDialogPicker extends StatefulWidget { final String title; @@ -32,7 +33,8 @@ class MeteringScreenDialogPicker extends StatefulWid State> createState() => _MeteringScreenDialogPickerState(); } -class _MeteringScreenDialogPickerState extends State> { +class _MeteringScreenDialogPickerState + extends State> { late T _selectedValue = widget.initialValue; final _scrollController = ScrollController(); @@ -101,7 +103,9 @@ class _MeteringScreenDialogPickerState extends State child: widget.itemTitleBuilder(context, widget.values[index]), ), secondary: widget.values[index].value != _selectedValue.value - ? Text(S.of(context).ev(widget.evDifferenceBuilder.call(_selectedValue, widget.values[index]))) + ? Text(S + .of(context) + .ev(widget.evDifferenceBuilder.call(_selectedValue, widget.values[index]))) : null, onChanged: (value) { if (value != null) { diff --git a/lib/screens/metering/components/topbar/shape_topbar.dart b/lib/screens/metering/components/topbar/shape_topbar.dart index aa79d73..a4c7c8f 100644 --- a/lib/screens/metering/components/topbar/shape_topbar.dart +++ b/lib/screens/metering/components/topbar/shape_topbar.dart @@ -8,17 +8,17 @@ class TopBarShape extends CustomPainter { /// The appendix is on the left side /// but if appendix height is negative, then we have to make a cutout - /// + /// /// negative positive /// | | /// | | /// | | /// | | /// | | /// | | /// | | /// | | - /// \________ | /// | ________/ + /// \________ | /// | ________/ /// \ | /// | / ↑ /// | | /// | | | appendix height /// \__________/ /// \__________/ ↓ - /// + /// final double appendixHeight; final double appendixWidth; @@ -54,7 +54,7 @@ class TopBarShape extends CustomPainter { ); // Bottom side with step - final double allowedRadius = min(appendixHeight.abs() / 2, Dimens.borderRadiusL); + final allowedRadius = min(appendixHeight.abs() / 2, Dimens.borderRadiusL); path.lineTo(appendixWidth - allowedRadius, size.height + appendixHeight); final bool isCutout = appendixHeight < 0; diff --git a/lib/screens/metering/components/topbar/widget_topbar.dart b/lib/screens/metering/components/topbar/widget_topbar.dart index 546249d..8b73008 100644 --- a/lib/screens/metering/components/topbar/widget_topbar.dart +++ b/lib/screens/metering/components/topbar/widget_topbar.dart @@ -174,7 +174,9 @@ class _NdValueTile extends StatelessWidget { subtitle: S.of(context).ndFilterFactor, selectedValue: value, values: ndValues, - itemTitleBuilder: (_, value) => Text(value.value == 0 ? S.of(context).none : value.value.toString()), + itemTitleBuilder: (_, value) => Text( + value.value == 0 ? S.of(context).none : value.value.toString(), + ), // using descending order, because ND filter darkens image & lowers EV evDifferenceBuilder: (selected, other) => other.toStringDifference(selected), onChanged: onChanged, diff --git a/lib/screens/metering/ev_source/camera/bloc_camera.dart b/lib/screens/metering/ev_source/camera/bloc_camera.dart index 5ee7552..4bd4409 100644 --- a/lib/screens/metering/ev_source/camera/bloc_camera.dart +++ b/lib/screens/metering/ev_source/camera/bloc_camera.dart @@ -9,8 +9,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lightmeter/interactors/metering_interactor.dart'; import 'package:lightmeter/screens/metering/ev_source/ev_source_bloc.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; -import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' as communication_event; -import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; +import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' + as communication_event; +import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' + as communication_states; import 'package:lightmeter/utils/log_2.dart'; import 'event_camera.dart'; @@ -61,7 +63,9 @@ class CameraBloc extends EvSourceBloc { if (communicationState is communication_states.MeasureState) { _takePhoto().then((ev100) { if (ev100 != null) { - communicationBloc.add(communication_event.MeasuredEvent(ev100 + _meteringInteractor.cameraEvCalibration)); + communicationBloc.add( + communication_event.MeasuredEvent(ev100 + _meteringInteractor.cameraEvCalibration), + ); } }); } @@ -92,7 +96,12 @@ class CameraBloc extends EvSourceBloc { _exposureOffsetRange = await Future.wait([ _cameraController!.getMinExposureOffset(), _cameraController!.getMaxExposureOffset(), - ]).then((levels) => RangeValues(max(_exposureMaxRange.start, levels[0]), min(_exposureMaxRange.end, levels[1]))); + ]).then( + (levels) => RangeValues( + max(_exposureMaxRange.start, levels[0]), + min(_exposureMaxRange.end, levels[1]), + ), + ); await _cameraController!.getExposureOffsetStepSize().then((value) { _exposureStep = value == 0 ? 0.1 : value; }); diff --git a/lib/screens/metering/ev_source/ev_source_bloc.dart b/lib/screens/metering/ev_source/ev_source_bloc.dart index 82cf346..eac25d8 100644 --- a/lib/screens/metering/ev_source/ev_source_bloc.dart +++ b/lib/screens/metering/ev_source/ev_source_bloc.dart @@ -1,7 +1,8 @@ import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; -import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; +import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' + as communication_states; abstract class EvSourceBloc extends Bloc { final MeteringCommunicationBloc communicationBloc; diff --git a/lib/screens/metering/ev_source/random_ev/bloc_random_ev.dart b/lib/screens/metering/ev_source/random_ev/bloc_random_ev.dart index 17103ee..1d72bed 100644 --- a/lib/screens/metering/ev_source/random_ev/bloc_random_ev.dart +++ b/lib/screens/metering/ev_source/random_ev/bloc_random_ev.dart @@ -1,8 +1,10 @@ import 'dart:math'; import 'package:lightmeter/screens/metering/ev_source/ev_source_bloc.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; -import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' as communication_event; -import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; +import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' + as communication_event; +import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' + as communication_states; import 'event_random_ev.dart'; import 'state_random_ev.dart'; diff --git a/lib/screens/metering/ev_source/random_ev/event_random_ev.dart b/lib/screens/metering/ev_source/random_ev/event_random_ev.dart index 25c0fee..61e5e54 100644 --- a/lib/screens/metering/ev_source/random_ev/event_random_ev.dart +++ b/lib/screens/metering/ev_source/random_ev/event_random_ev.dart @@ -1,3 +1,3 @@ abstract class RandomEvEvent { const RandomEvEvent(); -} \ No newline at end of file +} diff --git a/lib/screens/metering/screen_metering.dart b/lib/screens/metering/screen_metering.dart index 9a00b33..f9dcee3 100644 --- a/lib/screens/metering/screen_metering.dart +++ b/lib/screens/metering/screen_metering.dart @@ -22,10 +22,12 @@ class MeteringScreen extends StatefulWidget { class _MeteringScreenState extends State { double topBarOverflow = 0.0; + MeteringBloc get _bloc => context.read(); + @override void didChangeDependencies() { super.didChangeDependencies(); - context.read().add(StopTypeChangedEvent(context.watch())); + _bloc.add(StopTypeChangedEvent(context.watch())); } @override @@ -33,66 +35,83 @@ class _MeteringScreenState extends State { return Scaffold( backgroundColor: Theme.of(context).colorScheme.background, body: BlocBuilder( - builder: (context, state) { - return Stack( - children: [ - Column( - children: [ - MeteringTopBar( - fastest: state.fastest, - slowest: state.slowest, - ev: state.ev, - iso: state.iso, - nd: state.nd, - onIsoChanged: (value) => context.read().add(IsoChangedEvent(value)), - onNdChanged: (value) => context.read().add(NdChangedEvent(value)), - onCutoutLayout: (value) => topBarOverflow = value, - ), - Expanded( - child: LayoutBuilder( - builder: (context, constraints) => OverflowBox( - alignment: Alignment.bottomCenter, - maxHeight: constraints.maxHeight + topBarOverflow.abs(), - maxWidth: constraints.maxWidth, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM), - child: Row( - children: [ - Expanded( - child: Padding( - padding: topBarOverflow >= 0 ? EdgeInsets.only(top: topBarOverflow) : EdgeInsets.zero, - child: ExposurePairsList(state.exposurePairs), - ), - ), - const SizedBox(width: Dimens.grid8), - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM).add( - topBarOverflow <= 0 ? EdgeInsets.only(top: -topBarOverflow) : EdgeInsets.zero), - child: Column( - children: const [ - Expanded(child: CameraExposureSlider()), - SizedBox(height: Dimens.grid24), - CameraZoomSlider(), - ], - ), - ), - ), - ], - ), - ), - ), + builder: (context, state) => Column( + children: [ + MeteringTopBar( + fastest: state.fastest, + slowest: state.slowest, + ev: state.ev, + iso: state.iso, + nd: state.nd, + onIsoChanged: (value) => _bloc.add(IsoChangedEvent(value)), + onNdChanged: (value) => _bloc.add(NdChangedEvent(value)), + onCutoutLayout: (value) => topBarOverflow = value, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM), + child: _MiddleContentWrapper( + topBarOverflow: topBarOverflow, + leftContent: ExposurePairsList(state.exposurePairs), + rightContent: Padding( + padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM), + child: Column( + children: const [ + Expanded(child: CameraExposureSlider()), + SizedBox(height: Dimens.grid24), + CameraZoomSlider(), + ], ), ), - MeteringBottomControls( - onMeasure: () => context.read().add(const MeasureEvent()), - onSettings: () => Navigator.pushNamed(context, 'settings'), - ), - ], + ), ), - ], - ); - }, + ), + MeteringBottomControls( + onMeasure: () => _bloc.add(const MeasureEvent()), + onSettings: () => Navigator.pushNamed(context, 'settings'), + ), + ], + ), + ), + ); + } +} + +class _MiddleContentWrapper extends StatelessWidget { + final double topBarOverflow; + final Widget leftContent; + final Widget rightContent; + + const _MiddleContentWrapper({ + required this.topBarOverflow, + required this.leftContent, + required this.rightContent, + }); + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) => OverflowBox( + alignment: Alignment.bottomCenter, + maxHeight: constraints.maxHeight + topBarOverflow.abs(), + maxWidth: constraints.maxWidth, + child: Row( + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(top: topBarOverflow >= 0 ? topBarOverflow : 0), + child: leftContent, + ), + ), + const SizedBox(width: Dimens.grid8), + Expanded( + child: Padding( + padding: EdgeInsets.only(top: topBarOverflow <= 0 ? -topBarOverflow : 0), + child: rightContent, + ), + ), + ], + ), ), ); } diff --git a/lib/screens/settings/components/calibration/components/calibration_dialog/widget_dialog_calibration.dart b/lib/screens/settings/components/calibration/components/calibration_dialog/widget_dialog_calibration.dart index 7d319fa..ed49180 100644 --- a/lib/screens/settings/components/calibration/components/calibration_dialog/widget_dialog_calibration.dart +++ b/lib/screens/settings/components/calibration/components/calibration_dialog/widget_dialog_calibration.dart @@ -17,6 +17,8 @@ class CalibrationDialog extends StatefulWidget { } class _CalibrationDialogState extends State { + CalibrationDialogBloc get bloc => context.read(); + @override Widget build(BuildContext context) { return AlertDialog( @@ -37,8 +39,8 @@ class _CalibrationDialogState extends State { _CalibrationUnit( title: S.of(context).camera, value: state.cameraEvCalibration, - onChanged: (value) => context.read().add(CameraEvCalibrationChangedEvent(value)), - onReset: () => context.read().add(const CameraEvCalibrationResetEvent()), + onChanged: (value) => bloc.add(CameraEvCalibrationChangedEvent(value)), + onReset: () => bloc.add(const CameraEvCalibrationResetEvent()), ), ], ), @@ -56,7 +58,7 @@ class _CalibrationDialogState extends State { ), TextButton( onPressed: () { - context.read().add(const SaveCalibrationDialogEvent()); + bloc.add(const SaveCalibrationDialogEvent()); Navigator.of(context).pop(); }, child: Text(S.of(context).save), diff --git a/lib/screens/settings/components/version/widget_list_tile_version.dart b/lib/screens/settings/components/version/widget_list_tile_version.dart index a2622a6..347af56 100644 --- a/lib/screens/settings/components/version/widget_list_tile_version.dart +++ b/lib/screens/settings/components/version/widget_list_tile_version.dart @@ -12,12 +12,9 @@ class VersionListTile extends StatelessWidget { title: Text(S.of(context).version), trailing: FutureBuilder( future: PackageInfo.fromPlatform(), - builder: (context, snapshot) { - if (snapshot.data != null) { - return Text(S.of(context).versionNumber(snapshot.data!.version, snapshot.data!.buildNumber)); - } - return const SizedBox.shrink(); - }, + builder: (context, snapshot) => snapshot.data != null + ? Text(S.of(context).versionNumber(snapshot.data!.version, snapshot.data!.buildNumber)) + : const SizedBox.shrink(), ), ); } diff --git a/lib/screens/settings/components/write_email/widget_list_tile_write_email.dart b/lib/screens/settings/components/write_email/widget_list_tile_write_email.dart index c72e5e6..20ae54c 100644 --- a/lib/screens/settings/components/write_email/widget_list_tile_write_email.dart +++ b/lib/screens/settings/components/write_email/widget_list_tile_write_email.dart @@ -13,7 +13,8 @@ class WriteEmailListTile extends StatelessWidget { leading: const Icon(Icons.email), title: Text(S.of(context).writeEmail), onTap: () { - launchUrl(Uri.parse('mailto:${context.read().contactEmail}?subject=M3 Lightmeter')); + launchUrl( + Uri.parse('mailto:${context.read().contactEmail}?subject=M3 Lightmeter')); }, ); } diff --git a/lib/screens/settings/screen_settings.dart b/lib/screens/settings/screen_settings.dart index c41b1e7..6bfd1d7 100644 --- a/lib/screens/settings/screen_settings.dart +++ b/lib/screens/settings/screen_settings.dart @@ -32,7 +32,10 @@ class SettingsScreen extends StatelessWidget { titlePadding: const EdgeInsets.all(Dimens.paddingM), title: Text( S.of(context).settings, - style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: 24), + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface, + fontSize: 24, + ), ), ), actions: [ diff --git a/lib/screens/shared/centered_slider/widget_slider_centered.dart b/lib/screens/shared/centered_slider/widget_slider_centered.dart index 8647dca..56c2c91 100644 --- a/lib/screens/shared/centered_slider/widget_slider_centered.dart +++ b/lib/screens/shared/centered_slider/widget_slider_centered.dart @@ -51,8 +51,14 @@ class _CenteredSliderState extends State { quarterTurns: widget.isVertical ? -1 : 0, child: GestureDetector( behavior: HitTestBehavior.translucent, - onTapUp: (details) => _updateHandlePosition(details.localPosition.dx, handleDistance), - onHorizontalDragUpdate: (details) => _updateHandlePosition(details.localPosition.dx, handleDistance), + onTapUp: (details) => _updateHandlePosition( + details.localPosition.dx, + handleDistance, + ), + onHorizontalDragUpdate: (details) => _updateHandlePosition( + details.localPosition.dx, + handleDistance, + ), child: SizedBox( height: Dimens.cameraSliderHandleSize, width: biggestSize, @@ -83,10 +89,8 @@ class _CenteredSliderState extends State { relativeValue = (offset - Dimens.cameraSliderHandleSize / 2) / handleDistance; } setState(() {}); - widget.onChanged(_clampToRange(relativeValue)); + widget.onChanged(relativeValue * (widget.max - widget.min) + widget.min); } - - double _clampToRange(double relativeValue) => relativeValue * (widget.max - widget.min) + widget.min; } class _Slider extends StatelessWidget { @@ -111,7 +115,9 @@ class _Slider extends StatelessWidget { children: [ Positioned( height: trackThickness, - width: handleDistance + trackThickness, // add thickness to maintain radius overlap with handle + + /// add thickness to maintain radius overlap with handle + width: handleDistance + trackThickness, child: ClipRRect( borderRadius: BorderRadius.circular(trackThickness / 2), child: ColoredBox(color: Theme.of(context).colorScheme.surfaceVariant),