diff --git a/lib/common/widgets/flutter/pop_scope.dart b/lib/common/widgets/flutter/pop_scope.dart index 85401dc0f..33cffe2e1 100644 --- a/lib/common/widgets/flutter/pop_scope.dart +++ b/lib/common/widgets/flutter/pop_scope.dart @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide PopScope; +import 'package:get/get_core/src/get_main.dart'; +import 'package:get/get_navigation/src/extension_navigation.dart'; abstract class PopScopeState extends State - implements PopEntry { + implements PopEntry { ModalRoute? _route; @override @@ -14,31 +16,60 @@ abstract class PopScopeState extends State @override late final ValueNotifier canPopNotifier; - void initCanPopNotifier() { - canPopNotifier = ValueNotifier(false); - } + bool get initCanPop => true; @override void initState() { super.initState(); - initCanPopNotifier(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - final ModalRoute? nextRoute = ModalRoute.of(context); - if (nextRoute != _route) { - _route?.unregisterPopEntry(this); - _route = nextRoute; - _route?.registerPopEntry(this); - } + canPopNotifier = ValueNotifier(initCanPop); + _route = (Get.routing.route as ModalRoute)..registerPopEntry(this); } @override void dispose() { _route?.unregisterPopEntry(this); + _route = null; canPopNotifier.dispose(); super.dispose(); } } + +// ignore: camel_case_types +typedef popScope = PopScope; + +class PopScope extends StatefulWidget { + const PopScope({ + super.key, + required this.child, + this.canPop = true, + required this.onPopInvokedWithResult, + }); + + final Widget child; + + final PopInvokedWithResultCallback onPopInvokedWithResult; + + final bool canPop; + + @override + State createState() => _PopScopeState(); +} + +class _PopScopeState extends PopScopeState { + @override + bool get initCanPop => widget.canPop; + + @override + void onPopInvokedWithResult(bool didPop, Object? result) { + widget.onPopInvokedWithResult(didPop, result); + } + + @override + void didUpdateWidget(T oldWidget) { + super.didUpdateWidget(oldWidget); + canPopNotifier.value = widget.canPop; + } + + @override + Widget build(BuildContext context) => widget.child; +} diff --git a/lib/common/widgets/keep_alive_wrapper.dart b/lib/common/widgets/keep_alive_wrapper.dart index a7e76076e..5fdb25cf6 100644 --- a/lib/common/widgets/keep_alive_wrapper.dart +++ b/lib/common/widgets/keep_alive_wrapper.dart @@ -3,11 +3,11 @@ import 'package:flutter/material.dart'; class KeepAliveWrapper extends StatefulWidget { const KeepAliveWrapper({ super.key, - required this.builder, + required this.child, this.wantKeepAlive = true, }); - final WidgetBuilder builder; + final Widget child; final bool wantKeepAlive; @override @@ -19,7 +19,7 @@ class _KeepAliveWrapperState extends State @override Widget build(BuildContext context) { super.build(context); - return widget.builder(context); + return widget.child; } @override diff --git a/lib/common/widgets/route_aware_mixin.dart b/lib/common/widgets/route_aware_mixin.dart new file mode 100644 index 000000000..3fa04481b --- /dev/null +++ b/lib/common/widgets/route_aware_mixin.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; +import 'package:get/get_core/src/get_main.dart'; +import 'package:get/get_navigation/src/extension_navigation.dart'; +import 'package:get/get_navigation/src/routes/default_route.dart' + show GetPageRoute; + +final routeObserver = RouteObserver(); + +mixin RouteAwareMixin on State, RouteAware { + @override + void initState() { + super.initState(); + routeObserver.subscribe(this, Get.routing.route as GetPageRoute); + } + + @override + void dispose() { + routeObserver.unsubscribe(this); + super.dispose(); + } +} diff --git a/lib/main.dart b/lib/main.dart index d05282603..5a7920998 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/build_config.dart'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/back_detector.dart'; import 'package:PiliPlus/common/widgets/custom_toast.dart'; +import 'package:PiliPlus/common/widgets/route_aware_mixin.dart'; import 'package:PiliPlus/common/widgets/scale_app.dart'; import 'package:PiliPlus/common/widgets/scroll_behavior.dart'; import 'package:PiliPlus/http/init.dart'; @@ -18,7 +19,6 @@ import 'package:PiliPlus/utils/date_utils.dart'; import 'package:PiliPlus/utils/extension/iterable_ext.dart'; import 'package:PiliPlus/utils/extension/theme_ext.dart'; import 'package:PiliPlus/utils/json_file_handler.dart'; -import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/path_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/request_utils.dart'; @@ -296,7 +296,7 @@ class MyApp extends StatelessWidget { builder: _builder, ), navigatorObservers: [ - PageUtils.routeObserver, + routeObserver, FlutterSmartDialog.observer, ], scrollBehavior: PlatformUtils.isDesktop diff --git a/lib/pages/common/search/common_search_page.dart b/lib/pages/common/search/common_search_page.dart index 74a9fa7ae..3855836e5 100644 --- a/lib/pages/common/search/common_search_page.dart +++ b/lib/pages/common/search/common_search_page.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -20,7 +21,7 @@ abstract class CommonSearchPageState if (controller case final MultiSelectBase multiCtr) { return Obx(() { final enableMultiSelect = multiCtr.enableMultiSelect.value; - return PopScope( + return popScope( canPop: !enableMultiSelect, onPopInvokedWithResult: (didPop, result) { if (enableMultiSelect) { diff --git a/lib/pages/danmaku_block/view.dart b/lib/pages/danmaku_block/view.dart index 5d85af8df..b0ea54e1a 100644 --- a/lib/pages/danmaku_block/view.dart +++ b/lib/pages/danmaku_block/view.dart @@ -64,7 +64,7 @@ class _DanmakuBlockPageState extends State { children: DmBlockType.values .map( (e) => KeepAliveWrapper( - builder: (context) => Obx( + child: Obx( () => tabViewBuilder(e.index, _controller.rules[e.index]), ), ), diff --git a/lib/pages/download/detail/view.dart b/lib/pages/download/detail/view.dart index 71d4a00a5..f555bbb11 100644 --- a/lib/pages/download/detail/view.dart +++ b/lib/pages/download/detail/view.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart'; @@ -85,7 +86,7 @@ class _DownloadDetailPageState extends State final colorScheme = ColorScheme.of(context); return Obx(() { final enableMultiSelect = this.enableMultiSelect.value; - return PopScope( + return popScope( canPop: !enableMultiSelect, onPopInvokedWithResult: (didPop, result) { if (enableMultiSelect) { diff --git a/lib/pages/download/downloading/view.dart b/lib/pages/download/downloading/view.dart index e84255b09..80cf3b5a4 100644 --- a/lib/pages/download/downloading/view.dart +++ b/lib/pages/download/downloading/view.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart'; @@ -33,7 +34,7 @@ class _DownloadingPageState extends State Widget build(BuildContext context) { return Obx(() { final enableMultiSelect = this.enableMultiSelect.value; - return PopScope( + return popScope( canPop: !enableMultiSelect, onPopInvokedWithResult: (didPop, result) { if (enableMultiSelect) { diff --git a/lib/pages/download/view.dart b/lib/pages/download/view.dart index c32c83b0c..dfa2ad31e 100644 --- a/lib/pages/download/view.dart +++ b/lib/pages/download/view.dart @@ -5,6 +5,7 @@ import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/layout_builder.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/select_mask.dart'; @@ -49,7 +50,7 @@ class _DownloadPageState extends State { final padding = MediaQuery.viewPaddingOf(context); return Obx(() { final enableMultiSelect = _controller.enableMultiSelect.value; - return PopScope( + return popScope( canPop: !enableMultiSelect, onPopInvokedWithResult: (didPop, result) { if (enableMultiSelect) { diff --git a/lib/pages/episode_panel/view.dart b/lib/pages/episode_panel/view.dart index 2ae1072a3..f27bffbc9 100644 --- a/lib/pages/episode_panel/view.dart +++ b/lib/pages/episode_panel/view.dart @@ -279,7 +279,7 @@ class _EpisodePanelState extends State ) { final isCurrTab = tabIndex == widget.initialTabIndex; return KeepAliveWrapper( - builder: (context) => CustomScrollView( + child: CustomScrollView( reverse: _isReversed[tabIndex], physics: const AlwaysScrollableScrollPhysics(), controller: _itemScrollController[tabIndex], diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index 60a6db53b..4d8fffb46 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; @@ -51,7 +52,7 @@ class _FavDetailPageState extends State with GridMixin { return Obx( () { final enableMultiSelect = _favDetailController.enableMultiSelect.value; - return PopScope( + return popScope( canPop: !enableMultiSelect, onPopInvokedWithResult: (didPop, result) { if (enableMultiSelect) { diff --git a/lib/pages/history/view.dart b/lib/pages/history/view.dart index 610998d02..8a4219c51 100644 --- a/lib/pages/history/view.dart +++ b/lib/pages/history/view.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/flutter/page/tabs.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/gesture/horizontal_drag_gesture_recognizer.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; @@ -84,7 +85,7 @@ class _HistoryPageState extends State () { final enableMultiSelect = _historyController.baseCtr.enableMultiSelect.value; - return PopScope( + return popScope( canPop: !enableMultiSelect, onPopInvokedWithResult: (didPop, result) { if (enableMultiSelect) { @@ -141,7 +142,7 @@ class _HistoryPageState extends State horizontalDragGestureRecognizer: CustomHorizontalDragGestureRecognizer.new, children: [ - KeepAliveWrapper(builder: (context) => child), + KeepAliveWrapper(child: child), ..._historyController.tabs.map( (item) => HistoryPage(type: item.type), ), diff --git a/lib/pages/later/view.dart b/lib/pages/later/view.dart index b33e30f32..db37be02a 100644 --- a/lib/pages/later/view.dart +++ b/lib/pages/later/view.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/flutter/page/tabs.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/gesture/horizontal_drag_gesture_recognizer.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; @@ -65,7 +66,7 @@ class _LaterPageState extends State return Obx( () { final enableMultiSelect = _baseCtr.enableMultiSelect.value; - return PopScope( + return popScope( canPop: !enableMultiSelect, onPopInvokedWithResult: (didPop, result) { if (enableMultiSelect) { diff --git a/lib/pages/live_area/view.dart b/lib/pages/live_area/view.dart index 51858e1d0..7ea4458a4 100644 --- a/lib/pages/live_area/view.dart +++ b/lib/pages/live_area/view.dart @@ -95,57 +95,57 @@ class _LiveAreaPageState extends State { children: response .map( (e) => KeepAliveWrapper( - builder: (context) { - if (e.areaList.isNullOrEmpty) { - return const SizedBox.shrink(); - } - return GridView.builder( - padding: EdgeInsets.only( - top: 12, - bottom: bottom + 100, - ), - gridDelegate: - const SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 100, - mainAxisSpacing: 10, - crossAxisSpacing: 10, - mainAxisExtent: 80, + child: e.areaList.isNullOrEmpty + ? const SizedBox.shrink() + : GridView.builder( + padding: EdgeInsets.only( + top: 12, + bottom: bottom + 100, ), - itemCount: e.areaList!.length, - itemBuilder: (context, index) { - final item = e.areaList![index]; - return _tagItem( - theme: theme, - item: item, - onPressed: () { - // success - bool? isFav = - _controller.favInfo[item.id]; - if (isFav == true) { - _controller.favInfo[item.id] = false; - _controller.favState - ..value.data.remove(item) - ..refresh(); - (context as Element).markNeedsBuild(); - } else { - // check - if (_controller - .favState - .value - .isSuccess) { - _controller.favInfo[item.id] = true; - _controller.favState - ..value.data.add(item) - ..refresh(); - (context as Element) - .markNeedsBuild(); - } - } + gridDelegate: + const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 100, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + mainAxisExtent: 80, + ), + itemCount: e.areaList!.length, + itemBuilder: (context, index) { + final item = e.areaList![index]; + return _tagItem( + theme: theme, + item: item, + onPressed: () { + // success + bool? isFav = + _controller.favInfo[item.id]; + if (isFav == true) { + _controller.favInfo[item.id] = + false; + _controller.favState + ..value.data.remove(item) + ..refresh(); + (context as Element) + .markNeedsBuild(); + } else { + // check + if (_controller + .favState + .value + .isSuccess) { + _controller.favInfo[item.id] = + true; + _controller.favState + ..value.data.add(item) + ..refresh(); + (context as Element) + .markNeedsBuild(); + } + } + }, + ); }, - ); - }, - ); - }, + ), ), ) .toList(), diff --git a/lib/pages/live_dm_block/view.dart b/lib/pages/live_dm_block/view.dart index 0271c2823..7f190168c 100644 --- a/lib/pages/live_dm_block/view.dart +++ b/lib/pages/live_dm_block/view.dart @@ -47,12 +47,10 @@ class _LiveDmBlockPageState extends State { controller: _controller.tabController, children: [ KeepAliveWrapper( - builder: (context) => - Obx(() => _buildKeyword(_controller.keywordList)), + child: Obx(() => _buildKeyword(_controller.keywordList)), ), KeepAliveWrapper( - builder: (context) => - Obx(() => _buildKeyword(_controller.shieldUserList)), + child: Obx(() => _buildKeyword(_controller.shieldUserList)), ), ], ); diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 1e395e128..73e4d29eb 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -6,10 +6,12 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/flutter/page/page_view.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/flutter/text_field/controller.dart'; import 'package:PiliPlus/common/widgets/gesture/horizontal_drag_gesture_recognizer.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; +import 'package:PiliPlus/common/widgets/route_aware_mixin.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/models/common/image_type.dart'; import 'package:PiliPlus/models/common/live/live_contribution_rank_type.dart'; @@ -56,7 +58,7 @@ class LiveRoomPage extends StatefulWidget { } class _LiveRoomPageState extends State - with WidgetsBindingObserver, RouteAware { + with WidgetsBindingObserver, RouteAware, RouteAwareMixin { final String heroTag = Utils.generateRandomString(6); late final LiveRoomController _liveRoomController; late final PlPlayerController plPlayerController; @@ -83,10 +85,6 @@ class _LiveRoomPageState extends State @override void didChangeDependencies() { super.didChangeDependencies(); - PageUtils.routeObserver.subscribe( - this, - ModalRoute.of(context)! as PageRoute, - ); padding = MediaQuery.viewPaddingOf(context); final size = MediaQuery.sizeOf(context); maxWidth = size.width; @@ -159,7 +157,6 @@ class _LiveRoomPageState extends State plPlayerController ..removeStatusLister(playerListener) ..dispose(); - PageUtils.routeObserver.unsubscribe(this); for (final e in LiveContributionRankType.values) { Get.delete( tag: '${_liveRoomController.roomId}${e.name}', @@ -352,7 +349,7 @@ class _LiveRoomPageState extends State ], ); } - return PopScope( + return popScope( canPop: !isFullScreen && !plPlayerController.isDesktopPip, onPopInvokedWithResult: plPlayerController.onPopInvokedWithResult, child: player, @@ -731,7 +728,7 @@ class _LiveRoomPageState extends State horizontalDragGestureRecognizer: CustomHorizontalDragGestureRecognizer.new, children: [ - KeepAliveWrapper(builder: (context) => chat()), + KeepAliveWrapper(child: chat()), SuperChatPanel( key: scKey, controller: _liveRoomController, diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index 5e57f9d6a..36353995e 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/flutter/tabs.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; +import 'package:PiliPlus/common/widgets/route_aware_mixin.dart'; import 'package:PiliPlus/models/common/nav_bar_config.dart'; import 'package:PiliPlus/pages/home/view.dart'; import 'package:PiliPlus/pages/main/controller.dart'; @@ -13,7 +14,6 @@ import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/extension/context_ext.dart'; import 'package:PiliPlus/utils/extension/size_ext.dart'; import 'package:PiliPlus/utils/extension/theme_ext.dart'; -import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; @@ -32,11 +32,19 @@ class MainApp extends StatefulWidget { } class _MainAppState extends PopScopeState - with RouteAware, WidgetsBindingObserver, WindowListener, TrayListener { + with + RouteAware, + RouteAwareMixin, + WidgetsBindingObserver, + WindowListener, + TrayListener { final _mainController = Get.put(MainController()); late final _setting = GStorage.setting; late EdgeInsets _padding; + @override + bool get initCanPop => false; + @override void initState() { super.initState(); @@ -65,10 +73,6 @@ class _MainAppState extends PopScopeState if (PlatformUtils.isDesktop) { windowManager.setBrightness(brightness); } - PageUtils.routeObserver.subscribe( - this, - ModalRoute.of(context) as PageRoute, - ); if (!_mainController.useSideBar) { _mainController.useBottomNav = MediaQuery.sizeOf(context).isPortrait; } @@ -106,7 +110,6 @@ class _MainAppState extends PopScopeState trayManager.removeListener(this); windowManager.removeListener(this); } - PageUtils.routeObserver.unsubscribe(this); WidgetsBinding.instance.removeObserver(this); PiliScheme.listener?.cancel(); GStorage.close(); diff --git a/lib/pages/member_upower_rank/view.dart b/lib/pages/member_upower_rank/view.dart index e862fd61a..191b5feec 100644 --- a/lib/pages/member_upower_rank/view.dart +++ b/lib/pages/member_upower_rank/view.dart @@ -136,9 +136,7 @@ class _UpowerRankPageState extends State Expanded( child: tabBarView( children: [ - KeepAliveWrapper( - builder: (context) => child, - ), + KeepAliveWrapper(child: child), ...tabs .skip(1) .map( diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index 68c84e106..4f8a236c1 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -108,7 +108,7 @@ class VideoDetailController extends GetxController // 请求返回的视频信息 late PlayUrlModel data; - final Rx videoState = LoadingState.loading().obs; + final RxBool videoState = false.obs; /// 播放器配置 画质 音质 解码格式 final Rxn currentVideoQa = Rxn(); @@ -269,8 +269,6 @@ class VideoDetailController extends GetxController } } - bool imageview = false; - final isLoginVideo = Accounts.get(AccountType.video).isLogin; late final watchProgress = GStorage.watchProgress; @@ -711,9 +709,7 @@ class VideoDetailController extends GetxController pgcType: isUgc ? null : pgcType, videoType: videoType, onInit: () { - if (videoState.value is! Success) { - videoState.value = const Success(null); - } + videoState.value = true; setSubtitle(vttSubtitlesIndex.value); }, width: firstVideo.width, @@ -845,7 +841,7 @@ class VideoDetailController extends GetxController if (data.dash == null) { SmartDialog.showToast('视频资源不存在'); _autoPlay.value = false; - videoState.value = const Error('视频资源不存在'); + videoState.value = false; if (plPlayerController.isFullScreen.value) { plPlayerController.toggleFullScreen(false); } @@ -940,7 +936,7 @@ class VideoDetailController extends GetxController await _initPlayerIfNeeded(autoFullScreenFlag); } else { _autoPlay.value = false; - videoState.value = result..toast(); + videoState.value = false; if (plPlayerController.isFullScreen.value) { plPlayerController.toggleFullScreen(false); } diff --git a/lib/pages/video/introduction/pgc/widgets/intro_detail.dart b/lib/pages/video/introduction/pgc/widgets/intro_detail.dart index f29309597..c8619e1e2 100644 --- a/lib/pages/video/introduction/pgc/widgets/intro_detail.dart +++ b/lib/pages/video/introduction/pgc/widgets/intro_detail.dart @@ -100,7 +100,7 @@ class _IntroDetailState extends State horizontalDragGestureRecognizer: () => TabBarDragGestureRecognizer(isDxAllowed: isDxAllowed), children: [ - KeepAliveWrapper(builder: (context) => _buildInfo(theme)), + KeepAliveWrapper(child: _buildInfo(theme)), PgcReviewPage( name: widget.item.title!, mediaId: widget.item.mediaId, diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 6f9b7b2d4..42f66da77 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -5,12 +5,12 @@ import 'dart:ui'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; +import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; -import 'package:PiliPlus/common/widgets/image_viewer/hero_dialog_route.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; +import 'package:PiliPlus/common/widgets/route_aware_mixin.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_pinned_dynamic_header.dart'; -import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/main.dart'; import 'package:PiliPlus/models/common/episode_panel_type.dart'; import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart'; @@ -78,7 +78,11 @@ class VideoDetailPageV extends StatefulWidget { } class _VideoDetailPageVState extends State - with TickerProviderStateMixin, RouteAware, WidgetsBindingObserver { + with + TickerProviderStateMixin, + RouteAware, + RouteAwareMixin, + WidgetsBindingObserver { final heroTag = Get.arguments['heroTag']; late final VideoDetailController videoDetailController; @@ -368,7 +372,6 @@ class _VideoDetailPageVState extends State PlPlayerController.updatePlayCount(); } } - PageUtils.routeObserver.unsubscribe(this); WidgetsBinding.instance.removeObserver(this); if (PlatformUtils.isMobile) { showStatusBar(); @@ -379,10 +382,8 @@ class _VideoDetailPageVState extends State @override // 离开当前页面时 void didPushNext() { - if (Get.routing.route is HeroDialogRoute) { - videoDetailController.imageview = true; - return; - } + super.didPushNext(); + isShowing = false; WidgetsBinding.instance.removeObserver(this); @@ -390,11 +391,11 @@ class _VideoDetailPageVState extends State ScreenBrightnessPlatform.instance.resetApplicationScreenBrightness(); } - videoDetailController.cancelBlockListener(); - introController.cancelTimer(); videoDetailController + ..videoState.value = false + ..cancelBlockListener() ..playerStatus = plPlayerController?.playerStatus.value ..brightness = plPlayerController?.brightness.value; if (plPlayerController != null) { @@ -404,21 +405,18 @@ class _VideoDetailPageVState extends State ..removePositionListener(positionListener) ..pause(); } - isShowing = false; - super.didPushNext(); } @override // 返回当前页面时 void didPopNext() { - if (videoDetailController.imageview) { - videoDetailController.imageview = false; + super.didPopNext(); + + if (plPlayerController?.isCloseAll ?? false) { return; } - if (plPlayerController?.isCloseAll == true) { - return; - } + isShowing = true; WidgetsBinding.instance.addObserver(this); @@ -428,7 +426,6 @@ class _VideoDetailPageVState extends State videoDetailController.plPlayerController.pause(); } - isShowing = true; PlPlayerController.setPlayCallBack(playCallBack); introController.startTimer(); @@ -460,21 +457,14 @@ class _VideoDetailPageVState extends State ); } else if (videoDetailController.plPlayerController.preInitPlayer && !videoDetailController.isQuerying && - videoDetailController.videoState.value is! Error) { + videoDetailController.videoUrl != null) { videoDetailController.playerInit(); } - - super.didPopNext(); } @override void didChangeDependencies() { super.didChangeDependencies(); - PageUtils.routeObserver.subscribe( - this, - ModalRoute.of(context)! as PageRoute, - ); - padding = MediaQuery.viewPaddingOf(context); final size = MediaQuery.sizeOf(context); @@ -538,9 +528,7 @@ class _VideoDetailPageVState extends State ..addListener(animListener); if (PlatformUtils.isMobile && mounted && isShowing && !isFullScreen) { if (isPortrait) { - if (!videoDetailController.imageview) { - showStatusBar(); - } + showStatusBar(); } else if (!videoDetailController.horizontalScreen) { hideStatusBar(); } @@ -1085,7 +1073,7 @@ class _VideoDetailPageVState extends State localIntroPanel() else if (showIntro) KeepAliveWrapper( - builder: (context) => CustomScrollView( + child: CustomScrollView( key: const PageStorageKey(CommonIntroController), controller: videoDetailController.effectiveIntroScrollCtr, @@ -1342,7 +1330,7 @@ class _VideoDetailPageVState extends State required double width, required double height, bool isPipMode = false, - }) => PopScope( + }) => popScope( key: videoDetailController.videoPlayerKey, canPop: !isFullScreen && @@ -1351,7 +1339,7 @@ class _VideoDetailPageVState extends State onPopInvokedWithResult: _onPopInvokedWithResult, child: Obx( () => - videoDetailController.videoState.value is! Success || + !videoDetailController.videoState.value || !videoDetailController.autoPlay || plPlayerController?.videoController == null ? const SizedBox.shrink() @@ -1589,7 +1577,7 @@ class _VideoDetailPageVState extends State children: [ const Positioned.fill(child: ColoredBox(color: Colors.black)), - if (isShowing) plPlayer(width: width, height: height), + plPlayer(width: width, height: height), Obx(() { if (!videoDetailController.autoPlay) { @@ -1773,75 +1761,76 @@ class _VideoDetailPageVState extends State if (videoDetailController.isFileSource) { return localIntroPanel(needCtr: needCtr); } - Widget introPanel() => KeepAliveWrapper( - builder: (context) { - final child = CustomScrollView( - key: const PageStorageKey(CommonIntroController), - controller: needCtr - ? videoDetailController.effectiveIntroScrollCtr - : null, - physics: !needCtr - ? const AlwaysScrollableScrollPhysics( - parent: ClampingScrollPhysics(), - ) - : null, - slivers: [ - if (videoDetailController.isUgc) ...[ - UgcIntroPanel( - key: videoIntroKey, - heroTag: heroTag, - showAiBottomSheet: showAiBottomSheet, - showEpisodes: showEpisodes, - onShowMemberPage: onShowMemberPage, - isPortrait: isPortrait, - isHorizontal: isHorizontal ?? width! / height! >= kScreenRatio, - ), - if (needRelated && videoDetailController.showRelatedVideo) ...[ - SliverToBoxAdapter( - child: Padding( - padding: const EdgeInsets.only(top: StyleString.safeSpace), - child: Divider( - height: 1, - indent: 12, - endIndent: 12, - color: themeData.colorScheme.outline.withValues( - alpha: 0.08, - ), + Widget introPanel() { + Widget child = CustomScrollView( + key: const PageStorageKey(CommonIntroController), + controller: needCtr + ? videoDetailController.effectiveIntroScrollCtr + : null, + physics: !needCtr + ? const AlwaysScrollableScrollPhysics( + parent: ClampingScrollPhysics(), + ) + : null, + slivers: [ + if (videoDetailController.isUgc) ...[ + UgcIntroPanel( + key: videoIntroKey, + heroTag: heroTag, + showAiBottomSheet: showAiBottomSheet, + showEpisodes: showEpisodes, + onShowMemberPage: onShowMemberPage, + isPortrait: isPortrait, + isHorizontal: isHorizontal ?? width! / height! >= kScreenRatio, + ), + if (needRelated && videoDetailController.showRelatedVideo) ...[ + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only( + top: StyleString.safeSpace, + ), + child: Divider( + height: 1, + indent: 12, + endIndent: 12, + color: themeData.colorScheme.outline.withValues( + alpha: 0.08, ), ), ), - RelatedVideoPanel(key: videoRelatedKey, heroTag: heroTag), - ], - ] else - PgcIntroPage( - key: videoIntroKey, - heroTag: heroTag, - cid: videoDetailController.cid.value, - showEpisodes: showEpisodes, - showIntroDetail: showIntroDetail, - maxWidth: width ?? maxWidth, - isLandscape: !isPortrait, - ), - SliverToBoxAdapter( - child: SizedBox( - height: - (videoDetailController.isPlayAll && !isPortrait - ? 80 - : StyleString.safeSpace) + - padding.bottom, ), + RelatedVideoPanel(key: videoRelatedKey, heroTag: heroTag), + ], + ] else + PgcIntroPage( + key: videoIntroKey, + heroTag: heroTag, + cid: videoDetailController.cid.value, + showEpisodes: showEpisodes, + showIntroDetail: showIntroDetail, + maxWidth: width ?? maxWidth, + isLandscape: !isPortrait, ), - ], + SliverToBoxAdapter( + child: SizedBox( + height: + (videoDetailController.isPlayAll && !isPortrait + ? 80 + : StyleString.safeSpace) + + padding.bottom, + ), + ), + ], + ); + if (isNested) { + child = ExtendedVisibilityDetector( + uniqueKey: const Key('intro-panel'), + child: child, ); - if (isNested) { - return ExtendedVisibilityDetector( - uniqueKey: const Key('intro-panel'), - child: child, - ); - } - return child; - }, - ); + } + return KeepAliveWrapper(child: child); + } + if (videoDetailController.isPlayAll) { return Stack( clipBehavior: Clip.none, @@ -1894,7 +1883,7 @@ class _VideoDetailPageVState extends State Widget get seasonPanel { final videoDetail = ugcIntroController.videoDetail.value; return KeepAliveWrapper( - builder: (context) => Column( + child: Column( children: [ if ((videoDetail.pages?.length ?? 0) > 1) if (videoDetail.ugcSeason != null) diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index e080f8432..42d6ce04f 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -1683,8 +1683,11 @@ class PlPlayerController with BlockConfigMixin { } bool onPopInvokedWithResult(bool didPop, Object? result) { - if (Platform.isAndroid && didPop) { - _disableAutoEnterPipIfNeeded(); + if (didPop) { + if (Platform.isAndroid) { + _disableAutoEnterPipIfNeeded(); + } + return true; } if (controlsLock.value) { onLockControl(false); diff --git a/lib/utils/page_utils.dart b/lib/utils/page_utils.dart index 79649c71e..647cf604e 100644 --- a/lib/utils/page_utils.dart +++ b/lib/utils/page_utils.dart @@ -37,9 +37,6 @@ import 'package:get/get.dart'; import 'package:url_launcher/url_launcher.dart'; abstract final class PageUtils { - static final RouteObserver routeObserver = - RouteObserver(); - static RelativeRect menuPosition(Offset offset) { return .fromLTRB(offset.dx, offset.dy, offset.dx, 0); }