mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-22 07:20:39 +00:00
made zoom slider vertical & added more ticks to ruler
This commit is contained in:
parent
bfd0bfe531
commit
26175c2c3e
6 changed files with 137 additions and 79 deletions
|
@ -38,7 +38,7 @@ class Dimens {
|
||||||
// `CenteredSlider`
|
// `CenteredSlider`
|
||||||
static const double cameraSliderTrackHeight = grid4;
|
static const double cameraSliderTrackHeight = grid4;
|
||||||
static const double cameraSliderTrackRadius = cameraSliderTrackHeight / 2;
|
static const double cameraSliderTrackRadius = cameraSliderTrackHeight / 2;
|
||||||
static const double cameraSliderHandleSize = 32;
|
static const double cameraSliderHandleSize = 24;
|
||||||
static const double cameraSliderHandleIconSize = cameraSliderHandleSize * 2 / 3;
|
static const double cameraSliderHandleIconSize = cameraSliderHandleSize * 2 / 3;
|
||||||
|
|
||||||
// Dialog
|
// Dialog
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/screens/shared/ruler_slider/widget_slider_ruler.dart';
|
||||||
import 'package:lightmeter/screens/shared/centered_slider/widget_slider_centered.dart';
|
|
||||||
import 'package:lightmeter/utils/to_string_signed.dart';
|
import 'package:lightmeter/utils/to_string_signed.dart';
|
||||||
|
|
||||||
class ExposureOffsetSlider extends StatelessWidget {
|
class ExposureOffsetSlider extends StatelessWidget {
|
||||||
|
@ -26,68 +25,15 @@ class ExposureOffsetSlider extends StatelessWidget {
|
||||||
tooltip: S.of(context).tooltipResetToZero,
|
tooltip: S.of(context).tooltipResetToZero,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Row(
|
child: RulerSlider(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
icon: Icons.light_mode,
|
||||||
children: [
|
range: range,
|
||||||
Padding(
|
value: value,
|
||||||
padding: const EdgeInsets.symmetric(vertical: Dimens.grid8),
|
onChanged: onChanged,
|
||||||
child: _Ruler(
|
rulerValueAdapter: (value) => value.toStringSignedAsFixed(0),
|
||||||
range.start,
|
|
||||||
range.end,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CenteredSlider(
|
|
||||||
isVertical: true,
|
|
||||||
icon: const Icon(Icons.light_mode),
|
|
||||||
value: value,
|
|
||||||
min: range.start,
|
|
||||||
max: range.end,
|
|
||||||
onChanged: onChanged,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
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 {
|
class ZoomSlider extends StatelessWidget {
|
||||||
final RangeValues range;
|
final RangeValues range;
|
||||||
|
@ -15,12 +15,22 @@ class ZoomSlider extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CenteredSlider(
|
return Column(
|
||||||
icon: const Icon(Icons.search),
|
children: [
|
||||||
value: value,
|
const IconButton(
|
||||||
min: range.start,
|
icon: Icon(Icons.lock_open),
|
||||||
max: range.end,
|
onPressed: null,
|
||||||
onChanged: onChanged,
|
),
|
||||||
|
Expanded(
|
||||||
|
child: RulerSlider(
|
||||||
|
icon: Icons.search,
|
||||||
|
range: range,
|
||||||
|
value: value,
|
||||||
|
onChanged: onChanged,
|
||||||
|
rulerValueAdapter: (value) => '${value.toStringAsFixed(0)}x',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:flutter/material.dart';
|
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/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';
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
ExposureOffsetSlider(
|
||||||
child: ExposureOffsetSlider(
|
range: exposureOffsetRange,
|
||||||
range: exposureOffsetRange,
|
value: exposureOffsetValue,
|
||||||
value: exposureOffsetValue,
|
onChanged: onExposureOffsetChanged,
|
||||||
onChanged: onExposureOffsetChanged,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: Dimens.grid24),
|
|
||||||
ZoomSlider(
|
ZoomSlider(
|
||||||
range: zoomRange,
|
range: zoomRange,
|
||||||
value: zoomValue,
|
value: zoomValue,
|
||||||
|
|
|
@ -157,7 +157,12 @@ class _CameraControlsBuilder extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
|
padding: const EdgeInsets.fromLTRB(
|
||||||
|
Dimens.paddingL,
|
||||||
|
Dimens.paddingM,
|
||||||
|
0,
|
||||||
|
Dimens.paddingL,
|
||||||
|
),
|
||||||
child: BlocBuilder<CameraContainerBloc, CameraContainerState>(
|
child: BlocBuilder<CameraContainerBloc, CameraContainerState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
late final Widget child;
|
late final Widget child;
|
||||||
|
|
100
lib/screens/shared/ruler_slider/widget_slider_ruler.dart
Normal file
100
lib/screens/shared/ruler_slider/widget_slider_ruler.dart
Normal file
|
@ -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<double> 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(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue