diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart index e3eed95..8804889 100644 --- a/lib/res/dimens.dart +++ b/lib/res/dimens.dart @@ -38,7 +38,7 @@ class Dimens { // `CenteredSlider` static const double cameraSliderTrackHeight = grid4; static const double cameraSliderTrackRadius = cameraSliderTrackHeight / 2; - static const double cameraSliderHandleSize = 32; + static const double cameraSliderHandleSize = 24; static const double cameraSliderHandleIconSize = cameraSliderHandleSize * 2 / 3; // Dialog diff --git a/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart b/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart index 40ec1f0..b68673e 100644 --- a/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart +++ b/lib/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/generated/l10n.dart'; -import 'package:lightmeter/res/dimens.dart'; -import 'package:lightmeter/screens/shared/centered_slider/widget_slider_centered.dart'; +import 'package:lightmeter/screens/shared/ruler_slider/widget_slider_ruler.dart'; import 'package:lightmeter/utils/to_string_signed.dart'; class ExposureOffsetSlider extends StatelessWidget { @@ -26,68 +25,15 @@ class ExposureOffsetSlider extends StatelessWidget { tooltip: S.of(context).tooltipResetToZero, ), Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: Dimens.grid8), - child: _Ruler( - range.start, - range.end, - ), - ), - CenteredSlider( - isVertical: true, - icon: const Icon(Icons.light_mode), - value: value, - min: range.start, - max: range.end, - onChanged: onChanged, - ), - ], + child: RulerSlider( + icon: Icons.light_mode, + range: range, + value: value, + onChanged: onChanged, + rulerValueAdapter: (value) => value.toStringSignedAsFixed(0), ), ), ], ); } } - -class _Ruler extends StatelessWidget { - final double min; - final double max; - - const _Ruler(this.min, this.max); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: List.generate( - (max - min + 1).toInt(), - (index) { - final bool showValue = index % 2 == 0.0 || index == 0.0; - return Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - if (showValue) - Text( - (index + min).toStringSignedAsFixed(0), - style: Theme.of(context).textTheme.bodyLarge, - ), - const SizedBox(width: Dimens.grid8), - ColoredBox( - color: Theme.of(context).colorScheme.onBackground, - child: SizedBox( - height: 1, - width: showValue ? Dimens.grid16 : Dimens.grid8, - ), - ), - const SizedBox(width: Dimens.grid8), - ], - ); - }, - ).reversed.toList(), - ); - } -} diff --git a/lib/screens/metering/components/camera_container/components/camera_controls/components/zoom_slider/widget_slider_zoom.dart b/lib/screens/metering/components/camera_container/components/camera_controls/components/zoom_slider/widget_slider_zoom.dart index e3619df..7a30ea6 100644 --- a/lib/screens/metering/components/camera_container/components/camera_controls/components/zoom_slider/widget_slider_zoom.dart +++ b/lib/screens/metering/components/camera_container/components/camera_controls/components/zoom_slider/widget_slider_zoom.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:lightmeter/screens/shared/centered_slider/widget_slider_centered.dart'; +import 'package:lightmeter/screens/shared/ruler_slider/widget_slider_ruler.dart'; class ZoomSlider extends StatelessWidget { final RangeValues range; @@ -15,12 +15,22 @@ class ZoomSlider extends StatelessWidget { @override Widget build(BuildContext context) { - return CenteredSlider( - icon: const Icon(Icons.search), - value: value, - min: range.start, - max: range.end, - onChanged: onChanged, + return Column( + children: [ + const IconButton( + icon: Icon(Icons.lock_open), + onPressed: null, + ), + Expanded( + child: RulerSlider( + icon: Icons.search, + range: range, + value: value, + onChanged: onChanged, + rulerValueAdapter: (value) => '${value.toStringAsFixed(0)}x', + ), + ), + ], ); } } diff --git a/lib/screens/metering/components/camera_container/components/camera_controls/widget_camera_controls.dart b/lib/screens/metering/components/camera_container/components/camera_controls/widget_camera_controls.dart index 493bbef..672d316 100644 --- a/lib/screens/metering/components/camera_container/components/camera_controls/widget_camera_controls.dart +++ b/lib/screens/metering/components/camera_container/components/camera_controls/widget_camera_controls.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/screens/metering/components/camera_container/components/camera_controls/components/exposure_offset_slider/widget_slider_exposure_offset.dart'; import 'package:lightmeter/screens/metering/components/camera_container/components/camera_controls/components/zoom_slider/widget_slider_zoom.dart'; @@ -25,16 +24,14 @@ class CameraControls extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Expanded( - child: ExposureOffsetSlider( - range: exposureOffsetRange, - value: exposureOffsetValue, - onChanged: onExposureOffsetChanged, - ), + ExposureOffsetSlider( + range: exposureOffsetRange, + value: exposureOffsetValue, + onChanged: onExposureOffsetChanged, ), - const SizedBox(height: Dimens.grid24), ZoomSlider( range: zoomRange, value: zoomValue, diff --git a/lib/screens/metering/components/camera_container/widget_container_camera.dart b/lib/screens/metering/components/camera_container/widget_container_camera.dart index ceaca91..c45de84 100644 --- a/lib/screens/metering/components/camera_container/widget_container_camera.dart +++ b/lib/screens/metering/components/camera_container/widget_container_camera.dart @@ -157,7 +157,12 @@ class _CameraControlsBuilder extends StatelessWidget { @override Widget build(BuildContext context) { return Padding( - padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM), + padding: const EdgeInsets.fromLTRB( + Dimens.paddingL, + Dimens.paddingM, + 0, + Dimens.paddingL, + ), child: BlocBuilder( builder: (context, state) { late final Widget child; diff --git a/lib/screens/shared/ruler_slider/widget_slider_ruler.dart b/lib/screens/shared/ruler_slider/widget_slider_ruler.dart new file mode 100644 index 0000000..9c6e318 --- /dev/null +++ b/lib/screens/shared/ruler_slider/widget_slider_ruler.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/res/dimens.dart'; +import 'package:lightmeter/screens/shared/centered_slider/widget_slider_centered.dart'; + +class RulerSlider extends StatelessWidget { + final IconData icon; + final RangeValues range; + final double value; + final ValueChanged onChanged; + final String Function(double value) rulerValueAdapter; + + const RulerSlider({ + required this.icon, + required this.range, + required this.value, + required this.onChanged, + required this.rulerValueAdapter, + super.key, + }); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + _Ruler( + range.start, + range.end, + rulerValueAdapter, + ), + CenteredSlider( + isVertical: true, + icon: Icon(icon), + value: value, + min: range.start, + max: range.end, + onChanged: onChanged, + ), + ], + ); + } +} + +class _Ruler extends StatelessWidget { + final double min; + final double max; + final String Function(double value) rulerValueAdapter; + late final int mainTicksCount = (max - min + 1).toInt(); + late final int itemsCount = mainTicksCount * 2 - 1; + + _Ruler( + this.min, + this.max, + this.rulerValueAdapter, + ); + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + final bool showAllMainTicks = Dimens.cameraSliderHandleSize * mainTicksCount <= constraints.maxHeight; + return Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.generate( + itemsCount, + (index) { + final bool isMainTick = index % 2 == 0.0; + if (!showAllMainTicks && !isMainTick) { + return const SizedBox(); + } + final bool showValue = (index % (showAllMainTicks ? 2 : 4) == 0.0); + return SizedBox( + height: index == itemsCount - 1 || showValue ? Dimens.cameraSliderHandleSize : 1, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + if (showValue) + Text( + rulerValueAdapter(index / 2 + min), + style: Theme.of(context).textTheme.bodySmall, + ), + const SizedBox(width: Dimens.grid4), + ColoredBox( + color: Theme.of(context).colorScheme.onBackground, + child: SizedBox( + height: 1, + width: isMainTick ? Dimens.grid8 : Dimens.grid4, + ), + ), + const SizedBox(width: Dimens.grid4), + ], + ), + ); + }, + ).reversed.toList(), + ); + }, + ); + } +}