tone_bar.dart 6.3 KB

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