tone_bar.dart 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. part of 'control_board.dart';
  2. class _ContrastToneBar extends StatefulWidget {
  3. @override
  4. State<StatefulWidget> createState() => _ContrastToneBarState();
  5. }
  6. class _ContrastToneBarState extends State<_ContrastToneBar> {
  7. @override
  8. void initState() {
  9. WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
  10. if (mounted) {
  11. _SharedWidget.of(context)!
  12. .controller
  13. .eventHandler
  14. .addListener(onControllerEvent);
  15. }
  16. });
  17. super.initState();
  18. }
  19. @override
  20. Widget build(BuildContext context) {
  21. final controller = _SharedWidget.of(context)!.controller;
  22. final processor = controller.getProcessor<VidContrastProcessor>();
  23. return _ToneBar(
  24. max: 99,
  25. min: -99,
  26. value: processor?.contrast.toDouble() ?? 0.0,
  27. icon: const Icon(Icons.brightness_medium),
  28. onChange: (v) {
  29. controller.setContrast(v.toInt());
  30. },
  31. );
  32. }
  33. @override
  34. void dispose() {
  35. _SharedWidget.of(context)
  36. ?.controller
  37. .eventHandler
  38. .removeListener(onControllerEvent);
  39. super.dispose();
  40. }
  41. void onControllerEvent(Object sender, VidPlayerEvent e) {
  42. if (e is VidPlayerContrastChangeEvent) {
  43. onPlayStatusChanged(e);
  44. }
  45. }
  46. void onPlayStatusChanged(VidPlayerContrastChangeEvent e) {
  47. setState(() {});
  48. }
  49. }
  50. class _BrightnessToneBar extends StatefulWidget {
  51. @override
  52. State<StatefulWidget> createState() => _BrightnessToneBarState();
  53. }
  54. class _BrightnessToneBarState extends State<_BrightnessToneBar> {
  55. @override
  56. void initState() {
  57. WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
  58. if (mounted) {
  59. _SharedWidget.of(context)!
  60. .controller
  61. .eventHandler
  62. .addListener(onControllerEvent);
  63. }
  64. });
  65. super.initState();
  66. }
  67. @override
  68. Widget build(BuildContext context) {
  69. final controller = _SharedWidget.of(context)!.controller;
  70. final processor = controller.getProcessor<VidBrightnessProcessor>();
  71. return _ToneBar(
  72. max: 255,
  73. min: -255,
  74. value: processor?.brightness.toDouble() ?? 0.0,
  75. icon: const Icon(Icons.wb_sunny_sharp),
  76. onChange: (v) {
  77. controller.setBrightness(v.toInt());
  78. },
  79. );
  80. }
  81. @override
  82. void dispose() {
  83. _SharedWidget.of(context)
  84. ?.controller
  85. .eventHandler
  86. .removeListener(onControllerEvent);
  87. super.dispose();
  88. }
  89. void onControllerEvent(Object sender, VidPlayerEvent e) {
  90. if (e is VidPlayerBrightnessChangeEvent) {
  91. onPlayStatusChanged(e);
  92. }
  93. }
  94. void onPlayStatusChanged(VidPlayerBrightnessChangeEvent e) {
  95. setState(() {});
  96. }
  97. }
  98. class _ToneBar extends StatefulWidget {
  99. const _ToneBar({
  100. Key? key,
  101. required this.icon,
  102. required this.min,
  103. required this.max,
  104. required this.value,
  105. this.onChange,
  106. }) : super(key: key);
  107. final Widget icon;
  108. final ValueChanged<double>? onChange;
  109. final double min;
  110. final double max;
  111. final double value;
  112. @override
  113. State<StatefulWidget> createState() => _ToneBarState();
  114. }
  115. class _ToneBarState extends State<_ToneBar> {
  116. static const _kIconSize = 20.0;
  117. static const splashRadius = _kIconSize / 2 + 3;
  118. late double _value;
  119. @override
  120. void initState() {
  121. syncProps();
  122. super.initState();
  123. }
  124. @override
  125. void didUpdateWidget(covariant _ToneBar oldWidget) {
  126. syncProps();
  127. super.didUpdateWidget(oldWidget);
  128. }
  129. void syncProps() {
  130. _value = widget.value;
  131. }
  132. @override
  133. Widget build(BuildContext context) {
  134. return Row(
  135. children: [
  136. const SizedBox(width: 8),
  137. widget.icon,
  138. const SizedBox(width: 8),
  139. buildReduceIcon(),
  140. buildSlider(context),
  141. buildIncreaseIcon(),
  142. const SizedBox(width: 8),
  143. Text('${_value.toInt()}'),
  144. ],
  145. );
  146. }
  147. Widget buildReduceIcon() {
  148. return IconButton(
  149. constraints: const BoxConstraints(
  150. minHeight: _kIconSize,
  151. minWidth: _kIconSize,
  152. ),
  153. splashRadius: splashRadius,
  154. padding: EdgeInsets.zero,
  155. onPressed: () {
  156. updateValue(_value - 1);
  157. },
  158. icon: const Icon(Icons.remove_circle_outline, size: _kIconSize),
  159. );
  160. }
  161. Widget buildIncreaseIcon() {
  162. return IconButton(
  163. constraints: const BoxConstraints(
  164. minHeight: _kIconSize,
  165. minWidth: _kIconSize,
  166. ),
  167. splashRadius: splashRadius,
  168. padding: EdgeInsets.zero,
  169. onPressed: () {
  170. updateValue(_value + 1);
  171. },
  172. icon: const Icon(Icons.add_circle_outline, size: _kIconSize),
  173. );
  174. }
  175. Widget buildSlider(BuildContext context) {
  176. final trackColor = Theme.of(context).primaryColor;
  177. return SliderTheme(
  178. data: SliderThemeData(
  179. trackHeight: 4,
  180. activeTrackColor: trackColor,
  181. inactiveTrackColor: trackColor,
  182. thumbColor: Colors.grey[300],
  183. thumbShape: const RoundSliderThumbShape(
  184. enabledThumbRadius: 6,
  185. elevation: 3.0,
  186. ),
  187. overlayShape: SliderComponentShape.noOverlay,
  188. trackShape: const _FullWidthRectangularSliderTrackShape(
  189. padding: EdgeInsets.symmetric(horizontal: 4),
  190. ),
  191. ),
  192. child: Slider(
  193. max: widget.max,
  194. min: widget.min,
  195. value: _value,
  196. label: _value.toInt().toString(),
  197. divisions: (widget.max - widget.min).toInt(),
  198. onChanged: (v) {
  199. updateValue(v);
  200. },
  201. ),
  202. );
  203. }
  204. void updateValue(double value) {
  205. setState(() {
  206. _value = value;
  207. });
  208. widget.onChange?.call(value);
  209. }
  210. }
  211. class _FullWidthRectangularSliderTrackShape
  212. extends RectangularSliderTrackShape {
  213. const _FullWidthRectangularSliderTrackShape({this.padding});
  214. final EdgeInsets? padding;
  215. @override
  216. Rect getPreferredRect({
  217. required RenderBox parentBox,
  218. Offset offset = Offset.zero,
  219. required SliderThemeData sliderTheme,
  220. bool isEnabled = false,
  221. bool isDiscrete = false,
  222. }) {
  223. double trackHeight = sliderTheme.trackHeight ?? 2;
  224. double trackLeft = offset.dx;
  225. double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
  226. // 让轨道宽度等于 Slider 宽度
  227. double trackWidth = parentBox.size.width;
  228. if (padding != null) {
  229. trackHeight -= padding!.bottom;
  230. trackHeight -= padding!.top;
  231. trackWidth -= padding!.right;
  232. trackWidth -= padding!.left;
  233. trackTop += padding!.top;
  234. trackLeft += padding!.left;
  235. }
  236. return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
  237. }
  238. }