opt: video page v

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-02-27 10:56:26 +08:00
parent 72e7f0aa9f
commit 6a9795f561
3 changed files with 266 additions and 269 deletions

View File

@@ -2088,7 +2088,7 @@ class VideoDetailController extends GetxController
@override @override
void onClose() { void onClose() {
tabCtr.dispose(); tabCtr.dispose();
if (Get.currentRoute.startsWith('/videoV')) { if (GStorage.collapsibleVideoPage) {
scrollCtr.removeListener(scrollListener); scrollCtr.removeListener(scrollListener);
scrollCtr.dispose; scrollCtr.dispose;
animationController.dispose(); animationController.dispose();
@@ -2101,7 +2101,7 @@ class VideoDetailController extends GetxController
videoUrl = null; videoUrl = null;
audioUrl = null; audioUrl = null;
if (Get.currentRoute.startsWith('/videoV') && scrollRatio.value != 0) { if (GStorage.collapsibleVideoPage && scrollRatio.value != 0) {
scrollRatio.refresh(); scrollRatio.refresh();
} }

View File

@@ -111,7 +111,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
parent: ClampingScrollPhysics(), parent: ClampingScrollPhysics(),
) )
: const AlwaysScrollableScrollPhysics(), : const AlwaysScrollableScrollPhysics(),
// key: const PageStorageKey<String>('评论'), key: const PageStorageKey<String>('评论'),
slivers: <Widget>[ slivers: <Widget>[
SliverPersistentHeader( SliverPersistentHeader(
pinned: false, pinned: false,

View File

@@ -254,10 +254,14 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
videoDetailController.scrollCtr.offset / videoDetailController.scrollCtr.offset /
videoDetailController.videoHeight); videoDetailController.videoHeight);
} else { } else {
videoDetailController.scrollKey.currentState?.setState(() {}); if (videoDetailController.scrollKey.currentState?.mounted == true) {
videoDetailController.scrollKey.currentState?.setState(() {});
}
} }
} else { } else {
videoDetailController.scrollKey.currentState?.setState(() {}); if (videoDetailController.scrollKey.currentState?.mounted == true) {
videoDetailController.scrollKey.currentState?.setState(() {});
}
} }
} catch (e) { } catch (e) {
debugPrint('handle playe status: $e'); debugPrint('handle playe status: $e');
@@ -644,283 +648,276 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
), ),
), ),
), ),
body: Builder( body: ExtendedNestedScrollView(
builder: (context) { key: videoDetailController.scrollKey,
return ExtendedNestedScrollView( physics: const NeverScrollableScrollPhysics(
key: videoDetailController.scrollKey, parent: ClampingScrollPhysics(),
physics: const NeverScrollableScrollPhysics( ),
parent: ClampingScrollPhysics(), controller: videoDetailController.scrollCtr,
), onlyOneScrollInBody: true,
controller: videoDetailController.scrollCtr, pinnedHeaderSliverHeightBuilder: () {
onlyOneScrollInBody: true, double height = isFullScreen
pinnedHeaderSliverHeightBuilder: () { ? MediaQuery.sizeOf(context).height
double height = isFullScreen : videoDetailController.isExpanding ||
videoDetailController.isCollapsing
? animHeight
: videoDetailController.isCollapsing ||
plPlayerController?.playerStatus.status.value ==
PlayerStatus.playing
? videoDetailController.minVideoHeight
: kToolbarHeight;
if (videoDetailController.isExpanding &&
videoDetailController.animationController.value == 1) {
videoDetailController.isExpanding = false;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (videoDetailController.scrollKey.currentState?.mounted ==
true) {
videoDetailController.scrollRatio.value = 0;
videoDetailController.scrollKey.currentState
?.setState(() {});
}
});
} else if (videoDetailController.isCollapsing &&
videoDetailController.animationController.value == 1) {
videoDetailController.isCollapsing = false;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (videoDetailController.scrollKey.currentState?.mounted ==
true) {
videoDetailController.scrollKey.currentState
?.setState(() {});
}
});
}
return height;
},
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
automaticallyImplyLeading: false,
pinned: true,
expandedHeight: isFullScreen
? MediaQuery.sizeOf(context).height ? MediaQuery.sizeOf(context).height
: videoDetailController.isExpanding || : videoDetailController.isExpanding ||
videoDetailController.isCollapsing videoDetailController.isCollapsing
? animHeight ? animHeight
: videoDetailController.isCollapsing || : videoDetailController.videoHeight,
plPlayerController flexibleSpace: Stack(
?.playerStatus.status.value == children: [
PlayerStatus.playing Obx(
? videoDetailController.minVideoHeight () {
: kToolbarHeight; final double videoWidth = context.width;
if (videoDetailController.isExpanding && if (MediaQuery.of(context).orientation ==
videoDetailController.animationController.value == 1) { Orientation.landscape &&
videoDetailController.isExpanding = false; !horizontalScreen &&
WidgetsBinding.instance.addPostFrameCallback((_) { !isFullScreen &&
videoDetailController.scrollKey.currentState isShowing &&
?.setState(() {}); mounted) {
}); hideStatusBar();
} else if (videoDetailController.isCollapsing && }
videoDetailController.animationController.value == 1) { if (MediaQuery.of(context).orientation ==
videoDetailController.isCollapsing = false; Orientation.portrait &&
WidgetsBinding.instance.addPostFrameCallback((_) { !isFullScreen &&
videoDetailController.scrollKey.currentState isShowing &&
?.setState(() {}); mounted) {
}); if (videoDetailController.imageStatus.not &&
} removeSafeArea.not) {
return height; showStatusBar();
}, }
headerSliverBuilder: }
(BuildContext context, bool innerBoxIsScrolled) { return Container(
return [ color: Colors.black,
SliverAppBar( // showStatusBarBackgroundColor ? null : Colors.black,
automaticallyImplyLeading: false, height: MediaQuery.of(context).orientation ==
pinned: true, Orientation.landscape ||
expandedHeight: isFullScreen isFullScreen
? MediaQuery.sizeOf(context).height ? MediaQuery.sizeOf(context).height -
: videoDetailController.isExpanding || (MediaQuery.of(context).orientation ==
videoDetailController.isCollapsing Orientation.landscape ||
? animHeight removeSafeArea
: videoDetailController.videoHeight, ? 0
flexibleSpace: Stack( : MediaQuery.of(context).padding.top)
children: [ : videoDetailController.isExpanding ||
Obx( videoDetailController.isCollapsing
() { ? animHeight
final double videoWidth = context.width; : videoDetailController.videoHeight,
if (MediaQuery.of(context).orientation == width: context.width,
Orientation.landscape && child: PopScope(
!horizontalScreen && canPop: !isFullScreen &&
!isFullScreen && (horizontalScreen ||
isShowing && MediaQuery.of(context).orientation ==
mounted) { Orientation.portrait),
hideStatusBar(); onPopInvokedWithResult: _onPopInvokedWithResult,
} child: videoPlayer(
if (MediaQuery.of(context).orientation == videoWidth,
Orientation.portrait && videoDetailController.isExpanding ||
!isFullScreen && videoDetailController.isCollapsing
isShowing && ? animHeight
mounted) { : videoDetailController.videoHeight,
if (videoDetailController.imageStatus.not && ),
removeSafeArea.not) { ),
showStatusBar(); );
} },
} ),
return Container( Obx(
color: Colors.black, () {
// showStatusBarBackgroundColor ? null : Colors.black, Widget toolbar() => Opacity(
height: MediaQuery.of(context).orientation == opacity:
Orientation.landscape || videoDetailController.scrollRatio.value,
isFullScreen child: Container(
? MediaQuery.sizeOf(context).height - color: Theme.of(context).colorScheme.surface,
(MediaQuery.of(context).orientation == alignment: Alignment.topCenter,
Orientation.landscape || child: SizedBox(
removeSafeArea height: kToolbarHeight,
? 0 child: Stack(
: MediaQuery.of(context) children: [
.padding Align(
.top) alignment: Alignment.centerLeft,
: videoDetailController.isExpanding || child: Row(
videoDetailController.isCollapsing mainAxisSize: MainAxisSize.min,
? animHeight children: [
: videoDetailController.videoHeight, SizedBox(
width: context.width, width: 42,
child: PopScope( height: 34,
canPop: !isFullScreen && child: IconButton(
(horizontalScreen || tooltip: '返回',
MediaQuery.of(context).orientation == icon: Icon(
Orientation.portrait), FontAwesomeIcons.arrowLeft,
onPopInvokedWithResult: size: 15,
_onPopInvokedWithResult, color: Theme.of(context)
child: videoPlayer( .colorScheme
videoWidth, .onSurface,
videoDetailController.isExpanding || ),
videoDetailController.isCollapsing onPressed: Get.back,
? animHeight ),
: videoDetailController.videoHeight, ),
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '返回主页',
icon: Icon(
FontAwesomeIcons.house,
size: 15,
color: Theme.of(context)
.colorScheme
.onSurface,
),
onPressed: () {
Get.until((route) =>
route.isFirst);
},
),
),
],
),
),
Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.play_arrow_rounded,
color: Theme.of(context)
.colorScheme
.primary,
),
Text(
'${videoDetailController.playedTime == null ? '立即' : plPlayerController!.playerStatus.status.value == PlayerStatus.completed ? '重新' : '继续'}播放',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
),
),
],
),
),
],
),
), ),
), ),
); );
}, return videoDetailController.scrollRatio.value == 0 ||
), videoDetailController.scrollCtr.offset == 0
Obx( ? const SizedBox.shrink()
() { : Positioned.fill(
Widget toolbar() => Opacity( bottom: -2,
opacity: child: GestureDetector(
videoDetailController.scrollRatio.value, onTap: () async {
child: Container( if (videoDetailController.isQuerying) {
color: debugPrint('handlePlay: querying');
Theme.of(context).colorScheme.surface, return;
alignment: Alignment.topCenter, }
child: SizedBox( if (videoDetailController.videoUrl ==
height: kToolbarHeight, null ||
child: Stack( videoDetailController.audioUrl ==
children: [ null) {
Align( debugPrint(
alignment: Alignment.centerLeft, 'handlePlay: videoUrl/audioUrl not initialized');
child: Row( videoDetailController.queryVideoUrl();
mainAxisSize: MainAxisSize.min, return;
children: [ }
SizedBox( videoDetailController.scrollRatio.value =
width: 42, 0;
height: 34, if (plPlayerController == null) {
child: IconButton( handlePlay();
tooltip: '返回', } else {
icon: Icon( if (plPlayerController!
FontAwesomeIcons .videoPlayerController!
.arrowLeft, .state
size: 15, .completed) {
color: Theme.of(context) await plPlayerController!
.colorScheme .videoPlayerController!
.onSurface, .seek(Duration.zero);
), plPlayerController!
onPressed: Get.back, .videoPlayerController!
), .play();
), } else {
SizedBox( plPlayerController!
width: 42, .videoPlayerController!
height: 34, .playOrPause();
child: IconButton( }
tooltip: '返回主页', }
icon: Icon( },
FontAwesomeIcons.house, behavior: HitTestBehavior.opaque,
size: 15, child: toolbar(),
color: Theme.of(context) ),
.colorScheme );
.onSurface,
),
onPressed: () {
Get.until((route) =>
route.isFirst);
},
),
),
],
),
),
Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.play_arrow_rounded,
color: Theme.of(context)
.colorScheme
.primary,
),
Text(
'${videoDetailController.playedTime == null ? '立即' : plPlayerController!.playerStatus.status.value == PlayerStatus.completed ? '重新' : '继续'}播放',
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary,
),
),
],
),
),
],
),
),
),
);
return videoDetailController.scrollRatio.value ==
0 ||
videoDetailController.scrollCtr.offset ==
0
? const SizedBox.shrink()
: Positioned.fill(
bottom: -2,
child: GestureDetector(
onTap: () async {
if (videoDetailController
.isQuerying) {
debugPrint('handlePlay: querying');
return;
}
if (videoDetailController.videoUrl ==
null ||
videoDetailController.audioUrl ==
null) {
debugPrint(
'handlePlay: videoUrl/audioUrl not initialized');
videoDetailController
.queryVideoUrl();
return;
}
videoDetailController
.scrollRatio.value = 0;
if (plPlayerController == null) {
handlePlay();
} else {
if (plPlayerController!
.videoPlayerController!
.state
.completed) {
await plPlayerController!
.videoPlayerController!
.seek(Duration.zero);
plPlayerController!
.videoPlayerController!
.play();
} else {
plPlayerController!
.videoPlayerController!
.playOrPause();
}
}
},
behavior: HitTestBehavior.opaque,
child: toolbar(),
),
);
},
),
],
),
),
];
},
body: Scaffold(
key: videoDetailController.childKey,
resizeToAvoidBottomInset: false,
body: Column(
children: [
buildTabbar(
showReply: videoDetailController.showReply,
onTap: () {
videoDetailController
.scrollKey.currentState?.outerController
.animToTop();
}, },
), ),
Expanded(
child: videoTabBarView(
controller: videoDetailController.tabCtr,
children: [
videoIntro(true, false),
if (videoDetailController.showReply)
videoReplyPanel(false),
if (_shouldShowSeasonPanel) seasonPanel,
],
),
),
], ],
), ),
), ),
); ];
}, },
body: Scaffold(
key: videoDetailController.childKey,
resizeToAvoidBottomInset: false,
body: Column(
children: [
buildTabbar(
showReply: videoDetailController.showReply,
onTap: () {
videoDetailController
.scrollKey.currentState?.outerController
.animToTop();
},
),
Expanded(
child: videoTabBarView(
controller: videoDetailController.tabCtr,
children: [
videoIntro(true, false),
if (videoDetailController.showReply)
videoReplyPanel(false),
if (_shouldShowSeasonPanel) seasonPanel,
],
),
),
],
),
),
), ),
), ),
); );