tone_bar.dart 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. part of 'operate_bar.dart';
  2. class _ContrastToneBar extends StatefulWidget {
  3. @override
  4. State<StatefulWidget> createState() => _ContrastToneBarState();
  5. }
  6. class _ContrastToneBarState extends State<_ContrastToneBar> {
  7. late final measureController = Get.find<MeasureController>();
  8. VidPlayerController playerController =
  9. Get.find<IPlayerController>() as VidPlayerController;
  10. ///屏幕缩放比例
  11. double get devicePixelRatio =>
  12. kIsMobile ? 1 : MediaQuery.of(context).devicePixelRatio;
  13. double curValue = 0;
  14. @override
  15. void initState() {
  16. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  17. if (mounted) {
  18. playerController.eventHandler.addListener(onControllerEvent);
  19. measureController.imageLoaded.addListener(updatePlayerController);
  20. }
  21. });
  22. super.initState();
  23. }
  24. /// 更新 controller
  25. void updatePlayerController(a, b) {
  26. playerController.eventHandler.removeListener(onControllerEvent);
  27. playerController = Get.find<IPlayerController>() as VidPlayerController;
  28. playerController.eventHandler.addListener(onControllerEvent);
  29. }
  30. @override
  31. Widget build(BuildContext context) {
  32. return _ToneBar(
  33. max: 100,
  34. min: -100,
  35. value: curValue,
  36. icon: Icon(
  37. Icons.contrast,
  38. color: Colors.white,
  39. size: 24 / devicePixelRatio,
  40. ),
  41. onChange: (v) {
  42. playerController.setContrast(v.toInt());
  43. },
  44. );
  45. }
  46. @override
  47. void dispose() {
  48. playerController.eventHandler.removeListener(onControllerEvent);
  49. measureController.imageLoaded.removeListener(updatePlayerController);
  50. super.dispose();
  51. }
  52. void onControllerEvent(Object sender, VidPlayerEvent e) {
  53. if (e is VidPlayResetToneEvent) {
  54. onResetTone();
  55. }
  56. }
  57. void onResetTone() {
  58. setState(() {
  59. curValue = 0;
  60. });
  61. }
  62. }
  63. class _BrightnessToneBar extends StatefulWidget {
  64. @override
  65. State<StatefulWidget> createState() => _BrightnessToneBarState();
  66. }
  67. class _BrightnessToneBarState extends State<_BrightnessToneBar> {
  68. late final measureController = Get.find<MeasureController>();
  69. VidPlayerController playerController =
  70. Get.find<IPlayerController>() as VidPlayerController;
  71. ///屏幕缩放比例
  72. double get devicePixelRatio =>
  73. kIsMobile ? 1 : MediaQuery.of(context).devicePixelRatio;
  74. double curValue = 0;
  75. @override
  76. void initState() {
  77. WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
  78. if (mounted) {
  79. playerController.eventHandler.addListener(onControllerEvent);
  80. measureController.imageLoaded.addListener(updatePlayerController);
  81. }
  82. });
  83. super.initState();
  84. }
  85. /// 更新 controller
  86. void updatePlayerController(a, b) {
  87. playerController.eventHandler.removeListener(onControllerEvent);
  88. playerController = Get.find<IPlayerController>() as VidPlayerController;
  89. playerController.eventHandler.addListener(onControllerEvent);
  90. }
  91. @override
  92. Widget build(BuildContext context) {
  93. return _ToneBar(
  94. max: 100,
  95. min: -100,
  96. value: curValue,
  97. icon: Icon(
  98. Icons.wb_sunny_sharp,
  99. color: Colors.white,
  100. size: 24 / devicePixelRatio,
  101. ),
  102. onChange: (v) {
  103. playerController.setBrightness(v.toInt());
  104. },
  105. );
  106. }
  107. @override
  108. void dispose() {
  109. playerController.eventHandler.removeListener(onControllerEvent);
  110. measureController.imageLoaded.removeListener(updatePlayerController);
  111. super.dispose();
  112. }
  113. void onControllerEvent(Object sender, VidPlayerEvent e) {
  114. if (e is VidPlayResetToneEvent) {
  115. onResetTone();
  116. }
  117. }
  118. void onResetTone() {
  119. setState(() {
  120. curValue = 0;
  121. });
  122. }
  123. }
  124. class _ToneBar extends StatefulWidget {
  125. const _ToneBar({
  126. Key? key,
  127. required this.icon,
  128. required this.min,
  129. required this.max,
  130. required this.value,
  131. this.onChange,
  132. }) : super(key: key);
  133. final Widget icon;
  134. final ValueChanged<double>? onChange;
  135. final double min;
  136. final double max;
  137. final double value;
  138. final Color themeColor = Colors.white;
  139. @override
  140. State<StatefulWidget> createState() => _ToneBarState();
  141. }
  142. class _ToneBarState extends State<_ToneBar> {
  143. double get _kIconSize => 20.0 / devicePixelRatio;
  144. double get splashRadius => _kIconSize / 2 + 3;
  145. double get devicePixelRatio =>
  146. kIsMobile ? 1 : MediaQuery.of(context).devicePixelRatio;
  147. late double _value;
  148. @override
  149. void initState() {
  150. syncProps();
  151. super.initState();
  152. }
  153. @override
  154. void didUpdateWidget(covariant _ToneBar oldWidget) {
  155. syncProps();
  156. super.didUpdateWidget(oldWidget);
  157. }
  158. void syncProps() {
  159. _value = widget.value;
  160. }
  161. @override
  162. Widget build(BuildContext context) {
  163. return Row(
  164. mainAxisAlignment: MainAxisAlignment.center,
  165. children: [
  166. widget.icon,
  167. const SizedBox(width: 8),
  168. buildReduceIcon(),
  169. buildSlider(context),
  170. buildIncreaseIcon(),
  171. const SizedBox(width: 8),
  172. SizedBox(
  173. width: 30 / devicePixelRatio,
  174. child: Text(
  175. '${_value.toInt()}',
  176. style: TextStyle(color: widget.themeColor),
  177. )),
  178. ],
  179. );
  180. }
  181. Widget buildReduceIcon() {
  182. return IconButton(
  183. color: widget.themeColor,
  184. constraints: BoxConstraints(
  185. minHeight: _kIconSize,
  186. minWidth: _kIconSize,
  187. ),
  188. splashRadius: splashRadius,
  189. padding: EdgeInsets.zero,
  190. onPressed: () {
  191. updateValue(_value - 1);
  192. },
  193. icon: Icon(Icons.remove_circle_outline, size: _kIconSize),
  194. );
  195. }
  196. Widget buildIncreaseIcon() {
  197. return IconButton(
  198. color: widget.themeColor,
  199. constraints: BoxConstraints(
  200. minHeight: _kIconSize,
  201. minWidth: _kIconSize,
  202. ),
  203. splashRadius: splashRadius,
  204. padding: EdgeInsets.zero,
  205. onPressed: () {
  206. updateValue(_value + 1);
  207. },
  208. icon: Icon(Icons.add_circle_outline, size: _kIconSize),
  209. );
  210. }
  211. Widget buildSlider(BuildContext context) {
  212. final trackColor = Theme.of(context).primaryColor;
  213. return Expanded(
  214. child: SliderTheme(
  215. data: SliderThemeData(
  216. trackHeight: 4,
  217. activeTrackColor: trackColor,
  218. inactiveTrackColor: trackColor,
  219. thumbColor: Colors.grey[300],
  220. thumbShape: const RoundSliderThumbShape(
  221. enabledThumbRadius: 6,
  222. elevation: 3.0,
  223. ),
  224. overlayShape: SliderComponentShape.noOverlay,
  225. trackShape: _FullWidthRectangularSliderTrackShape(
  226. padding: const EdgeInsets.symmetric(horizontal: 4),
  227. devicePixelRatio: devicePixelRatio,
  228. ),
  229. ),
  230. child: Slider(
  231. max: widget.max,
  232. min: widget.min,
  233. value: _value,
  234. label: _value.toInt().toString(),
  235. divisions: (widget.max - widget.min).toInt(),
  236. onChanged: (v) {
  237. updateValue(v);
  238. },
  239. ),
  240. ),
  241. );
  242. }
  243. void updateValue(double value) {
  244. if (value < widget.min || value > widget.max) {
  245. return;
  246. }
  247. setState(() {
  248. _value = value;
  249. });
  250. widget.onChange?.call(value);
  251. }
  252. }
  253. class _FullWidthRectangularSliderTrackShape
  254. extends RectangularSliderTrackShape {
  255. const _FullWidthRectangularSliderTrackShape({
  256. this.padding,
  257. this.devicePixelRatio = 1,
  258. });
  259. final EdgeInsets? padding;
  260. final double devicePixelRatio;
  261. @override
  262. Rect getPreferredRect({
  263. required RenderBox parentBox,
  264. Offset offset = Offset.zero,
  265. required SliderThemeData sliderTheme,
  266. bool isEnabled = false,
  267. bool isDiscrete = false,
  268. }) {
  269. double trackHeight = sliderTheme.trackHeight ?? 2;
  270. double trackLeft = offset.dx;
  271. double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
  272. // 让轨道宽度等于 Slider 宽度
  273. double trackWidth = parentBox.size.width;
  274. if (padding != null) {
  275. trackHeight -= padding!.bottom;
  276. trackHeight -= padding!.top;
  277. trackWidth -= padding!.right;
  278. trackWidth -= padding!.left;
  279. trackTop += padding!.top;
  280. trackLeft += padding!.left;
  281. }
  282. return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
  283. }
  284. }
  285. class _ResetToneButton extends StatelessWidget {
  286. @override
  287. Widget build(BuildContext context) {
  288. return ElevatedButton(
  289. onPressed: () {
  290. final playerController =
  291. Get.find<IPlayerController>() as VidPlayerController;
  292. playerController.resetTone();
  293. },
  294. child: Text(
  295. i18nBook.measure.resetTone4Btn.t,
  296. style: const TextStyle(
  297. color: Colors.white,
  298. fontSize: 16,
  299. ),
  300. ),
  301. );
  302. }
  303. }