|
@@ -0,0 +1,266 @@
|
|
|
+part of 'control_board.dart';
|
|
|
+
|
|
|
+class _ContrastToneBar extends StatefulWidget {
|
|
|
+ @override
|
|
|
+ State<StatefulWidget> createState() => _ContrastToneBarState();
|
|
|
+}
|
|
|
+
|
|
|
+class _ContrastToneBarState extends State<_ContrastToneBar> {
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
|
|
|
+ if (mounted) {
|
|
|
+ _SharedWidget.of(context)!
|
|
|
+ .controller
|
|
|
+ .eventHandler
|
|
|
+ .addListener(onControllerEvent);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ super.initState();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final controller = _SharedWidget.of(context)!.controller;
|
|
|
+ final processor = controller.getProcessor<VidContrastProcessor>();
|
|
|
+ return _ToneBar(
|
|
|
+ max: 99,
|
|
|
+ min: -99,
|
|
|
+ value: processor?.contrast.toDouble() ?? 0.0,
|
|
|
+ icon: const Icon(Icons.brightness_medium),
|
|
|
+ onChange: (v) {
|
|
|
+ controller.setContrast(v.toInt());
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ _SharedWidget.of(context)
|
|
|
+ ?.controller
|
|
|
+ .eventHandler
|
|
|
+ .removeListener(onControllerEvent);
|
|
|
+ super.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ void onControllerEvent(Object sender, VidPlayerEvent e) {
|
|
|
+ if (e is VidPlayerContrastChangeEvent) {
|
|
|
+ onPlayStatusChanged(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void onPlayStatusChanged(VidPlayerContrastChangeEvent e) {
|
|
|
+ setState(() {});
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _BrightnessToneBar extends StatefulWidget {
|
|
|
+ @override
|
|
|
+ State<StatefulWidget> createState() => _BrightnessToneBarState();
|
|
|
+}
|
|
|
+
|
|
|
+class _BrightnessToneBarState extends State<_BrightnessToneBar> {
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
|
|
|
+ if (mounted) {
|
|
|
+ _SharedWidget.of(context)!
|
|
|
+ .controller
|
|
|
+ .eventHandler
|
|
|
+ .addListener(onControllerEvent);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ super.initState();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final controller = _SharedWidget.of(context)!.controller;
|
|
|
+ final processor = controller.getProcessor<VidBrightnessProcessor>();
|
|
|
+ return _ToneBar(
|
|
|
+ max: 255,
|
|
|
+ min: -255,
|
|
|
+ value: processor?.brightness.toDouble() ?? 0.0,
|
|
|
+ icon: const Icon(Icons.wb_sunny_sharp),
|
|
|
+ onChange: (v) {
|
|
|
+ controller.setBrightness(v.toInt());
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ _SharedWidget.of(context)
|
|
|
+ ?.controller
|
|
|
+ .eventHandler
|
|
|
+ .removeListener(onControllerEvent);
|
|
|
+ super.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ void onControllerEvent(Object sender, VidPlayerEvent e) {
|
|
|
+ if (e is VidPlayerBrightnessChangeEvent) {
|
|
|
+ onPlayStatusChanged(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void onPlayStatusChanged(VidPlayerBrightnessChangeEvent e) {
|
|
|
+ setState(() {});
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _ToneBar extends StatefulWidget {
|
|
|
+ const _ToneBar({
|
|
|
+ Key? key,
|
|
|
+ required this.icon,
|
|
|
+ required this.min,
|
|
|
+ required this.max,
|
|
|
+ required this.value,
|
|
|
+ this.onChange,
|
|
|
+ }) : super(key: key);
|
|
|
+
|
|
|
+ final Widget icon;
|
|
|
+ final ValueChanged<double>? onChange;
|
|
|
+ final double min;
|
|
|
+ final double max;
|
|
|
+ final double value;
|
|
|
+
|
|
|
+ @override
|
|
|
+ State<StatefulWidget> createState() => _ToneBarState();
|
|
|
+}
|
|
|
+
|
|
|
+class _ToneBarState extends State<_ToneBar> {
|
|
|
+ static const _kIconSize = 20.0;
|
|
|
+ static const splashRadius = _kIconSize / 2 + 3;
|
|
|
+
|
|
|
+ late double _value;
|
|
|
+
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ syncProps();
|
|
|
+ super.initState();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ void didUpdateWidget(covariant _ToneBar oldWidget) {
|
|
|
+ syncProps();
|
|
|
+ super.didUpdateWidget(oldWidget);
|
|
|
+ }
|
|
|
+
|
|
|
+ void syncProps() {
|
|
|
+ _value = widget.value;
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return Row(
|
|
|
+ children: [
|
|
|
+ const SizedBox(width: 8),
|
|
|
+ widget.icon,
|
|
|
+ const SizedBox(width: 8),
|
|
|
+ buildReduceIcon(),
|
|
|
+ buildSlider(context),
|
|
|
+ buildIncreaseIcon(),
|
|
|
+ const SizedBox(width: 8),
|
|
|
+ Text('${_value.toInt()}'),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget buildReduceIcon() {
|
|
|
+ return IconButton(
|
|
|
+ constraints: const BoxConstraints(
|
|
|
+ minHeight: _kIconSize,
|
|
|
+ minWidth: _kIconSize,
|
|
|
+ ),
|
|
|
+ splashRadius: splashRadius,
|
|
|
+ padding: EdgeInsets.zero,
|
|
|
+ onPressed: () {
|
|
|
+ updateValue(_value - 1);
|
|
|
+ },
|
|
|
+ icon: const Icon(Icons.remove_circle_outline, size: _kIconSize),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget buildIncreaseIcon() {
|
|
|
+ return IconButton(
|
|
|
+ constraints: const BoxConstraints(
|
|
|
+ minHeight: _kIconSize,
|
|
|
+ minWidth: _kIconSize,
|
|
|
+ ),
|
|
|
+ splashRadius: splashRadius,
|
|
|
+ padding: EdgeInsets.zero,
|
|
|
+ onPressed: () {
|
|
|
+ updateValue(_value + 1);
|
|
|
+ },
|
|
|
+ icon: const Icon(Icons.add_circle_outline, size: _kIconSize),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget buildSlider(BuildContext context) {
|
|
|
+ final trackColor = Theme.of(context).primaryColor;
|
|
|
+ return SliderTheme(
|
|
|
+ data: SliderThemeData(
|
|
|
+ trackHeight: 4,
|
|
|
+ activeTrackColor: trackColor,
|
|
|
+ inactiveTrackColor: trackColor,
|
|
|
+ thumbColor: Colors.grey[300],
|
|
|
+ thumbShape: const RoundSliderThumbShape(
|
|
|
+ enabledThumbRadius: 6,
|
|
|
+ elevation: 3.0,
|
|
|
+ ),
|
|
|
+ overlayShape: SliderComponentShape.noOverlay,
|
|
|
+ trackShape: const _FullWidthRectangularSliderTrackShape(
|
|
|
+ padding: EdgeInsets.symmetric(horizontal: 4),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Slider(
|
|
|
+ max: widget.max,
|
|
|
+ min: widget.min,
|
|
|
+ value: _value,
|
|
|
+ label: _value.toInt().toString(),
|
|
|
+ divisions: (widget.max - widget.min).toInt(),
|
|
|
+ onChanged: (v) {
|
|
|
+ updateValue(v);
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ void updateValue(double value) {
|
|
|
+ setState(() {
|
|
|
+ _value = value;
|
|
|
+ });
|
|
|
+ widget.onChange?.call(value);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class _FullWidthRectangularSliderTrackShape
|
|
|
+ extends RectangularSliderTrackShape {
|
|
|
+ const _FullWidthRectangularSliderTrackShape({this.padding});
|
|
|
+
|
|
|
+ final EdgeInsets? padding;
|
|
|
+
|
|
|
+ @override
|
|
|
+ Rect getPreferredRect({
|
|
|
+ required RenderBox parentBox,
|
|
|
+ Offset offset = Offset.zero,
|
|
|
+ required SliderThemeData sliderTheme,
|
|
|
+ bool isEnabled = false,
|
|
|
+ bool isDiscrete = false,
|
|
|
+ }) {
|
|
|
+ double trackHeight = sliderTheme.trackHeight ?? 2;
|
|
|
+ double trackLeft = offset.dx;
|
|
|
+ double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
|
|
|
+ // 让轨道宽度等于 Slider 宽度
|
|
|
+ double trackWidth = parentBox.size.width;
|
|
|
+ if (padding != null) {
|
|
|
+ trackHeight -= padding!.bottom;
|
|
|
+ trackHeight -= padding!.top;
|
|
|
+ trackWidth -= padding!.right;
|
|
|
+ trackWidth -= padding!.left;
|
|
|
+ trackTop += padding!.top;
|
|
|
+ trackLeft += padding!.left;
|
|
|
+ }
|
|
|
+ return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
|
|
|
+ }
|
|
|
+}
|