opt: video page v

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-02-27 09:28:08 +08:00
parent 0a6950e34a
commit c2d27ddd04
3 changed files with 160 additions and 77 deletions

View File

@@ -63,8 +63,8 @@ class SubDetailController extends GetxController {
if (subList.length >= mediaCount) {
loadingText.value = '没有更多了';
}
currentPage += 1;
}
currentPage += 1;
isLoadingMore = false;
return res;
}

View File

@@ -1,6 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:ui';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/icon_button.dart';
import 'package:PiliPlus/common/widgets/loading_widget.dart';
@@ -50,7 +51,7 @@ import '../../../utils/id_utils.dart';
import 'widgets/header_control.dart';
class VideoDetailController extends GetxController
with GetSingleTickerProviderStateMixin {
with GetTickerProviderStateMixin {
/// 路由传参
String bvid = Get.parameters['bvid']!;
RxInt cid = int.parse(Get.parameters['cid']!).obs;
@@ -128,8 +129,87 @@ class VideoDetailController extends GetxController
StreamSubscription<Duration>? positionSubscription;
late final scrollKey = GlobalKey<ExtendedNestedScrollViewState>();
late final RxString direction = 'horizontal'.obs;
late String _direction = 'horizontal';
late final RxDouble scrollRatio = 0.0.obs;
late final ScrollController scrollCtr = ScrollController()
..addListener(scrollListener);
late bool isExpanding = false;
late bool isCollapsing = false;
late final AnimationController animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
);
late final double minVideoHeight = Get.width * 9 / 16;
late final double maxVideoHeight = max(Get.height * 0.65, Get.width);
late double videoHeight = minVideoHeight;
void setVideoHeight() {
String direction = firstVideo.width != null && firstVideo.height != null
? firstVideo.width! > firstVideo.height!
? 'horizontal'
: 'vertical'
: 'horizontal';
if (_direction != direction) {
_direction = direction;
double videoHeight =
direction == 'vertical' ? maxVideoHeight : minVideoHeight;
if (this.videoHeight != videoHeight) {
if (videoHeight > this.videoHeight) {
// current minVideoHeight
isExpanding = true;
animationController.forward(
from: (minVideoHeight - scrollCtr.offset) / maxVideoHeight);
this.videoHeight = maxVideoHeight;
} else {
// current maxVideoHeight
final currentHeight =
(maxVideoHeight - scrollCtr.offset).toPrecision(2);
double minVideoHeightPrecise = minVideoHeight.toPrecision(2);
if (currentHeight == minVideoHeightPrecise) {
isExpanding = true;
this.videoHeight = minVideoHeight;
animationController.forward(from: 1);
} else if (currentHeight < minVideoHeightPrecise) {
// expande
isExpanding = true;
animationController.forward(from: currentHeight / minVideoHeight);
this.videoHeight = minVideoHeight;
} else {
// collapse
isCollapsing = true;
animationController.forward(
from: scrollCtr.offset / (maxVideoHeight - minVideoHeight));
this.videoHeight = minVideoHeight;
}
}
}
} else {
if (scrollCtr.offset != 0) {
isExpanding = true;
animationController.forward(from: 1 - scrollCtr.offset / videoHeight);
}
}
}
void scrollListener() {
if (scrollCtr.hasClients) {
if (scrollCtr.offset == 0) {
scrollRatio.value = 0;
} else {
double offset = scrollCtr.offset - (videoHeight - minVideoHeight);
if (offset > 0) {
scrollRatio.value = clampDouble(
offset.toPrecision(2) /
(minVideoHeight - kToolbarHeight).toPrecision(2),
0.0,
1.0,
);
} else {
scrollRatio.value = 0;
}
}
}
}
bool imageStatus = false;
@@ -993,11 +1073,7 @@ class VideoDetailController extends GetxController
? null
: Duration(milliseconds: data.timeLength!),
// 宽>高 水平 否则 垂直
direction: firstVideo.width != null && firstVideo.height != null
? ((firstVideo.width! - firstVideo.height!) > 0
? 'horizontal'
: 'vertical')
: null,
direction: _direction,
bvid: bvid,
cid: cid.value,
enableHeart: enableHeart,
@@ -1087,11 +1163,7 @@ class VideoDetailController extends GetxController
baseUrl: videoUrl,
codecs: 'avc1',
quality: VideoQualityCode.fromCode(data.quality!)!);
direction.value = firstVideo.width != null && firstVideo.height != null
? firstVideo.width! > firstVideo.height!
? 'horizontal'
: 'vertical'
: 'horizontal';
setVideoHeight();
currentDecodeFormats = VideoDecodeFormatsCode.fromString('avc1')!;
currentVideoQa = VideoQualityCode.fromCode(data.quality!)!;
if (autoPlay.value) {
@@ -1162,11 +1234,7 @@ class VideoDetailController extends GetxController
firstVideo = videosList.firstWhere(
(e) => e.codecs!.startsWith(currentDecodeFormats.code),
orElse: () => videosList.first);
direction.value = firstVideo.width != null && firstVideo.height != null
? firstVideo.width! > firstVideo.height!
? 'horizontal'
: 'vertical'
: 'horizontal';
setVideoHeight();
// videoUrl = enableCDN
// ? VideoUtils.getCdnUrl(firstVideo)
@@ -2020,6 +2088,11 @@ class VideoDetailController extends GetxController
@override
void onClose() {
tabCtr.dispose();
if (Get.currentRoute.startsWith('/videoV')) {
scrollCtr.removeListener(scrollListener);
scrollCtr.dispose;
animationController.dispose();
}
super.onClose();
}

View File

@@ -197,6 +197,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
});
}
videoDetailController.animationController.addListener(animListener);
WidgetsBinding.instance.addObserver(this);
}
@@ -243,10 +245,14 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
try {
bool isPlaying = status == PlayerStatus.playing;
if (isPlaying) {
if (scrollController.offset != 0) {
isExpanding = true;
animationController.value = 0;
animationController.forward();
if (videoDetailController.isExpanding.not &&
videoDetailController.scrollCtr.offset != 0 &&
videoDetailController.animationController.isAnimating.not) {
videoDetailController.isExpanding = true;
videoDetailController.animationController.forward(
from: 1 -
videoDetailController.scrollCtr.offset /
videoDetailController.videoHeight);
} else {
videoDetailController.scrollKey.currentState?.setState(() {});
}
@@ -371,14 +377,11 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
videoDetailController.skipTimer = null;
try {
animationController.removeListener(animListener);
animationController.dispose();
videoDetailController.animationController.removeListener(animListener);
if (videoDetailController.showReply) {
videoDetailController.scrollKey.currentState?.innerController
.removeListener(innerScrollListener);
}
scrollController.removeListener(scrollListener);
scrollController.dispose();
} catch (_) {}
WidgetsBinding.instance.removeObserver(this);
@@ -557,40 +560,30 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
}
}
late final AnimationController animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
)..addListener(animListener);
late final ScrollController scrollController = ScrollController()
..addListener(scrollListener);
late final double defVideoHeight = MediaQuery.sizeOf(context).width * 9 / 16;
late double videoHeight = MediaQuery.sizeOf(context).width * 9 / 16;
late bool isExpanding = false;
void animListener() {
if (animationController.isForwardOrCompleted) {
if (videoDetailController.animationController.isForwardOrCompleted &&
videoDetailController.scrollKey.currentState?.mounted == true) {
cal();
videoDetailController.scrollKey.currentState?.setState(() {});
}
}
void scrollListener() {
if (scrollController.hasClients) {
if (scrollController.offset == 0) {
videoDetailController.scrollRatio.value = 0;
} else {
double offset =
scrollController.offset - (videoHeight - defVideoHeight);
if (offset > 0) {
videoDetailController.scrollRatio.value = clampDouble(
offset.toPrecision(2) /
(defVideoHeight - kToolbarHeight).toPrecision(2),
0.0,
1.0,
);
} else {
videoDetailController.scrollRatio.value = 0;
}
}
late double animHeight;
void cal() {
if (videoDetailController.isExpanding) {
animHeight = clampDouble(
videoDetailController.videoHeight *
videoDetailController.animationController.value,
kToolbarHeight,
videoDetailController.videoHeight);
} else if (videoDetailController.isCollapsing) {
animHeight = clampDouble(
videoDetailController.maxVideoHeight -
(videoDetailController.maxVideoHeight -
videoDetailController.minVideoHeight) *
videoDetailController.animationController.value,
videoDetailController.minVideoHeight,
videoDetailController.maxVideoHeight);
}
}
@@ -638,7 +631,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
toolbarHeight: 0,
),
if (videoDetailController.scrollRatio.value != 0 &&
scrollController.offset != 0)
videoDetailController.scrollCtr.offset != 0)
AppBar(
backgroundColor: Theme.of(context)
.colorScheme
@@ -651,33 +644,37 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
),
),
),
body: Obx(
() {
if (videoDetailController.direction.value == 'vertical') {
videoHeight = max(context.height * 0.7, context.width);
} else {
videoHeight = context.width * 9 / 16;
}
body: Builder(
builder: (context) {
return ExtendedNestedScrollView(
key: videoDetailController.scrollKey,
physics: const NeverScrollableScrollPhysics(
parent: ClampingScrollPhysics(),
),
controller: scrollController,
controller: videoDetailController.scrollCtr,
onlyOneScrollInBody: true,
pinnedHeaderSliverHeightBuilder: () {
double height = isFullScreen
? MediaQuery.sizeOf(context).height
: isExpanding
? clampDouble(videoHeight * animationController.value,
kToolbarHeight, videoHeight) +
45
: plPlayerController?.playerStatus.status.value ==
PlayerStatus.playing
? defVideoHeight + 45
: videoDetailController.isExpanding ||
videoDetailController.isCollapsing
? animHeight
: videoDetailController.isCollapsing ||
plPlayerController
?.playerStatus.status.value ==
PlayerStatus.playing
? videoDetailController.minVideoHeight
: kToolbarHeight;
if (isExpanding && animationController.value == 1) {
isExpanding = false;
if (videoDetailController.isExpanding &&
videoDetailController.animationController.value == 1) {
videoDetailController.isExpanding = false;
WidgetsBinding.instance.addPostFrameCallback((_) {
videoDetailController.scrollKey.currentState
?.setState(() {});
});
} else if (videoDetailController.isCollapsing &&
videoDetailController.animationController.value == 1) {
videoDetailController.isCollapsing = false;
WidgetsBinding.instance.addPostFrameCallback((_) {
videoDetailController.scrollKey.currentState
?.setState(() {});
@@ -693,7 +690,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
pinned: true,
expandedHeight: isFullScreen
? MediaQuery.sizeOf(context).height
: videoHeight,
: videoDetailController.isExpanding ||
videoDetailController.isCollapsing
? animHeight
: videoDetailController.videoHeight,
flexibleSpace: Stack(
children: [
Obx(
@@ -731,7 +731,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
: MediaQuery.of(context)
.padding
.top)
: videoHeight,
: videoDetailController.isExpanding ||
videoDetailController.isCollapsing
? animHeight
: videoDetailController.videoHeight,
width: context.width,
child: PopScope(
canPop: !isFullScreen &&
@@ -740,7 +743,13 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
Orientation.portrait),
onPopInvokedWithResult:
_onPopInvokedWithResult,
child: videoPlayer(videoWidth, videoHeight),
child: videoPlayer(
videoWidth,
videoDetailController.isExpanding ||
videoDetailController.isCollapsing
? animHeight
: videoDetailController.videoHeight,
),
),
);
},
@@ -828,7 +837,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
);
return videoDetailController.scrollRatio.value ==
0 ||
scrollController.offset == 0
videoDetailController.scrollCtr.offset ==
0
? const SizedBox.shrink()
: Positioned.fill(
bottom: -2,