From 199ad274b707d284bf60c4f46de114a912365c74 Mon Sep 17 00:00:00 2001 From: My-Responsitories <107370289+My-Responsitories@users.noreply.github.com> Date: Sat, 13 Jun 2026 02:43:37 +0000 Subject: [PATCH] tweaks (#2404) * tweaks * opt: semantics --- lib/common/style.dart | 4 +- .../image_grid/image_grid_builder.dart | 21 ++++- .../widgets/image_grid/image_grid_view.dart | 31 +++---- lib/grpc/audio.dart | 8 +- lib/grpc/space.dart | 5 +- lib/grpc/view.dart | 4 +- lib/pages/about/view.dart | 12 +-- .../publish/common_rich_text_pub_page.dart | 3 +- lib/pages/dynamics_create_vote/view.dart | 3 +- lib/pages/fav_create/view.dart | 3 +- .../login/geetest/geetest_webview_dialog.dart | 2 +- lib/pages/login/view.dart | 17 ++-- lib/pages/member_profile/view.dart | 3 +- .../widgets/ordered_multi_select_dialog.dart | 2 +- .../introduction/ugc/widgets/action_item.dart | 15 ++-- lib/pages/video/reply_reply/view.dart | 45 ++++------ lib/pages/video/view.dart | 8 +- lib/pages/video/widgets/header_control.dart | 4 +- lib/pages/whisper_detail/view.dart | 3 +- lib/plugin/pl_player/controller.dart | 23 +++--- lib/plugin/pl_player/view/view.dart | 82 ++++++------------- lib/services/shutdown_timer_service.dart | 2 +- lib/utils/image_utils.dart | 3 - 23 files changed, 123 insertions(+), 180 deletions(-) diff --git a/lib/common/style.dart b/lib/common/style.dart index 2a7793b06..09b83ffa5 100644 --- a/lib/common/style.dart +++ b/lib/common/style.dart @@ -9,9 +9,7 @@ abstract final class Style { static const aspectRatio = 16 / 10; static const aspectRatio16x9 = 16 / 9; static const imgMaxRatio = 2.6; - static const bottomSheetRadius = BorderRadius.vertical( - top: Radius.circular(18), - ); + static const bottomSheetRadius = BorderRadius.vertical(top: .circular(18)); static const dialogFixedConstraints = BoxConstraints.tightFor(width: 420); static const topBarHeight = 52.0; static const buttonStyle = ButtonStyle( diff --git a/lib/common/widgets/image_grid/image_grid_builder.dart b/lib/common/widgets/image_grid/image_grid_builder.dart index 6d749034a..0136aeaac 100644 --- a/lib/common/widgets/image_grid/image_grid_builder.dart +++ b/lib/common/widgets/image_grid/image_grid_builder.dart @@ -37,7 +37,9 @@ import 'package:flutter/rendering.dart' BoxHitTestEntry, ContainerParentDataMixin, InformationCollector, - DiagnosticsDebugCreator; + DiagnosticsDebugCreator, + RenderObjectVisitor, + SemanticsConfiguration; /// ref [LayoutBuilder] @@ -250,6 +252,23 @@ class RenderImageGrid extends RenderBox super.dispose(); } + @override + void visitChildrenForSemantics(RenderObjectVisitor visitor) { + RenderBox? child = firstChild; + while (child != null) { + visitor(child); + child = (child.parentData as MultiChildLayoutParentData).nextSibling; + } + } + + @override + void describeSemanticsConfiguration(SemanticsConfiguration config) { + super.describeSemanticsConfiguration(config); + config + ..explicitChildNodes = true + ..isSemanticBoundary = true; + } + @override bool get isRepaintBoundary => true; // gif repaint } diff --git a/lib/common/widgets/image_grid/image_grid_view.dart b/lib/common/widgets/image_grid/image_grid_view.dart index b2fbfc84d..de226dc99 100644 --- a/lib/common/widgets/image_grid/image_grid_view.dart +++ b/lib/common/widgets/image_grid/image_grid_view.dart @@ -22,7 +22,6 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/image_grid/image_grid_builder.dart'; -import 'package:PiliPlus/models/common/badge_type.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/utils/extension/context_ext.dart'; import 'package:PiliPlus/utils/extension/num_ext.dart'; @@ -209,9 +208,9 @@ class ImageGridView extends StatelessWidget { width: width, height: height, decoration: BoxDecoration( - color: Theme.of( + color: ColorScheme.of( context, - ).colorScheme.onInverseSurface.withValues(alpha: 0.4), + ).onInverseSurface.withValues(alpha: 0.4), ), child: Image.asset( Assets.loading, @@ -221,6 +220,7 @@ class ImageGridView extends StatelessWidget { ), ); return List.generate(picArr.length, (index) { + void onTap() => _onTap(context, index); final item = picArr[index]; final borderRadius = _borderRadius( info.column, @@ -241,30 +241,21 @@ class ImageGridView extends StatelessWidget { getPlaceHolder: () => placeHolder, ), if (item.isLivePhoto) - const PBadge( - text: 'Live', - right: 8, - bottom: 8, - type: PBadgeType.gray, - ) + const PBadge(text: 'Live', right: 8, bottom: 8, type: .gray) else if (item.isLongPic) - const PBadge( - text: '长图', - right: 8, - bottom: 8, - ), + const PBadge(text: '长图', right: 8, bottom: 8), ], ); if (!item.isLongPic) { - child = Hero( - tag: '${item.url}$hashCode', - child: child, - ); + child = Hero(tag: '${item.url}$hashCode', child: child); } - return LayoutId( - id: index, + child = Semantics( + label: '图片,第 ${index + 1} 张,共 ${picArr.length} 张', + button: true, + onTap: onTap, child: child, ); + return LayoutId(id: index, child: child); }); }, ), diff --git a/lib/grpc/audio.dart b/lib/grpc/audio.dart index 09d8eb6cf..08b39ac67 100644 --- a/lib/grpc/audio.dart +++ b/lib/grpc/audio.dart @@ -25,8 +25,8 @@ abstract final class AudioGrpc { playerArgs: PlayerArgs( qn: Int64(qn), fnval: Int64(fnval), - forceHost: Int64(2), - voiceBalance: Int64(1), + forceHost: Int64.TWO, + voiceBalance: Int64.ONE, ), ), PlayURLResp.fromBuffer, @@ -60,8 +60,8 @@ abstract final class AudioGrpc { playerArgs: PlayerArgs( qn: Int64(qn), fnval: Int64(fnval), - forceHost: Int64(2), - voiceBalance: Int64(1), + forceHost: Int64.TWO, + voiceBalance: Int64.ONE, ), extraId: extraId, sortOpt: SortOption(order: order), diff --git a/lib/grpc/space.dart b/lib/grpc/space.dart index 232b86bcc..683c43b16 100644 --- a/lib/grpc/space.dart +++ b/lib/grpc/space.dart @@ -17,10 +17,7 @@ abstract final class SpaceGrpc { GrpcUrl.opusSpaceFlow, OpusSpaceFlowReq( hostMid: Int64(hostMid), - pagination: Pagination( - pageSize: 20, - next: next, - ), + pagination: Pagination(pageSize: 20, next: next), filterType: filterType, ), OpusSpaceFlowResp.fromBuffer, diff --git a/lib/grpc/view.dart b/lib/grpc/view.dart index e8de15f06..c0392d220 100644 --- a/lib/grpc/view.dart +++ b/lib/grpc/view.dart @@ -10,9 +10,7 @@ abstract final class ViewGrpc { }) { return GrpcReq.request( GrpcUrl.view, - ViewReq( - bvid: bvid, - ), + ViewReq(bvid: bvid), ViewReply.fromBuffer, ); } diff --git a/lib/pages/about/view.dart b/lib/pages/about/view.dart index 0935babba..3a232286d 100644 --- a/lib/pages/about/view.dart +++ b/lib/pages/about/view.dart @@ -181,22 +181,14 @@ Commit Hash: ${BuildConfig.commitHash}''', onTap: PiliAndroidHelper.openLinkVerifySettings, leading: const Icon(MdiIcons.linkBoxOutline), title: const Text('打开受支持的链接'), - trailing: Icon( - Icons.arrow_forward, - size: 16, - color: outline, - ), + trailing: Icon(Icons.arrow_forward, size: 16, color: outline), ), ListTile( onTap: () => PageUtils.launchURL('${Constants.sourceCodeUrl}/issues'), leading: const Icon(Icons.feedback_outlined), title: const Text('问题反馈'), - trailing: Icon( - Icons.arrow_forward, - size: 16, - color: outline, - ), + trailing: Icon(Icons.arrow_forward, size: 16, color: outline), ), ListTile( onTap: () => Get.toNamed('/logs'), diff --git a/lib/pages/common/publish/common_rich_text_pub_page.dart b/lib/pages/common/publish/common_rich_text_pub_page.dart index 44385d6c9..33c9f51db 100644 --- a/lib/pages/common/publish/common_rich_text_pub_page.dart +++ b/lib/pages/common/publish/common_rich_text_pub_page.dart @@ -225,9 +225,10 @@ abstract class CommonRichTextPubPageState const Duration(milliseconds: 500), () async { try { - List pickedFiles = await imagePicker.pickMultiImage( + final pickedFiles = await imagePicker.pickMultiImage( limit: limit, imageQuality: 100, + requestFullMetadata: false, ); if (pickedFiles.isNotEmpty) { for (int i = 0; i < pickedFiles.length; i++) { diff --git a/lib/pages/dynamics_create_vote/view.dart b/lib/pages/dynamics_create_vote/view.dart index f7610a54d..f23524260 100644 --- a/lib/pages/dynamics_create_vote/view.dart +++ b/lib/pages/dynamics_create_vote/view.dart @@ -428,9 +428,10 @@ class _CreateVotePageState extends State { const Duration(milliseconds: 500), () async { try { - XFile? pickedFile = await imagePicker.pickImage( + final pickedFile = await imagePicker.pickImage( imageQuality: 100, source: ImageSource.gallery, + requestFullMetadata: false, ); if (pickedFile != null) { final path = pickedFile.path; diff --git a/lib/pages/fav_create/view.dart b/lib/pages/fav_create/view.dart index c0cbf7f78..4b9faba17 100644 --- a/lib/pages/fav_create/view.dart +++ b/lib/pages/fav_create/view.dart @@ -116,9 +116,10 @@ class _CreateFavPageState extends State { Future _pickImg(BuildContext context, ThemeData theme) async { try { - XFile? pickedFile = await _imagePicker.pickImage( + final pickedFile = await _imagePicker.pickImage( source: ImageSource.gallery, imageQuality: 100, + requestFullMetadata: false, ); if (pickedFile != null && mounted) { String imgPath = pickedFile.path; diff --git a/lib/pages/login/geetest/geetest_webview_dialog.dart b/lib/pages/login/geetest/geetest_webview_dialog.dart index 42feb2fb5..dad4afa07 100644 --- a/lib/pages/login/geetest/geetest_webview_dialog.dart +++ b/lib/pages/login/geetest/geetest_webview_dialog.dart @@ -37,7 +37,7 @@ class _GeetestWebviewDialogState extends State { Webview? _linuxWebview; late bool _linuxWebviewLoading = true; - String _showJs(String response) => + static String _showJs(String response) => 't=Geetest($response).onSuccess(()=>R("success",t.getValidate())).onError(o=>R("error",o)).onClose(o=>R("close",o));t.onReady(()=>t.verify())'; @override diff --git a/lib/pages/login/view.dart b/lib/pages/login/view.dart index c8ed426b0..b4cc05df4 100644 --- a/lib/pages/login/view.dart +++ b/lib/pages/login/view.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/dial_prefix.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; @@ -68,17 +66,16 @@ class _LoginPageState extends State { TextButton.icon( onPressed: () async { SmartDialog.showLoading(msg: '正在生成截图'); - RenderRepaintBoundary boundary = - globalKey.currentContext!.findRenderObject()! + final boundary = + globalKey.currentContext!.findRenderObject() as RenderRepaintBoundary; final image = await boundary.toImage(pixelRatio: 3); - ByteData? byteData = await image.toByteData( - format: ImageByteFormat.png, - ); - Uint8List pngBytes = byteData!.buffer.asUint8List(); + final byteData = await image.toByteData(format: .png); + final pngBytes = byteData!.buffer.asUint8List(); + image.dispose(); SmartDialog.dismiss(); - String picName = - "${Constants.appName}_loginQRCode_${ImageUtils.time}"; + final picName = + "${Constants.appName}_loginQRCode_${_loginPageCtr.codeInfo.value.data.authCode.hashCode.toUnsigned(32).toRadixString(16)}"; ImageUtils.saveByteImg(bytes: pngBytes, fileName: picName); }, icon: const Icon(Icons.save), diff --git a/lib/pages/member_profile/view.dart b/lib/pages/member_profile/view.dart index 7f663931c..0fe5f38e7 100644 --- a/lib/pages/member_profile/view.dart +++ b/lib/pages/member_profile/view.dart @@ -475,9 +475,10 @@ class _EditProfilePageState extends State { Future _pickImg(ThemeData theme) async { try { - XFile? pickedFile = await _imagePicker.pickImage( + final pickedFile = await _imagePicker.pickImage( source: ImageSource.gallery, imageQuality: 100, + requestFullMetadata: false, ); if (pickedFile != null && mounted) { String? imagePath = pickedFile.path; diff --git a/lib/pages/setting/widgets/ordered_multi_select_dialog.dart b/lib/pages/setting/widgets/ordered_multi_select_dialog.dart index 6d8900c16..7f1452173 100644 --- a/lib/pages/setting/widgets/ordered_multi_select_dialog.dart +++ b/lib/pages/setting/widgets/ordered_multi_select_dialog.dart @@ -88,7 +88,7 @@ class _OrderedMultiSelectDialogState ), TextButton( onPressed: () { - assert(_tempValues.values.isSorted((a, b) => a.compareTo(b))); + assert(_tempValues.values.isSorted(Comparable.compare)); Get.back(result: _tempValues.keys.toList()); }, child: const Text('确定'), diff --git a/lib/pages/video/introduction/ugc/widgets/action_item.dart b/lib/pages/video/introduction/ugc/widgets/action_item.dart index d22481272..db61cdd2f 100644 --- a/lib/pages/video/introduction/ugc/widgets/action_item.dart +++ b/lib/pages/video/introduction/ugc/widgets/action_item.dart @@ -44,6 +44,7 @@ class ActionItem extends StatelessWidget { selectStatus ? selectIcon!.icon! : icon.icon, size: 18, color: selectStatus ? primary : icon.color ?? colorScheme.outline, + semanticLabel: semanticsLabel, ); if (animation != null) { @@ -53,11 +54,8 @@ class ActionItem extends StatelessWidget { children: [ AnimatedBuilder( animation: animation!, - builder: (context, child) => Arc( - size: 28, - color: primary, - progress: -animation!.value, - ), + builder: (context, child) => + Arc(size: 28, color: primary, progress: -animation!.value), ), child, ], @@ -69,7 +67,7 @@ class ActionItem extends StatelessWidget { child = Material( type: .transparency, child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(6)), + borderRadius: const .all(.circular(6)), onTap: _isThumbsUp ? null : onTap, onLongPress: _isThumbsUp ? null : onLongPress, onSecondaryTap: PlatformUtils.isMobile || _isThumbsUp @@ -104,9 +102,8 @@ class ActionItem extends StatelessWidget { if (hasText) { return AnimatedSwitcher( duration: const Duration(milliseconds: 300), - transitionBuilder: (Widget child, Animation animation) { - return ScaleTransition(scale: animation, child: child); - }, + transitionBuilder: (child, animation) => + ScaleTransition(scale: animation, child: child), child: child, ); } diff --git a/lib/pages/video/reply_reply/view.dart b/lib/pages/video/reply_reply/view.dart index c4825de06..ed7e3d910 100644 --- a/lib/pages/video/reply_reply/view.dart +++ b/lib/pages/video/reply_reply/view.dart @@ -203,17 +203,16 @@ class _VideoReplyReplyPanelState extends State } return _header(theme, firstFloor); }), - _sortWidget(theme), + _sortWidget(theme.colorScheme), ], - Obx(() => _buildBody(theme, _controller.loadingState.value)), + Obx( + () => _buildBody(theme.colorScheme, _controller.loadingState.value), + ), ], ), ); if (widget.isNested) { - return ExtendedVisibilityDetector( - uniqueKey: Key(_tag), - child: child, - ); + return ExtendedVisibilityDetector(uniqueKey: Key(_tag), child: child); } return child; } @@ -243,9 +242,9 @@ class _VideoReplyReplyPanelState extends State ); } - Widget _sortWidget(ThemeData theme) { + Widget _sortWidget(ColorScheme colorScheme) { return SliverPinnedHeader( - backgroundColor: theme.colorScheme.surface, + backgroundColor: colorScheme.surface, child: Padding( padding: const EdgeInsets.fromLTRB(12, 2.5, 6, 2.5), child: Row( @@ -265,18 +264,11 @@ class _VideoReplyReplyPanelState extends State TextButton.icon( style: Style.buttonStyle, onPressed: _controller.queryBySort, - icon: Icon( - Icons.sort, - size: 16, - color: theme.colorScheme.secondary, - ), + icon: Icon(Icons.sort, size: 16, color: colorScheme.secondary), label: Obx( () => Text( _controller.sortType.value.text!, - style: TextStyle( - fontSize: 13, - color: theme.colorScheme.secondary, - ), + style: TextStyle(fontSize: 13, color: colorScheme.secondary), ), ), ), @@ -287,7 +279,7 @@ class _VideoReplyReplyPanelState extends State } Widget _buildBody( - ThemeData theme, + ColorScheme colorScheme, LoadingState?> loadingState, ) { final jumpIndex = _controller.index.value; @@ -305,15 +297,13 @@ class _VideoReplyReplyPanelState extends State return Container( height: 125, alignment: Alignment.center, - margin: EdgeInsets.only( - bottom: MediaQuery.viewPaddingOf(context).bottom, - ), + margin: .only(bottom: MediaQuery.viewPaddingOf(context).bottom), child: Text( _controller.isEnd ? '没有更多了' : '加载中...', textAlign: TextAlign.center, style: TextStyle( fontSize: 12, - color: theme.colorScheme.outline, + color: colorScheme.outline, ), ), ); @@ -323,13 +313,10 @@ class _VideoReplyReplyPanelState extends State return ColoredBoxTransition( color: _colorAnimation ??= _controller.animController.drive( ColorTween( - begin: theme.colorScheme.onInverseSurface, - end: theme.colorScheme.surface, - ).chain( - CurveTween( - curve: const Interval(0.8, 1.0), // 前0.8s不变, 后0.2s开始动画 - ), - ), + begin: colorScheme.onInverseSurface, + end: colorScheme.surface, + // 前0.8s不变, 后0.2s开始动画 + ).chain(CurveTween(curve: const Interval(0.8, 1.0))), ), child: child, ); diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index e5e5be939..628809101 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -1614,9 +1614,7 @@ class _VideoDetailPageVState extends State return FilledButton.tonal( style: FilledButton.styleFrom( shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(6), - ), + borderRadius: .all(.circular(6)), ), backgroundColor: themeData .colorScheme @@ -1634,9 +1632,7 @@ class _VideoDetailPageVState extends State item, isStein: true, ); - videoDetailController.getSteinEdgeInfo( - item.id, - ); + videoDetailController.getSteinEdgeInfo(item.id); }, child: Text(item.option!), ); diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index 05d7a0bf3..5e98ad359 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -1974,9 +1974,7 @@ class HeaderControlState extends State FontAwesomeIcons.thumbsUp, color: Colors.white, ), - selectIcon: const Icon( - FontAwesomeIcons.solidThumbsUp, - ), + selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), selectStatus: introController.hasLike.value, semanticsLabel: '点赞', animation: introController.tripleAnimation, diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart index 9962334d8..593ae5a3a 100644 --- a/lib/pages/whisper_detail/view.dart +++ b/lib/pages/whisper_detail/view.dart @@ -344,9 +344,10 @@ class _WhisperDetailPageState ); } else { try { - final XFile? pickedFile = await imagePicker.pickImage( + final pickedFile = await imagePicker.pickImage( source: ImageSource.gallery, imageQuality: 100, + requestFullMetadata: false, ); if (pickedFile != null) { final path = pickedFile.path; diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 678636ce4..990fafc78 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -36,6 +36,7 @@ import 'package:PiliPlus/utils/android/android_helper.dart'; import 'package:PiliPlus/utils/android/bindings.g.dart'; import 'package:PiliPlus/utils/asset_utils.dart'; import 'package:PiliPlus/utils/device_utils.dart'; +import 'package:PiliPlus/utils/duration_utils.dart'; import 'package:PiliPlus/utils/extension/box_ext.dart'; import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/feed_back.dart'; @@ -46,7 +47,6 @@ import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; -import 'package:PiliPlus/utils/theme_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:archive/archive.dart' show getCrc32; import 'package:canvas_danmaku/canvas_danmaku.dart'; @@ -772,16 +772,12 @@ class PlPlayerController with BlockConfigMixin { assert(_videoPlayerController == null); final opt = { 'video-sync': Pref.videoSync, + if (Platform.isAndroid) 'ao': Pref.audioOutput, + 'volume': + (PlatformUtils.isMobile ? Pref.playerVolume : volume.value * 100) + .toString(), + 'volume-max': kMaxVolume.toString(), }; - if (Platform.isAndroid) { - opt['ao'] = Pref.audioOutput; - } - if (PlatformUtils.isMobile) { - opt['volume'] = Pref.playerVolume.toString(); - } else { - opt['volume'] = (volume.value * 100).toString(); - } - opt['volume-max'] = kMaxVolume.toString(); final autosync = Pref.autosync; if (autosync != '0') { opt['autosync'] = autosync; @@ -1737,6 +1733,9 @@ class PlPlayerController with BlockConfigMixin { Future takeScreenshot() async { SmartDialog.showToast('截图中'); + final time = DurationUtils.formatDuration( + position.inMilliseconds / 1000, + ).replaceAll(':', '-'); final image = await videoPlayerController?.screenshot(); if (image != null) { SmartDialog.showToast('点击弹窗保存截图'); @@ -1748,7 +1747,7 @@ class PlPlayerController with BlockConfigMixin { if (bytes != null) { ImageUtils.saveByteImg( bytes: bytes.buffer.asUint8List(), - fileName: 'screenshot_${ImageUtils.time}', + fileName: 'screenshot_${cid}_$time', ); } Get.back(); @@ -1765,7 +1764,7 @@ class PlPlayerController with BlockConfigMixin { decoration: BoxDecoration( border: Border.all( width: 5, - color: ThemeUtils.theme.colorScheme.surface, + color: ColorScheme.of(context).surface, ), ), child: Padding( diff --git a/lib/plugin/pl_player/view/view.dart b/lib/plugin/pl_player/view/view.dart index 3d80961f3..901add55e 100644 --- a/lib/plugin/pl_player/view/view.dart +++ b/lib/plugin/pl_player/view/view.dart @@ -25,8 +25,6 @@ import 'package:PiliPlus/models/common/super_resolution_type.dart'; import 'package:PiliPlus/models/common/video/video_quality.dart'; import 'package:PiliPlus/models/video/play/url.dart'; import 'package:PiliPlus/models_new/video/video_detail/episode.dart' as ugc; -import 'package:PiliPlus/models_new/video/video_detail/episode.dart'; -import 'package:PiliPlus/models_new/video/video_detail/section.dart'; import 'package:PiliPlus/models_new/video/video_detail/ugc_season.dart'; import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/pages/danmaku/danmaku_model.dart'; @@ -579,9 +577,9 @@ class _PLVideoPlayerState extends State String bvid = plPlayerController.bvid; List episodes = []; if (isSeason) { - final List sections = videoDetail.ugcSeason!.sections!; + final sections = videoDetail.ugcSeason!.sections!; for (int i = 0; i < sections.length; i++) { - final List episodesList = sections[i].episodes!; + final episodesList = sections[i].episodes!; for (final item in episodesList) { if (item.cid == currentCid) { index = i; @@ -811,18 +809,12 @@ class _PLVideoPlayerState extends State if (videoInfo.dash == null) { return const SizedBox.shrink(); } - final List videoFormat = videoInfo.supportFormats!; - final int totalQaSam = videoFormat.length; - int usefulQaSam = 0; - final List video = videoInfo.dash!.video!; - final Set idSet = {}; - for (final VideoItem item in video) { - final int id = item.id!; - if (!idSet.contains(id)) { - idSet.add(id); - usefulQaSam++; - } - } + final videoFormat = videoInfo.supportFormats!; + final totalQaSam = videoFormat.length; + final usefulQaSam = videoInfo.dash!.video! + .map((i) => i.id) + .toSet() + .length; return PopupMenuButton( tooltip: '画质', requestFocus: false, @@ -892,16 +884,8 @@ class _PLVideoPlayerState extends State height: 30, tooltip: isFullScreen ? '退出全屏' : '全屏', icon: isFullScreen - ? const Icon( - Icons.fullscreen_exit, - size: 24, - color: Colors.white, - ) - : const Icon( - Icons.fullscreen, - size: 24, - color: Colors.white, - ), + ? const Icon(Icons.fullscreen_exit, size: 24, color: Colors.white) + : const Icon(Icons.fullscreen, size: 24, color: Colors.white), onTap: () => plPlayerController.triggerFullScreen(status: !isFullScreen), onSecondaryTap: () => plPlayerController.triggerFullScreen( @@ -914,29 +898,24 @@ class _PLVideoPlayerState extends State final isNotFileSource = !plPlayerController.isFileSource; List userSpecifyItemLeft = [ - BottomControlType.playOrPause, - BottomControlType.time, - if (!isNotFileSource || anySeason) ...[ - BottomControlType.pre, - BottomControlType.next, - ], + .playOrPause, + .time, + if (!isNotFileSource || anySeason) ...[.pre, .next], ]; final flag = isFullScreen || plPlayerController.isDesktopPip || maxWidth >= 500; - List userSpecifyItemRight = [ - if (isNotFileSource && plPlayerController.showDmChart) - BottomControlType.dmChart, - if (plPlayerController.isAnim) BottomControlType.superResolution, - if (isNotFileSource && plPlayerController.showViewPoints) - BottomControlType.viewPoints, - if (isNotFileSource && anySeason) BottomControlType.episode, - if (flag) BottomControlType.fit, - if (isNotFileSource) BottomControlType.aiTranslate, - BottomControlType.subtitle, - BottomControlType.speed, - if (isNotFileSource && flag) BottomControlType.qa, - if (!plPlayerController.isDesktopPip) BottomControlType.fullscreen, + final List userSpecifyItemRight = [ + if (isNotFileSource && plPlayerController.showDmChart) .dmChart, + if (plPlayerController.isAnim) .superResolution, + if (isNotFileSource && plPlayerController.showViewPoints) .viewPoints, + if (isNotFileSource && anySeason) .episode, + if (flag) .fit, + if (isNotFileSource) .aiTranslate, + .subtitle, + .speed, + if (isNotFileSource && flag) .qa, + if (!plPlayerController.isDesktopPip) .fullscreen, ]; return PlayerBar( children: [ @@ -1058,21 +1037,14 @@ class _PLVideoPlayerState extends State displayTime: const Duration(milliseconds: 1500), maskColor: Colors.transparent, builder: (context) => Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), + padding: const .symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(6), - ), + borderRadius: const .all(.circular(6)), color: colorScheme.secondaryContainer, ), child: Text( '松开手指,取消进退', - style: TextStyle( - color: colorScheme.onSecondaryContainer, - ), + style: TextStyle(color: colorScheme.onSecondaryContainer), ), ), ); diff --git a/lib/services/shutdown_timer_service.dart b/lib/services/shutdown_timer_service.dart index c3bbebe38..5f34a1d8c 100644 --- a/lib/services/shutdown_timer_service.dart +++ b/lib/services/shutdown_timer_service.dart @@ -165,7 +165,7 @@ class ShutdownTimerService { const Center(child: Text('定时关闭', style: titleStyle)), const SizedBox(height: 10), ...{...scheduleTimeMinutes, _durationInMinutes} - .sorted((a, b) => a.compareTo(b)) + .sorted(Comparable.compare) .map( (minutes) => ListTile( dense: true, diff --git a/lib/utils/image_utils.dart b/lib/utils/image_utils.dart index a929b9301..41636c47f 100644 --- a/lib/utils/image_utils.dart +++ b/lib/utils/image_utils.dart @@ -20,14 +20,11 @@ import 'package:dio/dio.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:intl/intl.dart' show DateFormat; import 'package:live_photo_maker/live_photo_maker.dart'; import 'package:saver_gallery/saver_gallery.dart'; import 'package:share_plus/share_plus.dart'; abstract final class ImageUtils { - static String get time => - DateFormat('yyyy-MM-dd_HH-mm-ss').format(DateTime.now()); static bool silentDownImg = Pref.silentDownImg; static final _albumPath = Platform.isAndroid ? 'Pictures/${Constants.appName}'