import 'dart:async'; import 'package:animated_custom_dropdown/custom_dropdown.dart'; import 'package:chewie/chewie.dart'; import 'package:didvan/config/design_config.dart'; import 'package:didvan/utils/date_time.dart'; import 'package:didvan/views/widgets/didvan/divider.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/video/play_btn_animation.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class PrimaryControls extends StatefulWidget { const PrimaryControls({super.key}); @override State createState() => _PrimaryControlsState(); } class _PrimaryControlsState extends State { late ChewieController chewieController; bool isAnimating = false; bool isAnimatingForward = false; bool isAnimatingBackward = false; // bool isSpeedMenuOpen = false; double opacity = 1; Timer? _hideControlsTimer; ValueNotifier position = ValueNotifier(Duration.zero); @override void didChangeDependencies() { super.didChangeDependencies(); chewieController = ChewieController.of(context); chewieController.videoPlayerController.addListener( () { position.value = chewieController.videoPlayerController.value.position; }, ); } void _startHideControlsTimer() { _hideControlsTimer?.cancel(); _hideControlsTimer = Timer(const Duration(seconds: 5), () { setState(() { opacity = 0; isAnimating = false; // if (isSpeedMenuOpen) { // Navigator.pop(context); // } }); }); } @override void dispose() { _hideControlsTimer?.cancel(); // Clean up the timer super.dispose(); } void _handlePlay() { { setState(() { if (chewieController.isPlaying) { chewieController.pause(); opacity = 1; } else { chewieController.play(); opacity = 0; } isAnimating = true; }); _startHideControlsTimer(); // Restart the timer on tap } } void onClickScreen() { if (opacity == 0) { setState(() { opacity = 1; }); _startHideControlsTimer(); // Restart the timer on tap } else { setState(() { opacity = 0; }); } } @override Widget build(BuildContext context) { return Directionality( textDirection: TextDirection.ltr, child: Stack( children: [ forwardBtn(), backwardBtn(), AnimatedOpacity( duration: const Duration(milliseconds: 400), opacity: opacity, child: Stack( children: [ seekPositions(), IgnorePointer( ignoring: opacity == 0, child: Stack( children: [ forground(), playAndPause(), ], ), ), ], ), ), ], ), ); } Positioned seekPositions() { return Positioned.fill( child: Row( children: [ Expanded( child: InkWell( onTap: onClickScreen, onDoubleTap: () async { if (position.value.inSeconds < 1) return; setState(() => isAnimatingBackward = true); Duration backward = Duration(seconds: position.value.inSeconds - 1); await chewieController.videoPlayerController.seekTo(backward); }, )), Expanded( child: InkWell( onTap: onClickScreen, onDoubleTap: () async { if (position.value.inSeconds > chewieController .videoPlayerController.value.duration.inSeconds - 1) return; setState(() => isAnimatingForward = true); Duration forward = Duration(seconds: position.value.inSeconds + 1); await chewieController.videoPlayerController.seekTo(forward); }, )), ], )); } Positioned playAndPause() { return Positioned.fill( child: Center( child: InkWell( onTap: _handlePlay, child: Opacity( opacity: isAnimatingBackward || isAnimatingForward ? 0 : 1, child: PlayBtnAnimation( alwaysAnimate: false, isAnimating: isAnimating, onEnd: () => setState( () => isAnimating = false, ), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.black.withValues(alpha: 0.4)), child: Icon( chewieController.isPlaying ? CupertinoIcons.pause_fill : CupertinoIcons.play_fill, color: Colors.white, size: 32, ), ), ), ), ))); } Positioned forwardBtn() { return Positioned.fill( child: Center( child: Opacity( opacity: isAnimatingForward ? 1 : 0, child: PlayBtnAnimation( alwaysAnimate: false, isAnimating: isAnimatingForward, onEnd: () => setState( () => isAnimatingForward = false, ), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.black.withValues(alpha: 0.4)), child: const Icon( Icons.forward_5_rounded, color: Colors.white, size: 32, ), ), ), ))); } Positioned backwardBtn() { return Positioned.fill( child: Center( child: Opacity( opacity: isAnimatingBackward ? 1 : 0, child: PlayBtnAnimation( alwaysAnimate: false, isAnimating: isAnimatingBackward, onEnd: () => setState( () => isAnimatingBackward = false, ), child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.black.withValues(alpha: 0.4)), child: const Icon( Icons.replay_5_rounded, color: Colors.white, size: 32, ), ), ), ))); } Positioned forground() { return Positioned( bottom: 0, left: 0, right: 0, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, colors: [ Colors.black, Colors.black87, Colors.black54, Colors.black45, Colors.black26, Color.fromARGB(10, 0, 0, 0) ])), child: Row( children: [ // _buildPlayPause(), _buildProgressIndicator(), _buildFullScreenToggle(), ], ), ), ); } Positioned speedPlayBackButtons() { return Positioned( top: 0, right: 0, left: 0, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.black, Colors.black87, Colors.black54, Colors.black45, Colors.black26, Color.fromARGB(10, 0, 0, 0) ])), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ SizedBox( width: 120, child: CustomDropdown( closedHeaderPadding: EdgeInsets.zero, itemsListPadding: EdgeInsets.zero, items: const [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], initialItem: 1, listItemPadding: EdgeInsets.zero, expandedHeaderPadding: EdgeInsets.zero, hideSelectedFieldWhenExpanded: false, // overlayHeight: // chewieController.isFullScreen ? null : 54 * 8, decoration: const CustomDropdownDecoration( closedSuffixIcon: SizedBox(), closedFillColor: Colors.transparent, expandedBorderRadius: DesignConfig.lowBorderRadius), // hintText: "سرعت ویدیو", listItemBuilder: (context, item, isSelected, onItemSelect) { return Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 8), child: Column( children: [ DidvanText('x$item'), if (item != 2) const DidvanDivider( verticalPadding: 8, ) ], )); }, headerBuilder: (context, selectedItem, enabled) => const Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Icon( Icons.more_vert_rounded, size: 32, color: Colors.white, ), ], ), hintBuilder: (context, hint, enabled) => const SizedBox(), onChanged: (value) async { // isSpeedMenuOpen = false; await chewieController.videoPlayerController .setPlaybackSpeed(value!); _startHideControlsTimer(); }, ), ), ], ), )); } Widget _buildProgressIndicator() { return Expanded( child: ValueListenableBuilder( valueListenable: position, builder: (context, p, _) { Duration duration = chewieController.videoPlayerController.value.duration; return Column( children: [ SliderTheme( data: SliderThemeData( trackHeight: 2, // thumbColor: Colors.transparent, overlayShape: SliderComponentShape.noOverlay, thumbShape: const RoundSliderThumbShape( // elevation: 0, // pressedElevation: 0, enabledThumbRadius: 8)), child: Slider( min: 0, max: duration.inMilliseconds.toDouble(), value: p.inMilliseconds.toDouble(), onChanged: (value) async { await chewieController.pause(); position.value = Duration(milliseconds: value.round()); _startHideControlsTimer(); }, onChangeEnd: (value) async { await chewieController .seekTo(Duration(milliseconds: value.round())); await chewieController.play(); setState(() {}); }, ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ DidvanText( DateTimeUtils.normalizeTimeDuration(p), color: Colors.white, fontSize: 16, ), DidvanText( DateTimeUtils.normalizeTimeDuration(duration), color: Colors.white, fontSize: 16, ) ], ) ], ); }, ), ); } Widget _buildFullScreenToggle() { return Padding( padding: const EdgeInsets.fromLTRB(12, 0, 8, 12), child: InkWell( onTap: () => setState(() { chewieController.toggleFullScreen(); _startHideControlsTimer(); // Restart the timer on tap }), child: Icon( chewieController.isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen, color: Colors.white, size: 30, ), ), ); } }