Merge branch 'main' into feature-updateVideoDetailStructure

This commit is contained in:
guozhigq
2024-06-08 17:59:43 +08:00
65 changed files with 1528 additions and 963 deletions

View File

@ -4,6 +4,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:lottie/lottie.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/pages/video/detail/index.dart';
@ -96,11 +97,14 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
);
}
} else {
return const SliverToBoxAdapter(
return SliverToBoxAdapter(
child: SizedBox(
height: 100,
child: Center(
child: CircularProgressIndicator(),
child: Lottie.asset(
'assets/loading.json',
width: 200,
),
),
),
);
@ -589,8 +593,4 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
);
});
}
// Widget StaffPanel(BuildContext context, videoIntroController) {
// return
// }
}

View File

@ -29,7 +29,7 @@ class _FavPanelState extends State<FavPanel> {
Widget build(BuildContext context) {
return Container(
height: sheetHeight,
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
child: Column(
children: [
AppBar(

View File

@ -57,7 +57,7 @@ class _GroupPanelState extends State<GroupPanel> {
Widget build(BuildContext context) {
return Container(
height: sheetHeight,
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
child: Column(
children: <Widget>[
AppBar(

View File

@ -12,7 +12,7 @@ class MenuRow extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
width: double.infinity,
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
padding: const EdgeInsets.only(top: 9, bottom: 9, left: 12),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
@ -84,7 +84,7 @@ class MenuRow extends StatelessWidget {
style: TextStyle(
fontSize: 13,
color: selectStatus
? Theme.of(context).colorScheme.onBackground
? Theme.of(context).colorScheme.onSurface
: Theme.of(context).colorScheme.outline),
),
),

View File

@ -1,5 +1,4 @@
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/reply.dart';
@ -15,7 +14,6 @@ class VideoReplyController extends GetxController {
this.rpid,
this.replyLevel,
);
final ScrollController scrollController = ScrollController();
// 视频aid 请求时使用的oid
int? aid;
// 层级 2为楼中楼

View File

@ -67,13 +67,12 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
vsync: this, duration: const Duration(milliseconds: 300));
_futureBuilderFuture = _videoReplyController.queryReplyList();
scrollController = ScrollController();
fabAnimationCtr.forward();
scrollListener();
}
void scrollListener() {
scrollController = _videoReplyController.scrollController;
scrollController.addListener(
() {
if (scrollController.position.pixels >=
@ -185,7 +184,8 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
var data = snapshot.data;
if (data['status']) {
if (_videoReplyController.replyList.isNotEmpty ||
(data && data['status'])) {
// 请求成功
return Obx(
() => _videoReplyController.isLoadingMore &&

View File

@ -1,3 +1,4 @@
import 'package:appscheme/appscheme.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -11,6 +12,7 @@ import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/pages/preview/index.dart';
import 'package:pilipala/pages/video/detail/index.dart';
import 'package:pilipala/pages/video/detail/reply_new/index.dart';
import 'package:pilipala/utils/app_scheme.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/id_utils.dart';
import 'package:pilipala/utils/storage.dart';
@ -643,34 +645,17 @@ InlineSpan buildContent(
'',
);
} else {
final String pathSegment = Uri.parse(matchStr).path;
Map matchRes = IdUtils.matchAvorBv(input: pathSegment);
List matchKeys = matchRes.keys.toList();
if (matchKeys.isNotEmpty) {
UrlUtils.matchUrlPush(
matchRes.containsKey('AV')
? matchRes['AV']! as int
: matchRes['BV'],
title,
matchStr,
);
} else {
final String redirectUrl =
await UrlUtils.parseRedirectUrl(matchStr);
// if (redirectUrl == matchStr) {
// Clipboard.setData(ClipboardData(text: matchStr));
// SmartDialog.showToast('地址可能有误');
// return;
// }
Get.toNamed(
'/webview',
parameters: {
'url': redirectUrl,
'type': 'url',
'pageTitle': title
},
);
}
Uri uri = Uri.parse(matchStr);
SchemeEntity scheme = SchemeEntity(
scheme: uri.scheme,
host: uri.host,
port: uri.port,
path: uri.path,
query: uri.queryParameters,
source: '',
dataString: matchStr,
);
PiliSchame.fullPathPush(scheme);
}
} else {
if (appUrlSchema.startsWith('bilibili://search')) {

View File

@ -170,7 +170,7 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
),
child: Column(
mainAxisSize: MainAxisSize.min,

View File

@ -78,7 +78,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
Widget build(BuildContext context) {
return Container(
height: widget.source == 'videoDetail' ? widget.sheetHeight : null,
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
child: Column(
children: [
if (widget.source == 'videoDetail')

View File

@ -99,7 +99,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
fullScreenStatusListener();
if (Platform.isAndroid) {
floating = vdCtr.floating!;
autoEnterPip();
}
WidgetsBinding.instance.addObserver(this);
lifecycleListener();
@ -128,8 +127,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
}
// 播放器状态监听
void playerListener(PlayerStatus? status) async {
playerStatus.value = status!;
void playerListener(PlayerStatus status) async {
playerStatus.value = status;
autoEnterPip(status: status);
if (status == PlayerStatus.completed) {
// 结束播放退出全屏
if (autoExitFullcreen) {
@ -181,6 +181,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
plPlayerController!.addStatusLister(playerListener);
vdCtr.autoPlay.value = true;
vdCtr.isShowCover.value = false;
autoEnterPip(status: PlayerStatus.playing);
}
void fullScreenStatusListener() {
@ -287,10 +288,12 @@ class _VideoDetailPageState extends State<VideoDetailPage>
.subscribe(this, ModalRoute.of(context)! as PageRoute);
}
void autoEnterPip() {
void autoEnterPip({PlayerStatus? status}) {
final String routePath = Get.currentRoute;
if (autoPiP && routePath.startsWith('/video')) {
floating.toggleAutoPip(autoEnter: autoPiP);
floating.toggleAutoPip(
autoEnter: autoPiP && status == PlayerStatus.playing,
);
}
}
@ -314,6 +317,15 @@ class _VideoDetailPageState extends State<VideoDetailPage>
case 'show' || 'restart':
plPlayerController?.danmakuController?.clear();
break;
case 'pause':
vdCtr.hiddenReplyReplyPanel();
if (vdCtr.videoType == SearchType.video) {
videoIntroController.hiddenEpisodeBottomSheet();
}
if (vdCtr.videoType == SearchType.media_bangumi) {
bangumiIntroController.hiddenEpisodeBottomSheet();
}
break;
}
}
@ -525,11 +537,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
Scaffold(
resizeToAvoidBottomInset: false,
key: vdCtr.scaffoldKey,
backgroundColor: Colors.black,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(0),
child: AppBar(
backgroundColor: Colors.transparent,
backgroundColor: Colors.black,
elevation: 0,
),
),
@ -559,8 +570,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
}
return SliverAppBar(
automaticallyImplyLeading: false,
// 假装使用一个非空变量避免Obx检测不到而罢工
pinned: vdCtr.autoPlay.value,
pinned: true,
elevation: 0,
scrolledUnderElevation: 0,
forceElevated: innerBoxIsScrolled,
@ -568,47 +578,42 @@ class _VideoDetailPageState extends State<VideoDetailPage>
backgroundColor: Colors.black,
flexibleSpace: FlexibleSpaceBar(
background: PopScope(
canPop: plPlayerController?.isFullScreen.value !=
true,
onPopInvoked: (bool didPop) {
if (plPlayerController?.isFullScreen.value ==
true) {
plPlayerController!
.triggerFullScreen(status: false);
}
if (MediaQuery.of(context).orientation ==
Orientation.landscape) {
verticalScreen();
}
},
child: LayoutBuilder(
builder: (BuildContext context,
BoxConstraints boxConstraints) {
return Stack(
children: <Widget>[
if (isShowing)
Padding(
padding: EdgeInsets.only(top: 0),
child: videoPlayerPanel,
),
canPop:
plPlayerController?.isFullScreen.value != true,
onPopInvoked: (bool didPop) {
if (plPlayerController?.isFullScreen.value ==
true) {
plPlayerController!
.triggerFullScreen(status: false);
}
if (MediaQuery.of(context).orientation ==
Orientation.landscape) {
verticalScreen();
}
},
child: Hero(
tag: heroTag,
child: Stack(
children: <Widget>[
if (isShowing) videoPlayerPanel,
/// 关闭自动播放时 手动播放
Obx(
() => Visibility(
visible: !vdCtr.autoPlay.value &&
vdCtr.isShowCover.value,
child: Positioned(
top: 0,
left: 0,
right: 0,
child: handlePlayPanel(),
),
),
/// 关闭自动播放时 手动播放
Obx(
() => Visibility(
visible: !vdCtr.autoPlay.value &&
vdCtr.isShowCover.value,
child: Positioned(
top: 0,
left: 0,
right: 0,
child: handlePlayPanel(),
),
],
);
},
)),
),
),
],
),
),
),
),
);
},
@ -627,55 +632,51 @@ class _VideoDetailPageState extends State<VideoDetailPage>
: pinnedHeaderHeight;
},
onlyOneScrollInBody: true,
body: ColoredBox(
key: Key(heroTag),
color: Theme.of(context).colorScheme.background,
child: Column(
children: [
tabbarBuild(),
Expanded(
child: TabBarView(
controller: vdCtr.tabCtr,
children: <Widget>[
Builder(
builder: (BuildContext context) {
return CustomScrollView(
key: const PageStorageKey<String>('简介'),
slivers: <Widget>[
if (vdCtr.videoType == SearchType.video) ...[
VideoIntroPanel(bvid: vdCtr.bvid),
] else if (vdCtr.videoType ==
SearchType.media_bangumi) ...[
Obx(() => BangumiIntroPanel(
cid: vdCtr.cid.value)),
],
SliverToBoxAdapter(
child: Divider(
indent: 12,
endIndent: 12,
color: Theme.of(context)
.dividerColor
.withOpacity(0.06),
),
),
if (vdCtr.videoType == SearchType.video &&
vdCtr.enableRelatedVideo)
const RelatedVideoPanel(),
body: Column(
children: [
tabbarBuild(),
Expanded(
child: TabBarView(
controller: vdCtr.tabCtr,
children: <Widget>[
Builder(
builder: (BuildContext context) {
return CustomScrollView(
key: const PageStorageKey<String>('简介'),
slivers: <Widget>[
if (vdCtr.videoType == SearchType.video) ...[
VideoIntroPanel(bvid: vdCtr.bvid),
] else if (vdCtr.videoType ==
SearchType.media_bangumi) ...[
Obx(() =>
BangumiIntroPanel(cid: vdCtr.cid.value)),
],
);
},
SliverToBoxAdapter(
child: Divider(
indent: 12,
endIndent: 12,
color: Theme.of(context)
.dividerColor
.withOpacity(0.06),
),
),
if (vdCtr.videoType == SearchType.video &&
vdCtr.enableRelatedVideo)
const RelatedVideoPanel(),
],
);
},
),
Obx(
() => VideoReplyPanel(
bvid: vdCtr.bvid,
oid: vdCtr.oid.value,
),
Obx(
() => VideoReplyPanel(
bvid: vdCtr.bvid,
oid: vdCtr.oid.value,
),
)
],
),
)
],
),
],
),
),
],
),
),
),

View File

@ -23,7 +23,7 @@ class AiDetail extends StatelessWidget {
Widget build(BuildContext context) {
sheetHeight = localCache.get('sheetHeight');
return Container(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
padding: const EdgeInsets.only(left: 14, right: 14),
height: sheetHeight,
child: Column(

View File

@ -29,7 +29,7 @@ class ScrollAppBar extends StatelessWidget {
opacity: scrollDistance / (videoHeight - kToolbarHeight),
child: Container(
height: statusBarHeight + kToolbarHeight,
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
padding: EdgeInsets.only(top: statusBarHeight),
child: AppBar(
primary: false,

View File

@ -93,7 +93,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 460,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@ -317,7 +317,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 500,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@ -377,7 +377,7 @@ class _HeaderControlState extends State<HeaderControl> {
inactiveThumbColor:
Theme.of(context).colorScheme.primaryContainer,
inactiveTrackColor:
Theme.of(context).colorScheme.background,
Theme.of(context).colorScheme.surface,
splashRadius: 10.0,
// boolean variable value
value: shutdownTimerService.waitForPlayingCompleted,
@ -570,7 +570,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 310,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@ -660,7 +660,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 250,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@ -734,7 +734,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 250,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@ -828,7 +828,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 580,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@ -1084,7 +1084,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 250,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),