diff --git a/lib/views/ai/info_page.dart b/lib/views/ai/info_page.dart index 09cd770..1f4257a 100644 --- a/lib/views/ai/info_page.dart +++ b/lib/views/ai/info_page.dart @@ -7,6 +7,7 @@ import 'package:didvan/views/ai/info_state.dart'; import 'package:didvan/views/widgets/didvan/divider.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/hoshan_app_bar.dart'; +import 'package:didvan/views/widgets/state_handlers/empty_connection.dart'; import 'package:didvan/views/widgets/video/chat_video_player.dart'; import 'package:didvan/views/widgets/video/primary_controls.dart'; import 'package:flutter/material.dart'; @@ -37,6 +38,11 @@ class _InfoPageState extends State { ), ); } + if (state.appState == AppState.failed) { + return Center( + child: EmptyConnection(onRetry: state.getTools), + ); + } return Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/views/ai/info_state.dart b/lib/views/ai/info_state.dart index bfd1735..3389c8d 100644 --- a/lib/views/ai/info_state.dart +++ b/lib/views/ai/info_state.dart @@ -7,6 +7,9 @@ import 'package:didvan/services/network/request_helper.dart'; class InfoState extends CoreProvier { late InfoModel infoModel; void getTools() async { + appState = AppState.busy; + update(); + final service = RequestService( RequestHelper.info(), ); diff --git a/lib/views/home/home.dart b/lib/views/home/home.dart index 6f9cf38..7f65681 100644 --- a/lib/views/home/home.dart +++ b/lib/views/home/home.dart @@ -209,6 +209,18 @@ class _HomeState extends State confrimTitle: 'بله', dismissTitle: 'خیر', )); + } else if (context.read().tabController.index == 2) { + switch (context.read().page) { + case 1: + context.read().goToAi(); + break; + case 2: + context.read().goToTools(); + + break; + default: + _tabController.animateTo(0); + } } else { _tabController.animateTo(0); } diff --git a/lib/views/widgets/video/primary_controls.dart b/lib/views/widgets/video/primary_controls.dart index cb344bb..1f329db 100644 --- a/lib/views/widgets/video/primary_controls.dart +++ b/lib/views/widgets/video/primary_controls.dart @@ -20,6 +20,8 @@ class PrimaryControls extends StatefulWidget { class _PrimaryControlsState extends State { late ChewieController chewieController; bool isAnimating = false; + bool isAnimatingForward = false; + bool isAnimatingBackward = false; // bool isSpeedMenuOpen = false; double opacity = 1; @@ -67,187 +69,275 @@ class _PrimaryControlsState extends State { opacity = 0; } isAnimating = true; - - 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: AnimatedOpacity( - duration: const Duration(milliseconds: 400), - opacity: opacity, - child: InkWell( - onTap: () { - if (opacity == 0) { - setState(() { - opacity = 1; - }); - _startHideControlsTimer(); // Restart the timer on tap - } else { - setState(() { - opacity = 0; - }); - } - }, - child: IgnorePointer( - ignoring: opacity == 0, + child: Stack( + children: [ + forwardBtn(), + backwardBtn(), + AnimatedOpacity( + duration: const Duration(milliseconds: 400), + opacity: opacity, child: Stack( children: [ - 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(); - }, - ), - ), - ], - ), - )), - 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(), - ], - ), + seekPositions(), + IgnorePointer( + ignoring: opacity == 0, + child: Stack( + children: [ + forground(), + playAndPause(), + ], ), ), - Positioned.fill( - child: Center( - child: InkWell( - onTap: _handlePlay, - 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.withOpacity(0.4)), - child: Icon( - chewieController.isPlaying - ? CupertinoIcons.pause_fill - : CupertinoIcons.play_fill, - color: Colors.white, - size: 32, - ), - ), - ), - ))) ], ), ), + ], + ), + ); + } + + 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.withOpacity(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.withOpacity(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.withOpacity(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(