From 00f108710a7076027566d1bb3acc05a60a96748b Mon Sep 17 00:00:00 2001 From: MohammadTaha Basiri Date: Mon, 4 Apr 2022 14:16:21 +0430 Subject: [PATCH] new video player basic version --- ios/Podfile | 2 +- ios/Podfile.lock | 99 ++++-- .../studio_details/studio_details.mobile.dart | 195 +++--------- .../studio_details/studio_details.web.dart | 19 +- .../widgets/details_tab_bar.dart | 3 - .../widgets/studio_details_widget.dart | 296 +++++++++--------- lib/views/widgets/didvan/bnb.dart | 6 - pubspec.lock | 63 ++++ pubspec.yaml | 1 + 9 files changed, 331 insertions(+), 353 deletions(-) diff --git a/ios/Podfile b/ios/Podfile index 9411102..313ea4a 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '10.0' +platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 98e5804..5e2c2df 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,33 +1,40 @@ PODS: - audio_session (0.0.1): - Flutter - - Firebase/CoreOnly (8.11.0): - - FirebaseCore (= 8.11.0) - - Firebase/Messaging (8.11.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 8.11.0) - - firebase_core (1.13.1): - - Firebase/CoreOnly (= 8.11.0) + - better_player (0.0.1): + - Cache (~> 6.0.0) - Flutter - - firebase_messaging (11.2.8): - - Firebase/Messaging (= 8.11.0) + - GCDWebServer + - HLSCachingReverseProxyServer + - PINCache + - Cache (6.0.0) + - Firebase/CoreOnly (8.14.0): + - FirebaseCore (= 8.14.0) + - Firebase/Messaging (8.14.0): + - Firebase/CoreOnly + - FirebaseMessaging (~> 8.14.0) + - firebase_core (1.14.0): + - Firebase/CoreOnly (= 8.14.0) + - Flutter + - firebase_messaging (11.2.12): + - Firebase/Messaging (= 8.14.0) - firebase_core - Flutter - - FirebaseCore (8.11.0): + - FirebaseCore (8.14.0): - FirebaseCoreDiagnostics (~> 8.0) - GoogleUtilities/Environment (~> 7.7) - GoogleUtilities/Logger (~> 7.7) - - FirebaseCoreDiagnostics (8.12.0): + - FirebaseCoreDiagnostics (8.14.0): - GoogleDataTransport (~> 9.1) - GoogleUtilities/Environment (~> 7.7) - GoogleUtilities/Logger (~> 7.7) - nanopb (~> 2.30908.0) - - FirebaseInstallations (8.12.0): + - FirebaseInstallations (8.14.0): - FirebaseCore (~> 8.0) - GoogleUtilities/Environment (~> 7.7) - GoogleUtilities/UserDefaults (~> 7.7) - PromisesObjC (< 3.0, >= 1.2) - - FirebaseMessaging (8.11.0): + - FirebaseMessaging (8.14.0): - FirebaseCore (~> 8.0) - FirebaseInstallations (~> 8.0) - GoogleDataTransport (~> 9.1) @@ -44,6 +51,9 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) + - GCDWebServer (3.5.4): + - GCDWebServer/Core (= 3.5.4) + - GCDWebServer/Core (3.5.4) - GoogleDataTransport (9.1.2): - GoogleUtilities/Environment (~> 7.2) - nanopb (~> 2.30908.0) @@ -65,6 +75,9 @@ PODS: - GoogleUtilities/Logger - GoogleUtilities/UserDefaults (7.7.0): - GoogleUtilities/Logger + - HLSCachingReverseProxyServer (0.1.0): + - GCDWebServer (~> 3.5) + - PINCache (>= 3.0.1-beta.3) - image_cropper (0.0.4): - Flutter - TOCropViewController (~> 2.6.1) @@ -79,8 +92,16 @@ PODS: - nanopb/encode (2.30908.0) - path_provider_ios (0.0.1): - Flutter - - permission_handler_apple (9.0.2): + - permission_handler_apple (9.0.4): - Flutter + - PINCache (3.0.3): + - PINCache/Arc-exception-safe (= 3.0.3) + - PINCache/Core (= 3.0.3) + - PINCache/Arc-exception-safe (3.0.3): + - PINCache/Core + - PINCache/Core (3.0.3): + - PINOperation (~> 1.2.1) + - PINOperation (1.2.1) - PromisesObjC (2.0.0) - record (0.0.1): - Flutter @@ -90,11 +111,16 @@ PODS: - TOCropViewController (2.6.1) - url_launcher_ios (0.0.1): - Flutter + - video_player_avfoundation (0.0.1): + - Flutter + - wakelock (0.0.1): + - Flutter - webview_flutter_wkwebview (0.0.1): - Flutter DEPENDENCIES: - audio_session (from `.symlinks/plugins/audio_session/ios`) + - better_player (from `.symlinks/plugins/better_player/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - Flutter (from `Flutter`) @@ -108,25 +134,34 @@ DEPENDENCIES: - record (from `.symlinks/plugins/record/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) + - wakelock (from `.symlinks/plugins/wakelock/ios`) - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) SPEC REPOS: trunk: + - Cache - Firebase - FirebaseCore - FirebaseCoreDiagnostics - FirebaseInstallations - FirebaseMessaging - FMDB + - GCDWebServer - GoogleDataTransport - GoogleUtilities + - HLSCachingReverseProxyServer - nanopb + - PINCache + - PINOperation - PromisesObjC - TOCropViewController EXTERNAL SOURCES: audio_session: :path: ".symlinks/plugins/audio_session/ios" + better_player: + :path: ".symlinks/plugins/better_player/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" firebase_messaging: @@ -153,37 +188,49 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/sqflite/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" + video_player_avfoundation: + :path: ".symlinks/plugins/video_player_avfoundation/ios" + wakelock: + :path: ".symlinks/plugins/wakelock/ios" webview_flutter_wkwebview: :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: audio_session: 4f3e461722055d21515cf3261b64c973c062f345 - Firebase: 44dd9724c84df18b486639e874f31436eaa9a20c - firebase_core: 08f6a85f62060111de5e98d6a214810d11365de9 - firebase_messaging: 36238f3d0b933af8c919aef608408aae06ba22e8 - FirebaseCore: 2f4f85b453cc8fea4bb2b37e370007d2bcafe3f0 - FirebaseCoreDiagnostics: 3b40dfadef5b90433a60ae01f01e90fe87aa76aa - FirebaseInstallations: 25764cf322e77f99449395870a65b2bef88e1545 - FirebaseMessaging: 02e248e8997f71fa8cc9d78e9d49ec1a701ba14a + better_player: 2406bfe8175203c7a46fa15f9d778d73b12e1646 + Cache: 4ca7e00363fca5455f26534e5607634c820ffc2d + Firebase: 7e8fe528c161b9271d365217a74c16aaf834578e + firebase_core: b0b382f1497ab407aceb25e41e3036c8798c1609 + firebase_messaging: 34dd10d1aa6d8f40d03660eeacd0452d62eec7aa + FirebaseCore: b84a44ee7ba999e0f9f76d198a9c7f60a797b848 + FirebaseCoreDiagnostics: fd0c8490f34287229c1d6c103d3a55f81ec85712 + FirebaseInstallations: 7d1d967a307c12f1aadd76844fc321cef699b1ce + FirebaseMessaging: 5ebc42d281567658a2cb72b9ef3506e4a1a1a6e4 Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec flutter_vibrate: 9f4c2ab57008965f78969472367c329dd77eb801 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4 GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 + HLSCachingReverseProxyServer: 59935e1e0244ad7f3375d75b5ef46e8eb26ab181 image_cropper: 60c2789d1f1a78c873235d4319ca0c34a69f2d98 - image_picker: 9aa50e1d8cdacdbed739e925b7eea16d014367e6 + image_picker: 541dcbb3b9cf32d87eacbd957845d8651d6c62c3 just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 - path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5 - permission_handler_apple: d21b38e1a4b2e041c63af9568f9165e114e507a6 + path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 + permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce + PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 + PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 record: 7ee2393532f8553bbb09fa19e95478323b7c0a99 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863 - url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af + url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de + video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff + wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f webview_flutter_wkwebview: 005fbd90c888a42c5690919a1527ecc6649e1162 -PODFILE CHECKSUM: fe0e1ee7f3d1f7d00b11b474b62dd62134535aea +PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d COCOAPODS: 1.11.2 diff --git a/lib/views/home/studio/studio_details/studio_details.mobile.dart b/lib/views/home/studio/studio_details/studio_details.mobile.dart index 276d426..ea72e90 100644 --- a/lib/views/home/studio/studio_details/studio_details.mobile.dart +++ b/lib/views/home/studio/studio_details/studio_details.mobile.dart @@ -1,16 +1,15 @@ import 'dart:io'; -import 'package:didvan/config/design_config.dart'; +import 'package:better_player/better_player.dart'; import 'package:didvan/models/view/app_bar_data.dart'; import 'package:didvan/services/media/media.dart'; import 'package:didvan/views/home/studio/studio_details/studio_details_state.dart'; import 'package:didvan/views/home/studio/studio_details/widgets/details_tab_bar.dart'; import 'package:didvan/views/home/studio/studio_details/widgets/studio_details_widget.dart'; import 'package:didvan/views/home/widgets/bookmark_button.dart'; -import 'package:didvan/views/widgets/didvan/scaffold.dart'; +import 'package:didvan/views/widgets/didvan/app_bar.dart'; import 'package:didvan/views/widgets/state_handlers/state_handler.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:webview_flutter/webview_flutter.dart'; @@ -26,61 +25,23 @@ class StudioDetails extends StatefulWidget { class _StudioDetailsState extends State { final _scrollController = ScrollController(); - bool _isFullScreen = false; - bool _isInit = true; - - double _dwInPortrait = 0; - double _scaleInPortrait = 1; @override void initState() { final state = context.read(); + state.args = widget.pageData['args']; Future.delayed( Duration.zero, () => state.getStudioDetails(widget.pageData['id']), ); - state.args = widget.pageData['args']; + if (Platform.isAndroid) WebView.platform = AndroidWebView(); super.initState(); } - Future _changeFullSceen(bool value) async { - if (value) { - await SystemChrome.setEnabledSystemUIMode( - SystemUiMode.manual, - overlays: [], - ); - SystemChrome.setSystemUIOverlayStyle( - const SystemUiOverlayStyle( - systemNavigationBarColor: Colors.black, - ), - ); - await SystemChrome.setPreferredOrientations( - [DeviceOrientation.landscapeLeft], - ); - } else { - await SystemChrome.setEnabledSystemUIMode( - SystemUiMode.manual, - overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top], - ); - await SystemChrome.setPreferredOrientations( - [DeviceOrientation.portraitUp], - ); - DesignConfig.updateSystemUiOverlayStyle(); - } - setState(() { - _isFullScreen = value; - }); - } - @override Widget build(BuildContext context) { - final ds = MediaQuery.of(context).size; - if (_isInit) { - _dwInPortrait = MediaQuery.of(context).size.width; - _scaleInPortrait = _dwInPortrait / 576; - _isInit = false; - } + final d = MediaQuery.of(context); return Consumer( builder: (context, state, child) => StateHandler( @@ -95,23 +56,19 @@ class _StudioDetailsState extends State { builder: (context, state) { return WillPopScope( onWillPop: () async { - if (_isFullScreen) { - await _changeFullSceen(false); - return false; - } if (MediaService.currentPodcast != null) { state.studio = MediaService.currentPodcast!; } return true; }, - child: DidvanScaffold( - key: ValueKey(state.studio.id), - scrollController: _scrollController, - backgroundColor: Theme.of(context).colorScheme.surface, - padding: EdgeInsets.zero, - appBarData: _isFullScreen - ? null - : AppBarData( + child: SafeArea( + child: Scaffold( + key: ValueKey(state.studio.id), + backgroundColor: Theme.of(context).colorScheme.surface, + appBar: PreferredSize( + preferredSize: const Size.fromHeight(56), + child: DidvanAppBar( + appBarData: AppBarData( trailing: BookmarkButton( itemId: state.studio.id, type: 'video', @@ -125,103 +82,41 @@ class _StudioDetailsState extends State { isSmall: true, title: state.studio.title, ), - showSliversFirst: true, - slivers: [ - SliverAppBar( - automaticallyImplyLeading: false, - pinned: true, - backgroundColor: Theme.of(context).colorScheme.surface, - toolbarHeight: - (_isFullScreen ? ds.height : ds.width * 9 / 16) + - 72 - - MediaQuery.of(context).padding.top, - elevation: 0, - flexibleSpace: Column( - children: [ - SizedBox( - width: ds.width, - height: _isFullScreen ? ds.height : ds.width * 9 / 16, - child: Stack( - children: [ - WebView( - zoomEnabled: false, - backgroundColor: Colors.black, - allowsInlineMediaPlayback: true, - initialUrl: Uri.dataFromString( - ''' - - - - - - - ${state.studio.media} - - - ''', - mimeType: 'text/html', - ).toString(), - javascriptMode: JavascriptMode.unrestricted, - ), - Positioned( - right: 42, - bottom: 8, - child: GestureDetector( - onTap: () => _changeFullSceen(!_isFullScreen), - child: Container( - color: Colors.transparent, - width: 24, - height: 30, - ), - ), - ), - ], - ), - ), - DetailsTabBar( - isVideo: true, - onCommentsTabSelected: () => Future.delayed( - const Duration(milliseconds: 100), - () => _scrollController.animateTo( - _scrollController.position.maxScrollExtent, - duration: DesignConfig.lowAnimationDuration, - curve: Curves.easeIn, - ), - ), - ), - ], ), ), - ], - children: [ - StudioDetailsWidget( - scrollController: _scrollController, - onMarkChanged: (id, value) => - widget.pageData['onMarkChanged'](id, value, true), + body: Column( + children: [ + Directionality( + textDirection: TextDirection.ltr, + child: BetterPlayer.network( + 'https://studio-didvan.arvanvod.com/Vz01Bxq2bQ/nylPWJ4B63/h_,144_200,240_400,360_800,480_1215,720_1215,k.mp4.list/master.m3u8', + betterPlayerConfiguration: + const BetterPlayerConfiguration( + aspectRatio: 16 / 9, + controlsConfiguration: + BetterPlayerControlsConfiguration( + enablePlaybackSpeed: false, + enableSubtitles: false, + enableAudioTracks: false, + ), + autoDetectFullscreenAspectRatio: true, + autoDetectFullscreenDeviceOrientation: true, + fullScreenAspectRatio: 16 / 9, + ), + ), + ), + const DetailsTabBar( + isVideo: true, + ), + Expanded( + child: StudioDetailsWidget( + onMarkChanged: (id, value) => + widget.pageData['onMarkChanged'](id, value, true), + ), + ), + ], ), - ], + ), ), ); }, diff --git a/lib/views/home/studio/studio_details/studio_details.web.dart b/lib/views/home/studio/studio_details/studio_details.web.dart index b8d37ca..a1409c2 100644 --- a/lib/views/home/studio/studio_details/studio_details.web.dart +++ b/lib/views/home/studio/studio_details/studio_details.web.dart @@ -24,18 +24,17 @@ class StudioDetails extends StatefulWidget { } class _StudioDetailsState extends State { - final _scrollController = ScrollController(); - bool _isFullScreen = false; @override void initState() { final state = context.read(); + state.args = widget.pageData['args']; Future.delayed( Duration.zero, () => state.getStudioDetails(widget.pageData['id']), ); - state.args = widget.pageData['args']; + super.initState(); } @@ -100,7 +99,6 @@ class _StudioDetailsState extends State { return true; }, child: DidvanScaffold( - scrollController: _scrollController, padding: EdgeInsets.zero, appBarData: _isFullScreen ? null @@ -127,21 +125,13 @@ class _StudioDetailsState extends State { 72 - MediaQuery.of(context).padding.top, flexibleSpace: Column( - children: [ - const AspectRatio( + children: const [ + AspectRatio( aspectRatio: 16 / 9, child: HtmlElementView(viewType: 'video'), ), DetailsTabBar( isVideo: true, - onCommentsTabSelected: () => Future.delayed( - const Duration(milliseconds: 100), - () => _scrollController.animateTo( - _scrollController.position.maxScrollExtent, - duration: DesignConfig.lowAnimationDuration, - curve: Curves.easeIn, - ), - ), ), ], ), @@ -149,7 +139,6 @@ class _StudioDetailsState extends State { ], children: [ StudioDetailsWidget( - scrollController: _scrollController, onMarkChanged: widget.pageData['onMarkChanged'], ), ], diff --git a/lib/views/home/studio/studio_details/widgets/details_tab_bar.dart b/lib/views/home/studio/studio_details/widgets/details_tab_bar.dart index ce2a4a2..f5ef4d3 100644 --- a/lib/views/home/studio/studio_details/widgets/details_tab_bar.dart +++ b/lib/views/home/studio/studio_details/widgets/details_tab_bar.dart @@ -8,12 +8,10 @@ import 'package:provider/provider.dart'; class DetailsTabBar extends StatelessWidget { final bool isVideo; - final VoidCallback onCommentsTabSelected; const DetailsTabBar({ Key? key, required this.isVideo, - required this.onCommentsTabSelected, }) : super(key: key); @override @@ -55,7 +53,6 @@ class DetailsTabBar extends StatelessWidget { title: 'نظرات', onTap: () { state.selectedDetailsIndex = 1; - onCommentsTabSelected(); }, isSelected: state.selectedDetailsIndex == 1, isVideo: isVideo, diff --git a/lib/views/home/studio/studio_details/widgets/studio_details_widget.dart b/lib/views/home/studio/studio_details/widgets/studio_details_widget.dart index 12150b3..bdfc44e 100644 --- a/lib/views/home/studio/studio_details/widgets/studio_details_widget.dart +++ b/lib/views/home/studio/studio_details/widgets/studio_details_widget.dart @@ -19,165 +19,164 @@ import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; class StudioDetailsWidget extends StatelessWidget { - final ScrollController? scrollController; - final VoidCallback? onCommentsTabSelected; final void Function(int id, bool value) onMarkChanged; const StudioDetailsWidget({ Key? key, required this.onMarkChanged, - this.onCommentsTabSelected, - this.scrollController, }) : super(key: key); @override Widget build(BuildContext context) { final ds = MediaQuery.of(context).size; - return Consumer( - builder: (context, state, child) { - bool isVideo = state.studio.media.contains('iframe'); - return Container( - color: Theme.of(context).colorScheme.surface, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (!isVideo) - DetailsTabBar( - isVideo: isVideo, - onCommentsTabSelected: onCommentsTabSelected ?? () {}, - ), - const SizedBox(height: 16), - ConstrainedBox( - constraints: BoxConstraints( - maxHeight: ds.height - - ds.width * 9 / 16 - - 144 - - MediaQuery.of(context).padding.top, - ), - child: StateHandler( - onRetry: () {}, - state: state, - builder: (context, state) { - if (state.selectedDetailsIndex == 0) { - return SingleChildScrollView( - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Html( - key: ValueKey(state.studio.id), - data: state.studio.description, - onAnchorTap: (href, context, map, element) => - launch(href!), - style: { - '*': Style( - direction: TextDirection.rtl, - textAlign: TextAlign.right, - lineHeight: LineHeight.percent(135), - margin: EdgeInsets.zero, - padding: EdgeInsets.zero, - ), - }, - ), - if (state.studio.tags.isNotEmpty) + return SafeArea( + bottom: true, + child: Consumer( + builder: (context, state, child) { + bool isVideo = state.studio.media.contains('iframe'); + return Container( + color: Theme.of(context).colorScheme.surface, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (!isVideo) + DetailsTabBar( + isVideo: isVideo, + ), + const SizedBox(height: 16), + ConstrainedBox( + constraints: BoxConstraints( + maxHeight: isVideo + ? double.infinity + : ds.height - + ds.width * 9 / 16 - + 144 - + MediaQuery.of(context).padding.top, + ), + child: StateHandler( + onRetry: () {}, + state: state, + builder: (context, state) { + if (state.selectedDetailsIndex == 0) { + return SingleChildScrollView( + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Html( + key: ValueKey(state.studio.id), + data: state.studio.description, + onAnchorTap: (href, context, map, element) => + launch(href!), + style: { + '*': Style( + direction: TextDirection.rtl, + textAlign: TextAlign.right, + lineHeight: LineHeight.percent(135), + margin: EdgeInsets.zero, + padding: EdgeInsets.zero, + ), + }, + ), + if (state.studio.tags.isNotEmpty) + const SizedBox(height: 20), + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + for (var i = 0; + i < state.studio.tags.length; + i++) + TagItem( + tag: state.studio.tags[i], + onMarkChanged: (id, value) => + _onMarkChanged(id, value, state), + type: isVideo ? 'video' : 'podcast', + ), + ], + ), const SizedBox(height: 20), - Wrap( - spacing: 8, - runSpacing: 8, - children: [ - for (var i = 0; - i < state.studio.tags.length; - i++) - TagItem( - tag: state.studio.tags[i], - onMarkChanged: (id, value) => - _onMarkChanged(id, value, state), - type: isVideo ? 'video' : 'podcast', + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + const SizedBox(), + if (state.nextStudio != null && + state.alongSideState == AppState.idle) + _StudioPreview( + isNext: true, + studio: state.nextStudio!, + ), + if (state.alongSideState == AppState.busy) + _StudioPreview.placeHolder, + if (state.prevStudio != null && + state.alongSideState == AppState.idle) + _StudioPreview( + isNext: false, + studio: state.prevStudio!, + ), + if (state.alongSideState == AppState.busy) + _StudioPreview.placeHolder, + const SizedBox(), + ], + ), + ], + ), + ); + } + if (state.selectedDetailsIndex == 1) { + return ChangeNotifierProvider( + create: (context) => CommentsState(), + child: Comments( + pageData: { + 'id': state.studio.id, + 'type': 'studio', + 'title': state.studio.title, + 'onCommentsChanged': state.onCommentsChanged, + 'isPage': false, + }, + ), + ); + } + return SingleChildScrollView( + child: Column( + children: [ + if (state.studio.relatedContents.isEmpty) + for (var i = 0; i < 3; i++) + Padding( + padding: const EdgeInsets.only( + bottom: 8, + left: 16, + right: 16, ), - ], - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const SizedBox(), - if (state.nextStudio != null && - state.alongSideState == AppState.idle) - _StudioPreview( - isNext: true, - studio: state.nextStudio!, - scrollController: scrollController, - ), - if (state.alongSideState == AppState.busy) - _StudioPreview.placeHolder, - if (state.prevStudio != null && - state.alongSideState == AppState.idle) - _StudioPreview( - isNext: false, - studio: state.prevStudio!, - scrollController: scrollController, - ), - if (state.alongSideState == AppState.busy) - _StudioPreview.placeHolder, - const SizedBox(), - ], - ), - ], - ), - ); - } - if (state.selectedDetailsIndex == 1) { - return ChangeNotifierProvider( - create: (context) => CommentsState(), - child: Comments( - pageData: { - 'id': state.studio.id, - 'type': 'studio', - 'title': state.studio.title, - 'onCommentsChanged': state.onCommentsChanged, - 'isPage': false, - }, - ), - ); - } - return SingleChildScrollView( - child: Column( - children: [ - if (state.studio.relatedContents.isEmpty) - for (var i = 0; i < 3; i++) + child: MultitypeOverview.placeholder, + ), + for (var i = 0; + i < state.studio.relatedContents.length; + i++) Padding( padding: const EdgeInsets.only( bottom: 8, left: 16, right: 16, ), - child: MultitypeOverview.placeholder, + child: MultitypeOverview( + item: state.studio.relatedContents[i], + onMarkChanged: (id, value) {}, + ), ), - for (var i = 0; - i < state.studio.relatedContents.length; - i++) - Padding( - padding: const EdgeInsets.only( - bottom: 8, - left: 16, - right: 16, - ), - child: MultitypeOverview( - item: state.studio.relatedContents[i], - onMarkChanged: (id, value) {}, - ), - ), - ], - ), - ); - }, + ], + ), + ); + }, + ), ), - ), - ], - ), - ); - }, + ], + ), + ); + }, + ), ); } @@ -196,13 +195,11 @@ class StudioDetailsWidget extends StatelessWidget { class _StudioPreview extends StatelessWidget { final bool isNext; final StudioDetailsData studio; - final ScrollController? scrollController; - const _StudioPreview( - {Key? key, - required this.isNext, - required this.studio, - this.scrollController}) - : super(key: key); + const _StudioPreview({ + Key? key, + required this.isNext, + required this.studio, + }) : super(key: key); String get _previewTitle { if (studio.media.contains('iframe')) { @@ -221,11 +218,6 @@ class _StudioPreview extends StatelessWidget { args: state.args, isForward: isNext, ); - scrollController?.animateTo( - 0, - duration: DesignConfig.lowAnimationDuration, - curve: Curves.easeIn, - ); }, child: Container( width: 88, diff --git a/lib/views/widgets/didvan/bnb.dart b/lib/views/widgets/didvan/bnb.dart index 337c583..28c2d61 100644 --- a/lib/views/widgets/didvan/bnb.dart +++ b/lib/views/widgets/didvan/bnb.dart @@ -339,12 +339,6 @@ class _PlayerNavBar extends StatelessWidget { ), ) : StudioDetailsWidget( - onCommentsTabSelected: () { - Future.delayed( - const Duration(milliseconds: 100), - sheetKey.currentState?.expand, - ); - }, onMarkChanged: (id, value) => context.read().changeMark(id, value, true), ), diff --git a/pubspec.lock b/pubspec.lock index 4182fc8..cbb3c93 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -22,6 +22,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.10.0" + better_player: + dependency: "direct main" + description: + name: better_player + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.81" boolean_selector: dependency: transitive description: @@ -315,6 +322,20 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_widget_from_html_core: + dependency: transitive + description: + name: flutter_widget_from_html_core + url: "https://pub.dartlang.org" + source: hosted + version: "0.8.5+1" + fwfh_text_style: + dependency: transitive + description: + name: fwfh_text_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.7.3+1" graphs: dependency: transitive description: @@ -824,6 +845,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + visibility_detector: + dependency: transitive + description: + name: visibility_detector + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.2" + wakelock: + dependency: transitive + description: + name: wakelock + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.6" + wakelock_macos: + dependency: transitive + description: + name: wakelock_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.0" + wakelock_platform_interface: + dependency: transitive + description: + name: wakelock_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.0" + wakelock_web: + dependency: transitive + description: + name: wakelock_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.0" + wakelock_windows: + dependency: transitive + description: + name: wakelock_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" webview_flutter: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 4f32cce..63202fa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -65,6 +65,7 @@ dependencies: webview_flutter: ^3.0.1 expandable_bottom_sheet: ^1.1.1+1 permission_handler: ^9.2.0 + better_player: ^0.0.81 dev_dependencies: