mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt: video page
show tabbar on landscape page prevent showing bottomsheet above fullscreen video
This commit is contained in:
@@ -12,7 +12,6 @@ import 'package:PiliPalaX/common/widgets/stat/danmu.dart';
|
|||||||
import 'package:PiliPalaX/common/widgets/stat/view.dart';
|
import 'package:PiliPalaX/common/widgets/stat/view.dart';
|
||||||
import 'package:PiliPalaX/models/video_detail_res.dart';
|
import 'package:PiliPalaX/models/video_detail_res.dart';
|
||||||
import 'package:PiliPalaX/pages/video/detail/introduction/controller.dart';
|
import 'package:PiliPalaX/pages/video/detail/introduction/controller.dart';
|
||||||
import 'package:PiliPalaX/pages/video/detail/widgets/ai_detail.dart';
|
|
||||||
import 'package:PiliPalaX/utils/feed_back.dart';
|
import 'package:PiliPalaX/utils/feed_back.dart';
|
||||||
import 'package:PiliPalaX/utils/storage.dart';
|
import 'package:PiliPalaX/utils/storage.dart';
|
||||||
import 'package:PiliPalaX/utils/utils.dart';
|
import 'package:PiliPalaX/utils/utils.dart';
|
||||||
@@ -26,8 +25,15 @@ import 'widgets/page.dart';
|
|||||||
import 'widgets/season.dart';
|
import 'widgets/season.dart';
|
||||||
|
|
||||||
class VideoIntroPanel extends StatefulWidget {
|
class VideoIntroPanel extends StatefulWidget {
|
||||||
const VideoIntroPanel({required this.heroTag, super.key});
|
const VideoIntroPanel({
|
||||||
|
super.key,
|
||||||
|
required this.heroTag,
|
||||||
|
required this.showAiBottomSheet,
|
||||||
|
required this.showIntroDetail,
|
||||||
|
});
|
||||||
final String heroTag;
|
final String heroTag;
|
||||||
|
final Function showAiBottomSheet;
|
||||||
|
final Function showIntroDetail;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<VideoIntroPanel> createState() => _VideoIntroPanelState();
|
State<VideoIntroPanel> createState() => _VideoIntroPanelState();
|
||||||
@@ -74,6 +80,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
|||||||
loadingStatus: true,
|
loadingStatus: true,
|
||||||
videoDetail: videoDetail,
|
videoDetail: videoDetail,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
|
showAiBottomSheet: widget.showAiBottomSheet,
|
||||||
|
showIntroDetail: widget.showIntroDetail,
|
||||||
)
|
)
|
||||||
: VideoInfo(
|
: VideoInfo(
|
||||||
//key:herotag
|
//key:herotag
|
||||||
@@ -81,6 +89,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
|||||||
loadingStatus: false,
|
loadingStatus: false,
|
||||||
videoDetail: videoIntroController.videoDetail.value,
|
videoDetail: videoIntroController.videoDetail.value,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
|
showAiBottomSheet: widget.showAiBottomSheet,
|
||||||
|
showIntroDetail: widget.showIntroDetail,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,10 +99,17 @@ class VideoInfo extends StatefulWidget {
|
|||||||
final bool loadingStatus;
|
final bool loadingStatus;
|
||||||
final VideoDetailData? videoDetail;
|
final VideoDetailData? videoDetail;
|
||||||
final String? heroTag;
|
final String? heroTag;
|
||||||
|
final Function showAiBottomSheet;
|
||||||
|
final Function showIntroDetail;
|
||||||
|
|
||||||
const VideoInfo(
|
const VideoInfo({
|
||||||
{Key? key, this.loadingStatus = false, this.videoDetail, this.heroTag})
|
Key? key,
|
||||||
: super(key: key);
|
this.loadingStatus = false,
|
||||||
|
this.videoDetail,
|
||||||
|
this.heroTag,
|
||||||
|
required this.showAiBottomSheet,
|
||||||
|
required this.showIntroDetail,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<VideoInfo> createState() => _VideoInfoState();
|
State<VideoInfo> createState() => _VideoInfoState();
|
||||||
@@ -177,13 +194,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
feedBack();
|
feedBack();
|
||||||
showBottomSheet(
|
widget.showIntroDetail(widget.videoDetail);
|
||||||
context: context,
|
|
||||||
enableDrag: true,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return IntroDetail(videoDetail: widget.videoDetail!);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户主页
|
// 用户主页
|
||||||
@@ -200,17 +211,6 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
arguments: {'face': face, 'heroTag': memberHeroTag});
|
arguments: {'face': face, 'heroTag': memberHeroTag});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ai总结
|
|
||||||
showAiBottomSheet() {
|
|
||||||
showBottomSheet(
|
|
||||||
context: context,
|
|
||||||
enableDrag: true,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AiDetail(modelResult: videoIntroController.modelResult);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ThemeData t = Theme.of(context);
|
final ThemeData t = Theme.of(context);
|
||||||
@@ -384,7 +384,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
final res =
|
final res =
|
||||||
await videoIntroController.aiConclusion();
|
await videoIntroController.aiConclusion();
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
showAiBottomSheet();
|
widget.showAiBottomSheet();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child:
|
child:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:PiliPalaX/common/widgets/http_error.dart';
|
import 'package:PiliPalaX/common/widgets/http_error.dart';
|
||||||
import 'package:PiliPalaX/http/loading_state.dart';
|
import 'package:PiliPalaX/http/loading_state.dart';
|
||||||
import 'package:PiliPalaX/pages/video/detail/reply_reply/view.dart';
|
|
||||||
import 'package:easy_debounce/easy_throttle.dart';
|
import 'package:easy_debounce/easy_throttle.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
@@ -18,6 +17,7 @@ class VideoReplyPanel extends StatefulWidget {
|
|||||||
final int rpid;
|
final int rpid;
|
||||||
final String? replyLevel;
|
final String? replyLevel;
|
||||||
final String heroTag;
|
final String heroTag;
|
||||||
|
final Function replyReply;
|
||||||
|
|
||||||
const VideoReplyPanel({
|
const VideoReplyPanel({
|
||||||
this.bvid,
|
this.bvid,
|
||||||
@@ -25,6 +25,7 @@ class VideoReplyPanel extends StatefulWidget {
|
|||||||
this.rpid = 0,
|
this.rpid = 0,
|
||||||
this.replyLevel,
|
this.replyLevel,
|
||||||
required this.heroTag,
|
required this.heroTag,
|
||||||
|
required this.replyReply,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -115,21 +116,6 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 展示二级回复
|
|
||||||
void replyReply(replyItem) {
|
|
||||||
showBottomSheet(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => VideoReplyReplyPanel(
|
|
||||||
rcount: replyItem.rcount,
|
|
||||||
oid: replyItem.oid,
|
|
||||||
rpid: replyItem.rpid,
|
|
||||||
firstFloor: replyItem,
|
|
||||||
replyType: ReplyType.video,
|
|
||||||
source: 'videoDetail',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
@@ -239,7 +225,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
|||||||
replyItem: loadingState.response[index],
|
replyItem: loadingState.response[index],
|
||||||
showReplyRow: true,
|
showReplyRow: true,
|
||||||
replyLevel: replyLevel,
|
replyLevel: replyLevel,
|
||||||
replyReply: replyReply,
|
replyReply: widget.replyReply,
|
||||||
replyType: ReplyType.video,
|
replyType: ReplyType.video,
|
||||||
onReply: () {
|
onReply: () {
|
||||||
_videoReplyController.onReply(
|
_videoReplyController.onReply(
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import 'dart:math';
|
|||||||
|
|
||||||
import 'package:PiliPalaX/common/constants.dart';
|
import 'package:PiliPalaX/common/constants.dart';
|
||||||
import 'package:PiliPalaX/http/loading_state.dart';
|
import 'package:PiliPalaX/http/loading_state.dart';
|
||||||
|
import 'package:PiliPalaX/models/common/reply_type.dart';
|
||||||
|
import 'package:PiliPalaX/pages/video/detail/introduction/widgets/intro_detail.dart';
|
||||||
|
import 'package:PiliPalaX/pages/video/detail/reply_reply/view.dart';
|
||||||
|
import 'package:PiliPalaX/pages/video/detail/widgets/ai_detail.dart';
|
||||||
import 'package:PiliPalaX/utils/extension.dart';
|
import 'package:PiliPalaX/utils/extension.dart';
|
||||||
import 'package:PiliPalaX/utils/id_utils.dart';
|
import 'package:PiliPalaX/utils/id_utils.dart';
|
||||||
import 'package:auto_orientation/auto_orientation.dart';
|
import 'package:auto_orientation/auto_orientation.dart';
|
||||||
@@ -76,6 +80,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
late final MethodChannel onUserLeaveHintListener;
|
late final MethodChannel onUserLeaveHintListener;
|
||||||
// StreamSubscription<Duration>? _bufferedListener;
|
// StreamSubscription<Duration>? _bufferedListener;
|
||||||
|
|
||||||
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -411,102 +417,60 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
/// tabbar
|
/// tabbar
|
||||||
Widget tabbarBuild = Container(
|
Widget tabbarBuild([
|
||||||
width: double.infinity,
|
bool needIndicator = true,
|
||||||
height: 45,
|
String introText = '简介',
|
||||||
decoration: BoxDecoration(
|
]) {
|
||||||
border: Border(
|
return Container(
|
||||||
bottom: BorderSide(
|
width: double.infinity,
|
||||||
width: 1,
|
height: 45,
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
width: 1,
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
child: Material(
|
||||||
child: Material(
|
child: Row(
|
||||||
child: Row(
|
children: [
|
||||||
children: [
|
Flexible(
|
||||||
Flexible(
|
|
||||||
flex: 1,
|
|
||||||
child: Obx(
|
|
||||||
() => TabBar(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
controller: videoDetailController.tabCtr,
|
|
||||||
labelStyle: const TextStyle(fontSize: 13),
|
|
||||||
labelPadding:
|
|
||||||
const EdgeInsets.symmetric(horizontal: 10.0), // 设置每个标签的宽度
|
|
||||||
dividerColor: Colors.transparent,
|
|
||||||
onTap: (value) {
|
|
||||||
if (!videoDetailController.tabCtr.indexIsChanging) {
|
|
||||||
if (value == 0) {
|
|
||||||
_introController.animToTop();
|
|
||||||
} else {
|
|
||||||
_videoReplyController.animateToTop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tabs: [
|
|
||||||
const Tab(text: '简介'),
|
|
||||||
Tab(
|
|
||||||
text:
|
|
||||||
'评论${_videoReplyController.count.value == -1 ? '' : ' ${_videoReplyController.count.value}'}',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Flexible(
|
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: Center(
|
child: Obx(
|
||||||
child: Row(
|
() => TabBar(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
indicatorColor: needIndicator ? null : Colors.transparent,
|
||||||
children: [
|
padding: EdgeInsets.zero,
|
||||||
SizedBox(
|
controller: videoDetailController.tabCtr,
|
||||||
height: 32,
|
labelStyle: const TextStyle(fontSize: 13),
|
||||||
child: TextButton(
|
labelPadding: const EdgeInsets.symmetric(
|
||||||
style: ButtonStyle(
|
horizontal: 10.0), // 设置每个标签的宽度
|
||||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
dividerColor: Colors.transparent,
|
||||||
),
|
onTap: (value) {
|
||||||
onPressed: null,
|
if (!needIndicator ||
|
||||||
// onPressed: () => videoDetailController.showShootDanmakuSheet(),
|
!videoDetailController.tabCtr.indexIsChanging) {
|
||||||
child:
|
if (value == 0) {
|
||||||
const Text('发弹幕', style: TextStyle(fontSize: 12)),
|
_introController.animToTop();
|
||||||
),
|
} else {
|
||||||
|
_videoReplyController.animateToTop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tabs: [
|
||||||
|
Tab(text: introText),
|
||||||
|
Tab(
|
||||||
|
text:
|
||||||
|
'评论${_videoReplyController.count.value == -1 ? '' : ' ${_videoReplyController.count.value}'}',
|
||||||
),
|
),
|
||||||
// SizedBox(
|
|
||||||
// width: 38,
|
|
||||||
// height: 38,
|
|
||||||
// child: Obx(
|
|
||||||
// () => IconButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// plPlayerController?.isOpenDanmu.value =
|
|
||||||
// !(plPlayerController?.isOpenDanmu.value ??
|
|
||||||
// false);
|
|
||||||
// },
|
|
||||||
// icon: !(plPlayerController?.isOpenDanmu.value ??
|
|
||||||
// false)
|
|
||||||
// ? SvgPicture.asset(
|
|
||||||
// 'assets/images/video/danmu_close.svg',
|
|
||||||
// // ignore: deprecated_member_use
|
|
||||||
// color:
|
|
||||||
// Theme.of(context).colorScheme.outline,
|
|
||||||
// )
|
|
||||||
// : SvgPicture.asset(
|
|
||||||
// 'assets/images/video/danmu_open.svg',
|
|
||||||
// // ignore: deprecated_member_use
|
|
||||||
// color:
|
|
||||||
// Theme.of(context).colorScheme.primary,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
const SizedBox(width: 14),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)),
|
),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
|
|
||||||
Widget plPlayer = FutureBuilder(
|
Widget plPlayer = FutureBuilder(
|
||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
@@ -619,125 +583,126 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Scaffold(
|
Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
key: videoDetailController.scaffoldKey,
|
key: videoDetailController.scaffoldKey,
|
||||||
// backgroundColor: Colors.black,
|
// backgroundColor: Colors.black,
|
||||||
appBar: removeSafeArea
|
appBar: removeSafeArea
|
||||||
? null
|
? null
|
||||||
: AppBar(
|
: AppBar(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
showStatusBarBackgroundColor ? null : Colors.black,
|
showStatusBarBackgroundColor ? null : Colors.black,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
toolbarHeight: 0,
|
toolbarHeight: 0,
|
||||||
systemOverlayStyle: SystemUiOverlayStyle(
|
systemOverlayStyle: SystemUiOverlayStyle(
|
||||||
statusBarIconBrightness:
|
statusBarIconBrightness:
|
||||||
Theme.of(context).brightness == Brightness.dark ||
|
Theme.of(context).brightness == Brightness.dark ||
|
||||||
!showStatusBarBackgroundColor
|
!showStatusBarBackgroundColor
|
||||||
? Brightness.light
|
? Brightness.light
|
||||||
: Brightness.dark,
|
: Brightness.dark,
|
||||||
systemNavigationBarColor: Colors.transparent),
|
systemNavigationBarColor: Colors.transparent),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
Obx(
|
Obx(
|
||||||
() {
|
() {
|
||||||
double videoHeight = context.width * 9 / 16;
|
double videoHeight = context.width * 9 / 16;
|
||||||
final double videoWidth = context.width;
|
final double videoWidth = context.width;
|
||||||
// print(videoDetailController.tabCtr.index);
|
// print(videoDetailController.tabCtr.index);
|
||||||
if (enableVerticalExpand &&
|
if (enableVerticalExpand &&
|
||||||
plPlayerController?.direction.value == 'vertical') {
|
plPlayerController?.direction.value == 'vertical') {
|
||||||
videoHeight = context.width;
|
videoHeight = context.width;
|
||||||
}
|
}
|
||||||
if (MediaQuery.of(context).orientation ==
|
if (MediaQuery.of(context).orientation ==
|
||||||
Orientation.landscape &&
|
Orientation.landscape &&
|
||||||
!horizontalScreen &&
|
!horizontalScreen &&
|
||||||
!isFullScreen.value &&
|
!isFullScreen.value &&
|
||||||
isShowing &&
|
isShowing &&
|
||||||
mounted) {
|
mounted) {
|
||||||
hideStatusBar();
|
hideStatusBar();
|
||||||
}
|
}
|
||||||
if (MediaQuery.of(context).orientation ==
|
if (MediaQuery.of(context).orientation ==
|
||||||
Orientation.portrait &&
|
Orientation.portrait &&
|
||||||
!isFullScreen.value &&
|
!isFullScreen.value &&
|
||||||
isShowing &&
|
isShowing &&
|
||||||
mounted) {
|
mounted) {
|
||||||
if (!removeSafeArea) showStatusBar();
|
if (!removeSafeArea) showStatusBar();
|
||||||
}
|
}
|
||||||
return Container(
|
return Container(
|
||||||
color:
|
color: showStatusBarBackgroundColor ? null : Colors.black,
|
||||||
showStatusBarBackgroundColor ? null : Colors.black,
|
height: MediaQuery.of(context).orientation ==
|
||||||
height: MediaQuery.of(context).orientation ==
|
Orientation.landscape ||
|
||||||
Orientation.landscape ||
|
isFullScreen.value == true
|
||||||
isFullScreen.value == true
|
? MediaQuery.sizeOf(context).height -
|
||||||
? MediaQuery.sizeOf(context).height -
|
(MediaQuery.of(context).orientation ==
|
||||||
(MediaQuery.of(context).orientation ==
|
Orientation.landscape ||
|
||||||
Orientation.landscape ||
|
removeSafeArea
|
||||||
removeSafeArea
|
? 0
|
||||||
? 0
|
: MediaQuery.of(context).padding.top)
|
||||||
: MediaQuery.of(context).padding.top)
|
: videoHeight,
|
||||||
: videoHeight,
|
width: context.width,
|
||||||
width: context.width,
|
child: PopScope(
|
||||||
child: PopScope(
|
canPop: isFullScreen.value != true &&
|
||||||
canPop: isFullScreen.value != true &&
|
(horizontalScreen ||
|
||||||
(horizontalScreen ||
|
MediaQuery.of(context).orientation ==
|
||||||
MediaQuery.of(context).orientation ==
|
Orientation.portrait),
|
||||||
Orientation.portrait),
|
onPopInvokedWithResult: (bool didPop, Object? result) {
|
||||||
onPopInvokedWithResult:
|
if (isFullScreen.value == true) {
|
||||||
(bool didPop, Object? result) {
|
plPlayerController!
|
||||||
if (isFullScreen.value == true) {
|
.triggerFullScreen(status: false);
|
||||||
plPlayerController!
|
}
|
||||||
.triggerFullScreen(status: false);
|
if (MediaQuery.of(context).orientation ==
|
||||||
}
|
Orientation.landscape &&
|
||||||
if (MediaQuery.of(context).orientation ==
|
!horizontalScreen) {
|
||||||
Orientation.landscape &&
|
verticalScreenForTwoSeconds();
|
||||||
!horizontalScreen) {
|
}
|
||||||
verticalScreenForTwoSeconds();
|
},
|
||||||
}
|
child: Stack(
|
||||||
},
|
children: <Widget>[
|
||||||
child: Stack(
|
if (isShowing) plPlayer,
|
||||||
children: <Widget>[
|
|
||||||
if (isShowing) plPlayer,
|
|
||||||
|
|
||||||
/// 关闭自动播放时 手动播放
|
/// 关闭自动播放时 手动播放
|
||||||
if (!videoDetailController
|
if (!videoDetailController
|
||||||
.autoPlay.value) ...<Widget>[
|
.autoPlay.value) ...<Widget>[
|
||||||
Obx(
|
Obx(
|
||||||
() => Visibility(
|
() => Visibility(
|
||||||
visible: videoDetailController
|
visible:
|
||||||
.isShowCover.value,
|
videoDetailController.isShowCover.value,
|
||||||
child: Positioned(
|
child: Positioned(
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: handlePlay,
|
onTap: handlePlay,
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => NetworkImgLayer(
|
() => NetworkImgLayer(
|
||||||
type: 'emote',
|
type: 'emote',
|
||||||
src: videoDetailController
|
src: videoDetailController
|
||||||
.videoItem['pic'],
|
.videoItem['pic'],
|
||||||
width: videoWidth,
|
width: videoWidth,
|
||||||
height: videoHeight,
|
height: videoHeight,
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
manualPlayerWidget,
|
),
|
||||||
]
|
),
|
||||||
],
|
manualPlayerWidget,
|
||||||
)),
|
]
|
||||||
);
|
],
|
||||||
},
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
);
|
||||||
child: ColoredBox(
|
},
|
||||||
key: Key(heroTag),
|
),
|
||||||
color: Theme.of(context).colorScheme.surface,
|
Expanded(
|
||||||
child: Column(
|
child: ColoredBox(
|
||||||
|
key: Key(heroTag),
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
child: Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
tabbarBuild,
|
tabbarBuild(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TabBarView(
|
child: TabBarView(
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
@@ -749,7 +714,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
slivers: <Widget>[
|
slivers: <Widget>[
|
||||||
if (videoDetailController.videoType ==
|
if (videoDetailController.videoType ==
|
||||||
SearchType.video) ...[
|
SearchType.video) ...[
|
||||||
VideoIntroPanel(heroTag: heroTag),
|
VideoIntroPanel(
|
||||||
|
heroTag: heroTag,
|
||||||
|
showAiBottomSheet: showAiBottomSheet,
|
||||||
|
showIntroDetail: showIntroDetail,
|
||||||
|
),
|
||||||
] else if (videoDetailController
|
] else if (videoDetailController
|
||||||
.videoType ==
|
.videoType ==
|
||||||
SearchType.media_bangumi) ...[
|
SearchType.media_bangumi) ...[
|
||||||
@@ -776,13 +745,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
RelatedVideoPanel(heroTag: heroTag),
|
RelatedVideoPanel(heroTag: heroTag),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Obx(
|
videoReplyPanel,
|
||||||
() => VideoReplyPanel(
|
|
||||||
bvid: videoDetailController.bvid,
|
|
||||||
oid: videoDetailController.oid.value,
|
|
||||||
heroTag: heroTag,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -790,8 +753,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
)),
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -852,46 +817,56 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TabBarView(
|
child: Scaffold(
|
||||||
physics: const BouncingScrollPhysics(),
|
key: scaffoldKey,
|
||||||
controller: videoDetailController.tabCtr,
|
body: Column(
|
||||||
children: <Widget>[
|
children: [
|
||||||
CustomScrollView(
|
tabbarBuild(),
|
||||||
key: const PageStorageKey<String>('简介'),
|
Expanded(
|
||||||
slivers: <Widget>[
|
child: TabBarView(
|
||||||
if (videoDetailController.videoType ==
|
physics: const BouncingScrollPhysics(),
|
||||||
SearchType.video) ...[
|
controller: videoDetailController.tabCtr,
|
||||||
VideoIntroPanel(heroTag: heroTag),
|
children: <Widget>[
|
||||||
] else if (videoDetailController.videoType ==
|
CustomScrollView(
|
||||||
SearchType.media_bangumi) ...[
|
controller: _introController,
|
||||||
Obx(() => BangumiIntroPanel(
|
key: const PageStorageKey<String>('简介'),
|
||||||
heroTag: heroTag,
|
slivers: <Widget>[
|
||||||
cid: videoDetailController.cid.value)),
|
if (videoDetailController.videoType ==
|
||||||
],
|
SearchType.video) ...[
|
||||||
SliverToBoxAdapter(
|
VideoIntroPanel(
|
||||||
child: Padding(
|
heroTag: heroTag,
|
||||||
padding:
|
showAiBottomSheet: showAiBottomSheet,
|
||||||
const EdgeInsets.only(top: StyleString.safeSpace),
|
showIntroDetail: showIntroDetail,
|
||||||
child: Divider(
|
),
|
||||||
height: 1,
|
] else if (videoDetailController.videoType ==
|
||||||
indent: 12,
|
SearchType.media_bangumi) ...[
|
||||||
endIndent: 12,
|
Obx(() => BangumiIntroPanel(
|
||||||
color:
|
heroTag: heroTag,
|
||||||
Theme.of(context).dividerColor.withOpacity(0.06),
|
cid: videoDetailController.cid.value)),
|
||||||
|
],
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: StyleString.safeSpace),
|
||||||
|
child: Divider(
|
||||||
|
height: 1,
|
||||||
|
indent: 12,
|
||||||
|
endIndent: 12,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.dividerColor
|
||||||
|
.withOpacity(0.06),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RelatedVideoPanel(heroTag: heroTag),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
videoReplyPanel,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
RelatedVideoPanel(heroTag: heroTag),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Obx(
|
|
||||||
() => VideoReplyPanel(
|
|
||||||
bvid: videoDetailController.bvid,
|
|
||||||
oid: videoDetailController.oid.value,
|
|
||||||
heroTag: heroTag,
|
|
||||||
),
|
),
|
||||||
)
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
@@ -953,31 +928,46 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Row(children: [
|
child: Scaffold(
|
||||||
Expanded(
|
key: scaffoldKey,
|
||||||
child: CustomScrollView(
|
body: Column(
|
||||||
key: PageStorageKey<String>('简介${videoDetailController.bvid}'),
|
children: [
|
||||||
slivers: <Widget>[
|
tabbarBuild(false),
|
||||||
if (videoDetailController.videoType == SearchType.video) ...[
|
Expanded(
|
||||||
VideoIntroPanel(heroTag: heroTag),
|
child: Row(
|
||||||
RelatedVideoPanel(heroTag: heroTag),
|
children: [
|
||||||
] else if (videoDetailController.videoType ==
|
Expanded(
|
||||||
SearchType.media_bangumi) ...[
|
child: CustomScrollView(
|
||||||
Obx(() => BangumiIntroPanel(
|
controller: _introController,
|
||||||
heroTag: heroTag, cid: videoDetailController.cid.value)),
|
key: PageStorageKey<String>(
|
||||||
]
|
'简介${videoDetailController.bvid}'),
|
||||||
],
|
slivers: <Widget>[
|
||||||
)),
|
if (videoDetailController.videoType ==
|
||||||
Expanded(
|
SearchType.video) ...[
|
||||||
child: Obx(
|
VideoIntroPanel(
|
||||||
() => VideoReplyPanel(
|
heroTag: heroTag,
|
||||||
bvid: videoDetailController.bvid,
|
showAiBottomSheet: showAiBottomSheet,
|
||||||
oid: videoDetailController.oid.value,
|
showIntroDetail: showIntroDetail,
|
||||||
heroTag: heroTag,
|
),
|
||||||
),
|
RelatedVideoPanel(heroTag: heroTag),
|
||||||
|
] else if (videoDetailController.videoType ==
|
||||||
|
SearchType.media_bangumi) ...[
|
||||||
|
Obx(() => BangumiIntroPanel(
|
||||||
|
heroTag: heroTag,
|
||||||
|
cid: videoDetailController.cid.value)),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
Expanded(
|
||||||
|
child: videoReplyPanel,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
]))
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -994,7 +984,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
key: PageStorageKey<String>('简介${videoDetailController.bvid}'),
|
key: PageStorageKey<String>('简介${videoDetailController.bvid}'),
|
||||||
slivers: <Widget>[
|
slivers: <Widget>[
|
||||||
if (videoDetailController.videoType == SearchType.video) ...[
|
if (videoDetailController.videoType == SearchType.video) ...[
|
||||||
VideoIntroPanel(heroTag: heroTag),
|
VideoIntroPanel(
|
||||||
|
heroTag: heroTag,
|
||||||
|
showAiBottomSheet: showAiBottomSheet,
|
||||||
|
showIntroDetail: showIntroDetail,
|
||||||
|
),
|
||||||
RelatedVideoPanel(heroTag: heroTag),
|
RelatedVideoPanel(heroTag: heroTag),
|
||||||
] else if (videoDetailController.videoType ==
|
] else if (videoDetailController.videoType ==
|
||||||
SearchType.media_bangumi) ...[
|
SearchType.media_bangumi) ...[
|
||||||
@@ -1052,12 +1046,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Obx(
|
child: Scaffold(
|
||||||
() => VideoReplyPanel(
|
key: scaffoldKey,
|
||||||
bvid: videoDetailController.bvid,
|
body: videoReplyPanel,
|
||||||
oid: videoDetailController.oid.value,
|
|
||||||
heroTag: heroTag,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Expanded(
|
// Expanded(
|
||||||
@@ -1169,7 +1160,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
slivers: <Widget>[
|
slivers: <Widget>[
|
||||||
if (videoDetailController.videoType ==
|
if (videoDetailController.videoType ==
|
||||||
SearchType.video) ...[
|
SearchType.video) ...[
|
||||||
VideoIntroPanel(heroTag: heroTag),
|
VideoIntroPanel(
|
||||||
|
heroTag: heroTag,
|
||||||
|
showAiBottomSheet: showAiBottomSheet,
|
||||||
|
showIntroDetail: showIntroDetail,
|
||||||
|
),
|
||||||
// RelatedVideoPanel(heroTag: heroTag),
|
// RelatedVideoPanel(heroTag: heroTag),
|
||||||
] else if (videoDetailController.videoType ==
|
] else if (videoDetailController.videoType ==
|
||||||
SearchType.media_bangumi) ...[
|
SearchType.media_bangumi) ...[
|
||||||
@@ -1194,24 +1189,30 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
MediaQuery.of(context).padding.right))),
|
MediaQuery.of(context).padding.right))),
|
||||||
height: context.height -
|
height: context.height -
|
||||||
(removeSafeArea ? 0 : MediaQuery.of(context).padding.top),
|
(removeSafeArea ? 0 : MediaQuery.of(context).padding.top),
|
||||||
child: TabBarView(
|
child: Scaffold(
|
||||||
physics: const BouncingScrollPhysics(),
|
key: scaffoldKey,
|
||||||
controller: videoDetailController.tabCtr,
|
body: Column(
|
||||||
children: <Widget>[
|
children: [
|
||||||
if (videoDetailController.videoType == SearchType.video)
|
tabbarBuild(true, '相关视频'),
|
||||||
CustomScrollView(
|
Expanded(
|
||||||
slivers: [
|
child: TabBarView(
|
||||||
RelatedVideoPanel(heroTag: heroTag),
|
physics: const BouncingScrollPhysics(),
|
||||||
],
|
controller: videoDetailController.tabCtr,
|
||||||
),
|
children: <Widget>[
|
||||||
Obx(
|
if (videoDetailController.videoType ==
|
||||||
() => VideoReplyPanel(
|
SearchType.video)
|
||||||
bvid: videoDetailController.bvid,
|
CustomScrollView(
|
||||||
oid: videoDetailController.oid.value,
|
controller: _introController,
|
||||||
heroTag: heroTag,
|
slivers: [
|
||||||
),
|
RelatedVideoPanel(heroTag: heroTag),
|
||||||
)
|
],
|
||||||
],
|
),
|
||||||
|
videoReplyPanel,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -1239,7 +1240,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
systemNavigationBarColor: Colors.transparent),
|
systemNavigationBarColor: Colors.transparent),
|
||||||
),
|
),
|
||||||
body: Container(
|
body: Container(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
left: !removeSafeArea && isFullScreen.value != true,
|
left: !removeSafeArea && isFullScreen.value != true,
|
||||||
right: !removeSafeArea && isFullScreen.value != true,
|
right: !removeSafeArea && isFullScreen.value != true,
|
||||||
@@ -1268,7 +1269,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
systemNavigationBarColor: Colors.transparent),
|
systemNavigationBarColor: Colors.transparent),
|
||||||
),
|
),
|
||||||
body: Container(
|
body: Container(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
left: !removeSafeArea && isFullScreen.value != true,
|
left: !removeSafeArea && isFullScreen.value != true,
|
||||||
right: !removeSafeArea && isFullScreen.value != true,
|
right: !removeSafeArea && isFullScreen.value != true,
|
||||||
@@ -1324,7 +1325,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
if (!isShowing) {
|
if (!isShowing) {
|
||||||
return ColoredBox(color: Theme.of(context).colorScheme.background);
|
return ColoredBox(color: Theme.of(context).colorScheme.surface);
|
||||||
}
|
}
|
||||||
if (constraints.maxWidth > constraints.maxHeight * 1.25) {
|
if (constraints.maxWidth > constraints.maxHeight * 1.25) {
|
||||||
// hideStatusBar();
|
// hideStatusBar();
|
||||||
@@ -1372,4 +1373,39 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
// : childWhenDisabledLandscape;
|
// : childWhenDisabledLandscape;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget get videoReplyPanel => Obx(
|
||||||
|
() => VideoReplyPanel(
|
||||||
|
bvid: videoDetailController.bvid,
|
||||||
|
oid: videoDetailController.oid.value,
|
||||||
|
heroTag: heroTag,
|
||||||
|
replyReply: replyReply,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 展示二级回复
|
||||||
|
void replyReply(replyItem) {
|
||||||
|
scaffoldKey.currentState?.showBottomSheet(
|
||||||
|
(context) => VideoReplyReplyPanel(
|
||||||
|
rcount: replyItem.rcount,
|
||||||
|
oid: replyItem.oid,
|
||||||
|
rpid: replyItem.rpid,
|
||||||
|
firstFloor: replyItem,
|
||||||
|
replyType: ReplyType.video,
|
||||||
|
source: 'videoDetail',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ai总结
|
||||||
|
showAiBottomSheet() {
|
||||||
|
scaffoldKey.currentState?.showBottomSheet(
|
||||||
|
enableDrag: true,
|
||||||
|
(context) => AiDetail(modelResult: videoIntroController.modelResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
showIntroDetail(videoDetail) {
|
||||||
|
scaffoldKey.currentState?.showBottomSheet(
|
||||||
|
enableDrag: true, (context) => IntroDetail(videoDetail: videoDetail));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user