mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 15:00:40 +00:00
Format & tasks
This commit is contained in:
parent
130f5ff0b2
commit
42fe5d45bc
30 changed files with 293 additions and 119 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -49,4 +49,6 @@ app.*.map.json
|
|||
/ios/Runner.xcodeproj/project.pbxproj
|
||||
|
||||
pubspec.lock
|
||||
/ios/Podfile.lock
|
||||
/ios/Podfile.lock
|
||||
|
||||
.fvm/
|
24
.vscode/settings.json
vendored
Normal file
24
.vscode/settings.json
vendored
Normal file
|
@ -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/**"
|
||||
]
|
||||
}
|
53
.vscode/tasks.json
vendored
Normal file
53
.vscode/tasks.json
vendored
Normal file
|
@ -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",
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -39,13 +39,15 @@ class Application extends StatelessWidget {
|
|||
child: StopTypeProvider(
|
||||
child: ThemeProvider(
|
||||
builder: (context, _) {
|
||||
final systemIconsBrightness =
|
||||
ThemeData.estimateBrightnessForColor(context.watch<ThemeData>().colorScheme.onSurface);
|
||||
final systemIconsBrightness = ThemeData.estimateBrightnessForColor(
|
||||
context.watch<ThemeData>().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<ThemeData>().colorScheme.surface,
|
||||
systemNavigationBarIconBrightness: systemIconsBrightness,
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:vibration/vibration.dart';
|
|||
|
||||
class HapticsService {
|
||||
const HapticsService();
|
||||
|
||||
|
||||
Future<void> quickVibration() async => _tryVibrate(duration: 25, amplitude: 96);
|
||||
|
||||
Future<void> responseVibration() async => _tryVibrate(duration: 50, amplitude: 128);
|
||||
|
|
|
@ -1 +1 @@
|
|||
enum ThemeType {light, dark, systemDefault}
|
||||
enum ThemeType { light, dark, systemDefault }
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,10 @@ class ThemeProvider extends StatefulWidget {
|
|||
}
|
||||
|
||||
class ThemeProviderState extends State<ThemeProvider> {
|
||||
late final _themeTypeNotifier = ValueNotifier<ThemeType>(context.read<UserPreferencesService>().themeType);
|
||||
late final _dynamicColorNotifier = ValueNotifier<bool>(context.read<UserPreferencesService>().dynamicColor);
|
||||
UserPreferencesService get _prefs => context.read<UserPreferencesService>();
|
||||
|
||||
late final _themeTypeNotifier = ValueNotifier<ThemeType>(_prefs.themeType);
|
||||
late final _dynamicColorNotifier = ValueNotifier<bool>(_prefs.dynamicColor);
|
||||
late final _primaryColorNotifier = ValueNotifier<Color>(const Color(0xFF2196f3));
|
||||
|
||||
@override
|
||||
|
@ -64,7 +66,7 @@ class ThemeProviderState extends State<ThemeProvider> {
|
|||
|
||||
void setThemeType(ThemeType themeType) {
|
||||
_themeTypeNotifier.value = themeType;
|
||||
context.read<UserPreferencesService>().themeType = themeType;
|
||||
_prefs.themeType = themeType;
|
||||
}
|
||||
|
||||
Brightness get _themeBrightness {
|
||||
|
@ -80,7 +82,7 @@ class ThemeProviderState extends State<ThemeProvider> {
|
|||
|
||||
void enableDynamicColor(bool enable) {
|
||||
_dynamicColorNotifier.value = enable;
|
||||
context.read<UserPreferencesService>().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),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<MeteringEvent, MeteringState> {
|
|||
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<MeteringEvent, MeteringState> {
|
|||
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) {
|
||||
|
|
|
@ -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<MeteringCommunicationEvent, MeteringCommunicationState> {
|
||||
class MeteringCommunicationBloc
|
||||
extends Bloc<MeteringCommunicationEvent, MeteringCommunicationState> {
|
||||
MeteringCommunicationBloc() : super(const InitState()) {
|
||||
on<MeasureEvent>((_, emit) => emit(const MeasureState()));
|
||||
on<MeasuredEvent>((event, emit) => emit(MeasuredState(event.ev100)));
|
||||
|
|
|
@ -22,4 +22,4 @@ class MeasuredState extends ScreenState {
|
|||
final double ev100;
|
||||
|
||||
const MeasuredState(this.ev100);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,11 @@ class ExposurePairsListItem<T extends PhotographyStopValue> 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) {
|
||||
|
|
|
@ -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<ExposurePair> 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
|
||||
|
|
|
@ -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),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -47,7 +47,10 @@ class AnimatedDialogState extends State<AnimatedDialog> 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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ import 'package:lightmeter/data/models/photography_values/photography_value.dart
|
|||
import 'package:lightmeter/res/dimens.dart';
|
||||
|
||||
typedef DialogPickerItemBuilder<T extends PhotographyValue> = Widget Function(BuildContext, T);
|
||||
typedef DialogPickerEvDifferenceBuilder<T extends PhotographyValue> = String Function(T selected, T other);
|
||||
typedef DialogPickerEvDifferenceBuilder<T extends PhotographyValue> = String Function(
|
||||
T selected, T other);
|
||||
|
||||
class MeteringScreenDialogPicker<T extends PhotographyValue> extends StatefulWidget {
|
||||
final String title;
|
||||
|
@ -32,7 +33,8 @@ class MeteringScreenDialogPicker<T extends PhotographyValue> extends StatefulWid
|
|||
State<MeteringScreenDialogPicker<T>> createState() => _MeteringScreenDialogPickerState<T>();
|
||||
}
|
||||
|
||||
class _MeteringScreenDialogPickerState<T extends PhotographyValue> extends State<MeteringScreenDialogPicker<T>> {
|
||||
class _MeteringScreenDialogPickerState<T extends PhotographyValue>
|
||||
extends State<MeteringScreenDialogPicker<T>> {
|
||||
late T _selectedValue = widget.initialValue;
|
||||
final _scrollController = ScrollController();
|
||||
|
||||
|
@ -101,7 +103,9 @@ class _MeteringScreenDialogPickerState<T extends PhotographyValue> 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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<CameraEvent, CameraState> {
|
|||
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<CameraEvent, CameraState> {
|
|||
_exposureOffsetRange = await Future.wait<double>([
|
||||
_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;
|
||||
});
|
||||
|
|
|
@ -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<E, S> extends Bloc<E, S> {
|
||||
final MeteringCommunicationBloc communicationBloc;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
abstract class RandomEvEvent {
|
||||
const RandomEvEvent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,12 @@ class MeteringScreen extends StatefulWidget {
|
|||
class _MeteringScreenState extends State<MeteringScreen> {
|
||||
double topBarOverflow = 0.0;
|
||||
|
||||
MeteringBloc get _bloc => context.read<MeteringBloc>();
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
context.read<MeteringBloc>().add(StopTypeChangedEvent(context.watch<StopType>()));
|
||||
_bloc.add(StopTypeChangedEvent(context.watch<StopType>()));
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -33,66 +35,83 @@ class _MeteringScreenState extends State<MeteringScreen> {
|
|||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).colorScheme.background,
|
||||
body: BlocBuilder<MeteringBloc, MeteringState>(
|
||||
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<MeteringBloc>().add(IsoChangedEvent(value)),
|
||||
onNdChanged: (value) => context.read<MeteringBloc>().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<MeteringBloc>().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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ class CalibrationDialog extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _CalibrationDialogState extends State<CalibrationDialog> {
|
||||
CalibrationDialogBloc get bloc => context.read<CalibrationDialogBloc>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
|
@ -37,8 +39,8 @@ class _CalibrationDialogState extends State<CalibrationDialog> {
|
|||
_CalibrationUnit(
|
||||
title: S.of(context).camera,
|
||||
value: state.cameraEvCalibration,
|
||||
onChanged: (value) => context.read<CalibrationDialogBloc>().add(CameraEvCalibrationChangedEvent(value)),
|
||||
onReset: () => context.read<CalibrationDialogBloc>().add(const CameraEvCalibrationResetEvent()),
|
||||
onChanged: (value) => bloc.add(CameraEvCalibrationChangedEvent(value)),
|
||||
onReset: () => bloc.add(const CameraEvCalibrationResetEvent()),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -56,7 +58,7 @@ class _CalibrationDialogState extends State<CalibrationDialog> {
|
|||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
context.read<CalibrationDialogBloc>().add(const SaveCalibrationDialogEvent());
|
||||
bloc.add(const SaveCalibrationDialogEvent());
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(S.of(context).save),
|
||||
|
|
|
@ -12,12 +12,9 @@ class VersionListTile extends StatelessWidget {
|
|||
title: Text(S.of(context).version),
|
||||
trailing: FutureBuilder<PackageInfo>(
|
||||
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(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<Environment>().contactEmail}?subject=M3 Lightmeter'));
|
||||
launchUrl(
|
||||
Uri.parse('mailto:${context.read<Environment>().contactEmail}?subject=M3 Lightmeter'));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -51,8 +51,14 @@ class _CenteredSliderState extends State<CenteredSlider> {
|
|||
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<CenteredSlider> {
|
|||
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),
|
||||
|
|
Loading…
Reference in a new issue