new video player basic version

This commit is contained in:
MohammadTaha Basiri 2022-04-04 14:16:21 +04:30
parent 48387b0b79
commit 00f108710a
9 changed files with 331 additions and 353 deletions

View File

@ -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'

View File

@ -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

View File

@ -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<StudioDetails> {
final _scrollController = ScrollController();
bool _isFullScreen = false;
bool _isInit = true;
double _dwInPortrait = 0;
double _scaleInPortrait = 1;
@override
void initState() {
final state = context.read<StudioDetailsState>();
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<void> _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<StudioDetailsState>(
builder: (context, state, child) => StateHandler<StudioDetailsState>(
@ -95,23 +56,19 @@ class _StudioDetailsState extends State<StudioDetails> {
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<StudioDetails> {
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(
'''
<html>
<head>
<meta
name="viewport"
content="width=device-width, initial-scale=$_scaleInPortrait"
/>
<style>
* {
padding: 0;
margin: 0;
overflow: hidden;
}
iframe {
max-height: 100vh;
}
.r1_iframe_embed {
height: ${MediaQuery.of(context).size.width / _scaleInPortrait}px !important;
padding-top: 0 !important;
}
@media(max-width:580px){
.r1_iframe_embed {
height: ${_dwInPortrait * 9 / 16 / _scaleInPortrait}px !important;
padding-top: 0 !important;
}
}
</style>
</head>
<body>
${state.studio.media}
</body>
</html>
''',
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),
),
),
],
),
],
),
),
);
},

View File

@ -24,18 +24,17 @@ class StudioDetails extends StatefulWidget {
}
class _StudioDetailsState extends State<StudioDetails> {
final _scrollController = ScrollController();
bool _isFullScreen = false;
@override
void initState() {
final state = context.read<StudioDetailsState>();
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<StudioDetails> {
return true;
},
child: DidvanScaffold(
scrollController: _scrollController,
padding: EdgeInsets.zero,
appBarData: _isFullScreen
? null
@ -127,21 +125,13 @@ class _StudioDetailsState extends State<StudioDetails> {
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<StudioDetails> {
],
children: [
StudioDetailsWidget(
scrollController: _scrollController,
onMarkChanged: widget.pageData['onMarkChanged'],
),
],

View File

@ -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,

View File

@ -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<StudioDetailsState>(
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<StudioDetailsState>(
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<StudioDetailsState>(
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<StudioDetailsState>(
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<CommentsState>(
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<CommentsState>(
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,

View File

@ -339,12 +339,6 @@ class _PlayerNavBar extends StatelessWidget {
),
)
: StudioDetailsWidget(
onCommentsTabSelected: () {
Future.delayed(
const Duration(milliseconds: 100),
sheetKey.currentState?.expand,
);
},
onMarkChanged: (id, value) =>
context.read<StudioState>().changeMark(id, value, true),
),

View File

@ -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:

View File

@ -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: