diff --git a/lib/common/widgets/image/custom_grid_view.dart b/lib/common/widgets/image/custom_grid_view.dart index 4f13cc326..c31df1be8 100644 --- a/lib/common/widgets/image/custom_grid_view.dart +++ b/lib/common/widgets/image/custom_grid_view.dart @@ -77,7 +77,7 @@ class CustomGridView extends StatelessWidget { final bool fullScreen; static bool horizontalPreview = Pref.horizontalPreview; - static final _regex = RegExp(r'/(videoV|dynamicDetail)'); + static const _routes = ['/videoV', '/dynamicDetail']; void onTap(BuildContext context, int index) { final imgList = picArr.map( @@ -94,7 +94,7 @@ class CustomGridView extends StatelessWidget { ).toList(); if (horizontalPreview && !fullScreen && - Get.currentRoute.startsWith(_regex) && + _routes.contains(Get.currentRoute) && !context.mediaQuerySize.isPortrait) { final scaffoldState = Scaffold.maybeOf(context); if (scaffoldState != null) { diff --git a/lib/pages/episode_panel/view.dart b/lib/pages/episode_panel/view.dart index 917cea4a8..eab548284 100644 --- a/lib/pages/episode_panel/view.dart +++ b/lib/pages/episode_panel/view.dart @@ -169,14 +169,24 @@ class _EpisodePanelState extends State _isReversed = List.filled(widget.list.length, false); if (widget.type == EpisodeType.season && Accounts.main.isLogin) { - _favState = LoadingState.loading().obs; - VideoHttp.videoRelation(bvid: widget.bvid).then( - (result) { - if (result case Success(:var response)) { - _favState!.value = Success(response.seasonFav ?? false); - } - }, - ); + final favState = + widget.ugcIntroController?.seasonFavState[widget.seasonId]; + if (favState != null) { + _favState = Success(favState).obs; + } else { + _favState = LoadingState.loading().obs; + VideoHttp.videoRelation(bvid: widget.bvid).then( + (result) { + if (!mounted) return; + if (result case Success(:var response)) { + final seasonFav = response.seasonFav ?? false; + _favState!.value = Success(seasonFav); + widget.ugcIntroController?.seasonFavState[widget.seasonId] = + seasonFav; + } + }, + ); + } } } @@ -588,6 +598,8 @@ class _EpisodePanelState extends State if (result.isSuccess) { SmartDialog.showToast('${response ? '取消' : ''}订阅成功'); _favState!.value = Success(!response); + widget.ugcIntroController?.seasonFavState[widget.seasonId] = + !response; } else { result.toast(); } diff --git a/lib/pages/member_upower_rank/view.dart b/lib/pages/member_upower_rank/view.dart index c3157ce3c..e9372729a 100644 --- a/lib/pages/member_upower_rank/view.dart +++ b/lib/pages/member_upower_rank/view.dart @@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.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/loading_widget/http_error.dart'; +import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/image_type.dart'; @@ -171,14 +172,7 @@ class _UpowerRankPageState extends State ) { late final width = MediaQuery.textScalerOf(context).scale(32); return switch (loadingState) { - Loading() => const SliverToBoxAdapter( - child: SizedBox( - height: 125, - child: Center( - child: CircularProgressIndicator(), - ), - ), - ), + Loading() => linearLoading, Success?>(:var response) => response != null && response.isNotEmpty ? SliverList.builder( diff --git a/lib/pages/share/view.dart b/lib/pages/share/view.dart index 734d6d831..195dbbefb 100644 --- a/lib/pages/share/view.dart +++ b/lib/pages/share/view.dart @@ -202,11 +202,11 @@ class _SharePanelState extends State { height: 40, decoration: BoxDecoration( shape: BoxShape.circle, - color: theme.colorScheme.secondaryContainer, + color: theme.colorScheme.onInverseSurface, ), child: Icon( Icons.person_add_alt, - color: theme.colorScheme.onSecondaryContainer, + color: theme.colorScheme.onSurfaceVariant, ), ), ), diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index 1f34d1553..c289a33e9 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -1657,6 +1657,10 @@ class VideoDetailController extends GetxController @override void onClose() { + cancelSkipTimer(); + positionSubscription?.cancel(); + positionSubscription = null; + cid.close(); if (isFileSource) { cacheLocalProgress(); } diff --git a/lib/pages/video/introduction/ugc/controller.dart b/lib/pages/video/introduction/ugc/controller.dart index 1068e2ef7..87e9fb37d 100644 --- a/lib/pages/video/introduction/ugc/controller.dart +++ b/lib/pages/video/introduction/ugc/controller.dart @@ -64,6 +64,8 @@ class UgcIntroController extends CommonIntroController with ReloadMixin { AiConclusionResult? aiConclusionResult; + late final Map seasonFavState = {}; + @override void onInit() { super.onInit(); diff --git a/lib/pages/video/introduction/ugc/widgets/action_item.dart b/lib/pages/video/introduction/ugc/widgets/action_item.dart index 9eb8fe250..09ba3c304 100644 --- a/lib/pages/video/introduction/ugc/widgets/action_item.dart +++ b/lib/pages/video/introduction/ugc/widgets/action_item.dart @@ -1,6 +1,7 @@ import 'dart:math' show pi; import 'package:PiliPlus/utils/extension/theme_ext.dart'; +import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:flutter/material.dart'; class ActionItem extends StatelessWidget { @@ -74,6 +75,9 @@ class ActionItem extends StatelessWidget { borderRadius: const BorderRadius.all(Radius.circular(6)), onTap: _isThumbsUp ? null : onTap, onLongPress: _isThumbsUp ? null : onLongPress, + onSecondaryTap: PlatformUtils.isMobile || _isThumbsUp + ? null + : onLongPress, onTapDown: _isThumbsUp ? (_) => onStartTriple!() : null, onTapUp: _isThumbsUp ? (_) => onCancelTriple!(true) : null, onTapCancel: _isThumbsUp ? onCancelTriple : null, diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 46b82e1b4..527ee074d 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -324,11 +324,7 @@ class _VideoDetailPageVState extends State ?..removeStatusLister(playerListener) ..removePositionListener(positionListener); - videoDetailController - ..cancelSkipTimer() - ..positionSubscription?.cancel() - ..cid.close() - ..animController?.removeListener(animListener); + videoDetailController.animController?.removeListener(animListener); Get.delete( tag: videoDetailController.heroTag, diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart index b613d2cf9..c82af7dff 100644 --- a/lib/pages/whisper_detail/view.dart +++ b/lib/pages/whisper_detail/view.dart @@ -55,25 +55,6 @@ class _WhisperDetailPageState return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - leading: Center( - child: SizedBox( - width: 34, - height: 34, - child: IconButton( - tooltip: '返回', - style: IconButton.styleFrom( - padding: EdgeInsets.zero, - backgroundColor: theme.colorScheme.secondaryContainer, - ), - onPressed: Get.back, - icon: Icon( - Icons.arrow_back_outlined, - size: 18, - color: theme.colorScheme.onSecondaryContainer, - ), - ), - ), - ), title: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { @@ -118,18 +99,19 @@ class _WhisperDetailPageState ), actions: [ IconButton( + tooltip: '设置', onPressed: () => Get.to( WhisperLinkSettingPage( talkerUid: _whisperDetailController.talkerId, ), ), icon: Icon( - size: 20, + size: 22, Icons.settings, color: theme.colorScheme.onSurfaceVariant.withValues(alpha: 0.8), ), ), - const SizedBox(width: 10), + const SizedBox(width: 5), ], ), body: Padding( diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 1ebf4d8b9..d168872b5 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -1721,7 +1721,9 @@ class PlPlayerController { disableAutoEnterPip(); setPlayCallBack(null); dmState.clear(); - _clearPreview(); + if (showSeekPreview) { + _clearPreview(); + } Utils.channel.setMethodCallHandler(null); _timer?.cancel(); _timerForSeek?.cancel(); @@ -1744,6 +1746,9 @@ class PlPlayerController { } await removeListeners(); + subscriptions.clear(); + _positionListeners.clear(); + _statusListeners.clear(); if (playerStatus.playing) { WakelockPlus.disable(); } @@ -1779,7 +1784,7 @@ class PlPlayerController { ); } - final Map previewCache = {}; + late final Map previewCache = {}; LoadingState? videoShot; late final RxBool showPreview = false.obs; late final showSeekPreview = Pref.showSeekPreview; diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index aa54d27b5..a1715626b 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -1846,6 +1846,7 @@ class _PLVideoPlayerState extends State plPlayerController, maxWidth, maxHeight, + () => mounted, ), if (isFullScreen || plPlayerController.isDesktopPip) ...[ @@ -2537,6 +2538,7 @@ Widget buildSeekPreviewWidget( PlPlayerController plPlayerController, double maxWidth, double maxHeight, + ValueGetter isMounted, ) { return Obx( () { @@ -2591,6 +2593,7 @@ Widget buildSeekPreviewWidget( onSetSize: (xSize, ySize) => data ..imgXSize = imgXSize = xSize ..imgYSize = imgYSize = ySize, + isMounted: isMounted, ), ); }, @@ -2615,6 +2618,7 @@ class VideoShotImage extends StatefulWidget { required this.imgYSize, required this.height, required this.onSetSize, + required this.isMounted, }); final Map imageCache; @@ -2625,6 +2629,7 @@ class VideoShotImage extends StatefulWidget { final double imgYSize; final double height; final Function(double imgXSize, double imgYSize) onSetSize; + final ValueGetter isMounted; @override State createState() => _VideoShotImageState(); @@ -2707,7 +2712,9 @@ class _VideoShotImageState extends State { widget.imageCache[url] = null; _getImg(url).then((image) { if (image != null) { - widget.imageCache[url] = image; + if (widget.isMounted()) { + widget.imageCache[url] = image; + } if (mounted) { _image = image; _initSizeIfNeeded();