diff --git a/lib/main.dart b/lib/main.dart index 63ad3432f..58ea22a2c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -59,7 +59,7 @@ void main() async { SmartDialog.config.loading = SmartConfigLoading(backType: SmartBackType.normal); // 异常捕获 logo记录 - final String buildConfig = ''' + final String buildConfig = '''\n Build Time: ${BuildConfig.buildTime} Commit Hash: ${BuildConfig.commitHash}'''; final Catcher2Options debugConfig = Catcher2Options( diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index b4edc1bb2..20dc87048 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -401,10 +401,17 @@ class _ExtraSettingState extends State { setKey: SettingBoxKey.showArgueMsg, defaultVal: true, ), + SetSwitchItem( + title: '倒序播放从首集开始播放', + subTitle: '开启则自动切换为倒序首集,否则保持当前集', + leading: const Icon(Icons.u_turn_right), + setKey: SettingBoxKey.reverseFromFirst, + defaultVal: true, + ), Obx( () => ListTile( enableFeedback: true, - onTap: () => settingController.onOpenFeedBack(), + onTap: settingController.onOpenFeedBack, leading: const Icon(Icons.vibration_outlined), title: Text('震动反馈', style: titleStyle), subtitle: Text('请确定手机设置中已开启震动反馈', style: subTitleStyle), diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index e5fd98cbb..fc0b08d7c 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -112,8 +112,8 @@ class _SubDetailPageState extends State { top: kTextTabBarHeight + MediaQuery.of(context).padding.top + 15, - left: 20, - right: 20, + left: 12, + right: 12, ), child: SizedBox( height: 200, diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index f12d5f550..675b4c31e 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -224,6 +224,7 @@ class VideoDetailController extends GetxController late final horizontalSeasonPanel = GStorage.horizontalSeasonPanel; late int seasonCid = 0; late RxInt seasonIndex = 0.obs; + late final reverseFromFirst = GStorage.reverseFromFirst; late final bool enableSponsorBlock; PlayerStatus? playerStatus; diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 05d79660e..35462fc2a 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -50,10 +50,7 @@ class VideoIntroPanel extends StatefulWidget { class _VideoIntroPanelState extends State with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin { - late String heroTag; late VideoIntroController videoIntroController; - VideoDetailData? videoDetail; - StreamSubscription? _listener; // 添加页面缓存 @override @@ -63,55 +60,40 @@ class _VideoIntroPanelState extends State void initState() { super.initState(); - /// fix 全屏时参数丢失 - // if (Get.arguments != null) { - // heroTag = Get.arguments['heroTag']; - // } - heroTag = widget.heroTag; - videoIntroController = Get.put(VideoIntroController(), tag: heroTag) - ..heroTag = heroTag; - // _futureBuilderFuture = videoIntroController.queryVideoIntro(); - _listener = videoIntroController.videoDetail.listen((value) { - videoDetail = value; - }); - } - - @override - void dispose() { - _listener?.cancel(); - super.dispose(); + videoIntroController = Get.put(VideoIntroController(), tag: widget.heroTag) + ..heroTag = widget.heroTag; } @override Widget build(BuildContext context) { super.build(context); - return Obx(() => videoIntroController.videoDetail.value.title == null - ? VideoInfo( - loadingStatus: true, - videoDetail: videoDetail, - heroTag: heroTag, - showAiBottomSheet: widget.showAiBottomSheet, - showIntroDetail: () => widget.showIntroDetail( - videoDetail, - videoIntroController.videoTags, + return Obx( + () => videoIntroController.videoDetail.value.title == null + ? VideoInfo( + loadingStatus: true, + videoDetail: videoIntroController.videoDetail.value, + heroTag: widget.heroTag, + showAiBottomSheet: widget.showAiBottomSheet, + showIntroDetail: () => widget.showIntroDetail( + videoIntroController.videoDetail.value, + videoIntroController.videoTags, + ), + showEpisodes: widget.showEpisodes, + onShowMemberPage: widget.onShowMemberPage, + ) + : VideoInfo( + loadingStatus: false, + videoDetail: videoIntroController.videoDetail.value, + heroTag: widget.heroTag, + showAiBottomSheet: widget.showAiBottomSheet, + showIntroDetail: () => widget.showIntroDetail( + videoIntroController.videoDetail.value, + videoIntroController.videoTags, + ), + showEpisodes: widget.showEpisodes, + onShowMemberPage: widget.onShowMemberPage, ), - showEpisodes: widget.showEpisodes, - onShowMemberPage: widget.onShowMemberPage, - ) - : VideoInfo( - //key:herotag - key: ValueKey(heroTag), - loadingStatus: false, - videoDetail: videoIntroController.videoDetail.value, - heroTag: heroTag, - showAiBottomSheet: widget.showAiBottomSheet, - showIntroDetail: () => widget.showIntroDetail( - videoIntroController.videoDetail.value, - videoIntroController.videoTags, - ), - showEpisodes: widget.showEpisodes, - onShowMemberPage: widget.onShowMemberPage, - )); + ); } } diff --git a/lib/pages/video/detail/introduction/widgets/season.dart b/lib/pages/video/detail/introduction/widgets/season.dart index ecf2fb7ff..24328dabc 100644 --- a/lib/pages/video/detail/introduction/widgets/season.dart +++ b/lib/pages/video/detail/introduction/widgets/season.dart @@ -54,16 +54,15 @@ class _SeasonPanelState extends State { // .episodes; currentIndex.value = episodes.indexWhere( (EpisodeItem e) => e.cid == _videoDetailController.seasonCid); - _listener = _videoDetailController.cid.listen((int p0) { + _listener = _videoDetailController.cid.listen((int cid) { if (widget.pages != null && widget.pages!.length != 1) { - bool isPart = widget.pages?.indexWhere((item) => item.cid == p0) != -1; + bool isPart = widget.pages?.indexWhere((item) => item.cid == cid) != -1; if (isPart) return; } - _videoDetailController.seasonCid = p0; + _videoDetailController.seasonCid = cid; _findEpisode(); currentIndex.value = episodes.indexWhere( (EpisodeItem e) => e.cid == _videoDetailController.seasonCid); - if (!mounted) return; }); } diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index a32d22789..b6072dd01 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -44,6 +44,8 @@ import 'package:PiliPalaX/plugin/pl_player/index.dart'; import 'package:PiliPalaX/plugin/pl_player/models/play_repeat.dart'; import 'package:PiliPalaX/services/service_locator.dart'; import 'package:PiliPalaX/utils/storage.dart'; +import 'package:PiliPalaX/models/bangumi/info.dart' as bangumi; +import 'package:PiliPalaX/models/video_detail_res.dart' as video; import 'package:screen_brightness/screen_brightness.dart'; import '../../../services/shutdown_timer_service.dart'; @@ -1514,7 +1516,12 @@ class _VideoDetailPageState extends State ? bangumiIntroController.changeSeasonOrbangu : videoIntroController.changeSeasonOrbangu, showTitle: false, - onReverse: onReversePlay, + onReverse: () { + onReversePlay( + videoDetailController.bvid, + IdUtils.bv2av(videoDetailController.bvid), + ); + }, ), ), ), @@ -1599,7 +1606,7 @@ class _VideoDetailPageState extends State }, onReverse: () { Get.back(); - onReversePlay(); + onReversePlay(bvid, aid); }, ); if (isFullScreen) { @@ -1614,7 +1621,7 @@ class _VideoDetailPageState extends State } } - void onReversePlay() { + void onReversePlay(bvid, aid) { videoIntroController.videoDetail.value.ugcSeason! .sections![videoDetailController.seasonIndex.value].episodes = videoIntroController @@ -1625,8 +1632,29 @@ class _VideoDetailPageState extends State .episodes! .reversed .toList(); - videoDetailController.seasonIndex.refresh(); - videoDetailController.cid.refresh(); + + if (videoDetailController.reverseFromFirst.not) { + // keep current episode + videoDetailController.seasonIndex.refresh(); + videoDetailController.cid.refresh(); + } else { + // switch to first episode + dynamic episode = videoIntroController.videoDetail.value.ugcSeason! + .sections![videoDetailController.seasonIndex.value].episodes!.first; + if (episode.cid != videoDetailController.cid.value) { + videoIntroController.changeSeasonOrbangu( + episode is bangumi.EpisodeItem ? episode.epId : null, + episode.runtimeType.toString() == "EpisodeItem" ? episode.bvid : bvid, + episode.cid, + episode.runtimeType.toString() == "EpisodeItem" ? episode.aid : aid, + episode is video.EpisodeItem + ? episode.arc?.pic + : episode is bangumi.EpisodeItem + ? episode.cover + : null, + ); + } + } } void showViewPoints() { diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index e2f0e9ffe..a4c030950 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -148,6 +148,9 @@ class GStorage { static bool get showArgueMsg => setting.get(SettingBoxKey.showArgueMsg, defaultValue: true); + static bool get reverseFromFirst => + setting.get(SettingBoxKey.reverseFromFirst, defaultValue: true); + static List get dynamicDetailRatio => List.from(setting .get(SettingBoxKey.dynamicDetailRatio, defaultValue: [60.0, 40.0])); @@ -350,6 +353,7 @@ class SettingBoxKey { horizontalMemberPage = 'horizontalMemberPage', replyLengthLimit = 'replyLengthLimit', showArgueMsg = 'showArgueMsg', + reverseFromFirst = 'reverseFromFirst', // Sponsor Block enableSponsorBlock = 'enableSponsorBlock',