refa: list sheet

Closes #369

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-01 23:21:07 +08:00
parent f9f30a5f13
commit f99740ef2d
12 changed files with 841 additions and 2599 deletions

View File

@@ -1,4 +1,4 @@
library video_detail;
export './controller.dart';
export './view.dart';
export './view_v.dart';

View File

@@ -778,7 +778,11 @@ class VideoIntroController extends GetxController
final int currentIndex = episodes.indexWhere((e) =>
e.cid ==
(skipPages ? videoDetail.value.pages!.first.cid : lastPlayCid.value));
(skipPages
? videoDetail.value.isPageReversed == true
? videoDetail.value.pages!.last.cid
: videoDetail.value.pages!.first.cid
: lastPlayCid.value));
int prevIndex = currentIndex - 1;
final PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat;
@@ -838,8 +842,11 @@ class VideoIntroController extends GetxController
final int currentIndex = episodes.indexWhere((e) =>
e.cid ==
(skipPages
? videoDetail.value.pages!.first.cid
? videoDetail.value.isPageReversed == true
? videoDetail.value.pages!.last.cid
: videoDetail.value.pages!.first.cid
: videoDetailCtr.cid.value));
int nextIndex = currentIndex + 1;
if (isPages.not &&

View File

@@ -627,7 +627,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
context: context,
theme: 'gray',
value: Utils.numFormat(!widget.loadingStatus
? videoDetail.stat?.danmu ?? '-'
? videoDetail.stat?.danmaku ?? '-'
: videoItem['stat']?.danmu ?? '-'),
size: 'medium',
textColor: t.colorScheme.outline,
@@ -858,7 +858,6 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
heroTag: widget.heroTag,
videoIntroController: videoIntroController,
bvid: videoIntroController.bvid,
changeFuc: videoIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes,
),
),

View File

@@ -12,16 +12,20 @@ import '../../../../../utils/id_utils.dart';
class PagesPanel extends StatefulWidget {
const PagesPanel({
super.key,
this.list,
this.cover,
required this.bvid,
required this.changeFuc,
required this.heroTag,
required this.showEpisodes,
this.showEpisodes,
required this.videoIntroController,
});
final List<Part>? list;
final String? cover;
final String bvid;
final Function changeFuc;
final String heroTag;
final Function showEpisodes;
final Function? showEpisodes;
final VideoIntroController videoIntroController;
@override
@@ -30,36 +34,46 @@ class PagesPanel extends StatefulWidget {
class _PagesPanelState extends State<PagesPanel> {
late int cid;
late int pageIndex;
int pageIndex = -1;
late VideoDetailController _videoDetailController;
final ScrollController _scrollController = ScrollController();
StreamSubscription? _listener;
List<Part> get pages => widget.videoIntroController.videoDetail.value.pages!;
List<Part> get pages =>
widget.list ?? widget.videoIntroController.videoDetail.value.pages!;
@override
void initState() {
super.initState();
cid = widget.videoIntroController.lastPlayCid.value;
_videoDetailController =
Get.find<VideoDetailController>(tag: widget.heroTag);
pageIndex = pages.indexWhere((Part e) => e.cid == cid);
_listener = _videoDetailController.cid.listen((int cid) {
this.cid = cid;
pageIndex = max(0, pages.indexWhere((Part e) => e.cid == cid));
if (!mounted) return;
setState(() {});
const double itemWidth = 150; // 每个列表项的宽度
final double targetOffset = (pageIndex * itemWidth - itemWidth / 2).clamp(
_scrollController.position.minScrollExtent,
_scrollController.position.maxScrollExtent);
// 滑动至目标位置
_scrollController.animateTo(
targetOffset,
duration: const Duration(milliseconds: 300), // 滑动动画持续时间
curve: Curves.easeInOut, // 滑动动画曲线
);
});
if (widget.list == null) {
cid = widget.videoIntroController.lastPlayCid.value;
_videoDetailController =
Get.find<VideoDetailController>(tag: widget.heroTag);
pageIndex = pages.indexWhere((Part e) => e.cid == cid);
_listener = _videoDetailController.cid.listen((int cid) {
this.cid = cid;
pageIndex = max(0, pages.indexWhere((Part e) => e.cid == cid));
if (!mounted) return;
setState(() {});
jumpToCurr();
});
WidgetsBinding.instance.addPostFrameCallback((_) {
jumpToCurr();
});
}
}
void jumpToCurr() {
const double itemWidth = 150; // 每个列表项的宽度
final double targetOffset = (pageIndex * itemWidth - itemWidth / 2).clamp(
_scrollController.position.minScrollExtent,
_scrollController.position.maxScrollExtent);
// 滑动至目标位置
_scrollController.animateTo(
targetOffset,
duration: const Duration(milliseconds: 300), // 滑动动画持续时间
curve: Curves.easeInOut, // 滑动动画曲线
);
}
@override
@@ -73,46 +87,47 @@ class _PagesPanelState extends State<PagesPanel> {
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8, bottom: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('视频选集 '),
Expanded(
child: Text(
' 正在播放:${pages[pageIndex].pagePart}',
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.outline,
),
),
),
const SizedBox(width: 10),
SizedBox(
height: 34,
child: TextButton(
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () => widget.showEpisodes(
null,
null,
pages,
widget.bvid,
IdUtils.bv2av(widget.bvid),
cid,
),
if (widget.showEpisodes != null)
Padding(
padding: const EdgeInsets.only(top: 8, bottom: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('视频选集 '),
Expanded(
child: Text(
'${pages.length}',
style: const TextStyle(fontSize: 13),
' 正在播放:${pages[pageIndex].pagePart}',
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.outline,
),
),
),
),
],
const SizedBox(width: 10),
SizedBox(
height: 34,
child: TextButton(
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () => widget.showEpisodes!(
null,
null,
pages,
widget.bvid,
IdUtils.bv2av(widget.bvid),
cid,
),
child: Text(
'${pages.length}',
style: const TextStyle(fontSize: 13),
),
),
),
],
),
),
),
SizedBox(
height: 35,
child: ListView.builder(
@@ -132,14 +147,17 @@ class _PagesPanelState extends State<PagesPanel> {
borderRadius: BorderRadius.circular(6),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: () => {
widget.changeFuc(
onTap: () {
if (widget.showEpisodes == null) {
Get.back();
}
widget.videoIntroController.changeSeasonOrbangu(
null,
widget.bvid,
pages[i].cid,
IdUtils.bv2av(widget.bvid),
null,
)
widget.cover,
);
},
child: Padding(
padding: const EdgeInsets.symmetric(
@@ -160,10 +178,11 @@ class _PagesPanelState extends State<PagesPanel> {
pages[i].pagePart!,
maxLines: 1,
style: TextStyle(
fontSize: 13,
color: isCurrentIndex
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface),
fontSize: 13,
color: isCurrentIndex
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurface,
),
overflow: TextOverflow.ellipsis,
))
],

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ import 'dart:math';
import 'dart:ui';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/list_sheet.dart';
import 'package:PiliPlus/common/widgets/episode_panel.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/main.dart';
import 'package:PiliPlus/models/common/reply_type.dart';
@@ -2075,18 +2075,23 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
heroTag: heroTag,
videoIntroController: videoIntroController,
bvid: videoIntroController.bvid,
changeFuc: videoIntroController.changeSeasonOrbangu,
showEpisodes: showEpisodes,
),
)
else
Expanded(
child: Obx(
() => ListSheetContent(
episodes: videoIntroController.videoDetail.value.pages,
() => EpisodePanel(
heroTag: heroTag,
videoIntroController: videoIntroController,
type: EpisodeType.part,
list: [videoIntroController.videoDetail.value.pages!],
cover: videoDetailController.videoItem['pic'],
bvid: videoDetailController.bvid,
aid: IdUtils.bv2av(videoDetailController.bvid),
currentCid: videoDetailController.cid.value,
cid: videoDetailController.cid.value,
// count: videoIntroController.videoDetail.value.pages!.length,
// name: videoIntroController.videoDetail.value.pages!,
isReversed:
videoIntroController.videoDetail.value.isPageReversed,
changeFucCall: videoDetailController.videoType ==
@@ -2127,12 +2132,23 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
),
Expanded(
child: Obx(
() => ListSheetContent(
index: videoDetailController.seasonIndex.value,
season: videoIntroController.videoDetail.value.ugcSeason,
() => EpisodePanel(
heroTag: heroTag,
videoIntroController: videoIntroController,
type: EpisodeType.season,
initialTabIndex: videoDetailController.seasonIndex.value,
cover: videoDetailController.videoItem['pic'],
seasonId:
videoIntroController.videoDetail.value.ugcSeason!.id,
list: videoIntroController
.videoDetail.value.ugcSeason!.sections!,
// count: videoIntroController
// .videoDetail.value.ugcSeason!.epCount!,
// name:
// videoIntroController.videoDetail.value.ugcSeason!.title!,
bvid: videoDetailController.bvid,
aid: IdUtils.bv2av(videoDetailController.bvid),
currentCid: videoDetailController.seasonCid ?? 0,
cid: videoDetailController.seasonCid ?? 0,
isReversed:
videoIntroController.videoDetail.value.isSeasonReversed,
changeFucCall: videoDetailController.videoType ==
@@ -2243,14 +2259,22 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
videoDetailController.showMediaListPanel(context);
return;
}
Widget listSheetContent([bool? enableSlide]) => ListSheetContent(
Widget listSheetContent([bool? enableSlide]) => EpisodePanel(
heroTag: heroTag,
videoIntroController: videoIntroController,
type: season != null
? EpisodeType.season
: episodes is List<video.Part>
? EpisodeType.part
: EpisodeType.bangumi,
cover: videoDetailController.videoItem['pic'],
enableSlide: enableSlide,
index: index,
season: season,
initialTabIndex: index ?? 0,
bvid: bvid,
aid: aid,
currentCid: cid,
episodes: episodes,
cid: cid,
seasonId: season?.id,
list: season != null ? season.sections : [episodes],
isReversed:
videoDetailController.videoType == SearchType.media_bangumi
? null