part of 'control_board.dart'; class _ContrastToneBar extends StatefulWidget { @override State createState() => _ContrastToneBarState(); } class _ContrastToneBarState extends State<_ContrastToneBar> { final playerController = Get.find() as VidPlayerController; @override void initState() { WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { if (mounted) { playerController.eventHandler.addListener(onControllerEvent); } }); super.initState(); } @override Widget build(BuildContext context) { final processor = playerController.getProcessor(); return _ToneBar( max: 99, min: -99, value: processor?.contrast.toDouble() ?? 0.0, icon: const Icon(Icons.brightness_medium), onChange: (v) { playerController.setContrast(v.toInt()); }, ); } @override void dispose() { playerController.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 createState() => _BrightnessToneBarState(); } class _BrightnessToneBarState extends State<_BrightnessToneBar> { final playerController = Get.find() as VidPlayerController; @override void initState() { WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { if (mounted) { playerController.eventHandler.addListener(onControllerEvent); } }); super.initState(); } @override Widget build(BuildContext context) { final processor = playerController.getProcessor(); return _ToneBar( max: 255, min: -255, value: processor?.brightness.toDouble() ?? 0.0, icon: const Icon(Icons.wb_sunny_sharp), onChange: (v) { playerController.setBrightness(v.toInt()); }, ); } @override void dispose() { playerController.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? onChange; final double min; final double max; final double value; @override State 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); } }