diff --git a/lib/common/widgets/custom_icon.dart b/lib/common/widgets/custom_icon.dart index a7e7f2222..8555a8d3d 100644 --- a/lib/common/widgets/custom_icon.dart +++ b/lib/common/widgets/custom_icon.dart @@ -2,7 +2,7 @@ import 'package:flutter/widgets.dart'; -class CustomIcon { +class CustomIcons { static const IconData coin = _CustomIconData(0xe800); static const IconData dm_off = _CustomIconData(0xe801); static const IconData dm_on = _CustomIconData(0xe802); diff --git a/lib/pages/article/view.dart b/lib/pages/article/view.dart index 3f4d4674e..7f93e739e 100644 --- a/lib/pages/article/view.dart +++ b/lib/pages/article/view.dart @@ -682,7 +682,7 @@ class _ArticlePageState extends CommonDynPageState { Expanded( child: textIconButton( text: '分享', - icon: CustomIcon.share_node, + icon: CustomIcons.share_node, stat: null, onPressed: () => Utils.shareText(controller.url), ), diff --git a/lib/pages/dynamics/widgets/content_panel.dart b/lib/pages/dynamics/widgets/content_panel.dart index 76e1114fa..a0a0df620 100644 --- a/lib/pages/dynamics/widgets/content_panel.dart +++ b/lib/pages/dynamics/widgets/content_panel.dart @@ -52,7 +52,7 @@ Widget content( padding: const EdgeInsets.only(right: 4), child: Icon( size: 18, - CustomIcon.topic_tag, + CustomIcons.topic_tag, color: theme.colorScheme.primary, ), ), diff --git a/lib/pages/dynamics_create/view.dart b/lib/pages/dynamics_create/view.dart index f1f3f0481..f210094b2 100644 --- a/lib/pages/dynamics_create/view.dart +++ b/lib/pages/dynamics_create/view.dart @@ -147,7 +147,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState { child: Padding( padding: const EdgeInsets.only(right: 5), child: Icon( - CustomIcon.topic_tag, + CustomIcons.topic_tag, size: 18, color: hasTopic ? null @@ -604,7 +604,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState { children: [ item( onTap: _onReserve, - icon: Icon(CustomIcon.live_reserve, size: 28, color: color), + icon: Icon(CustomIcons.live_reserve, size: 28, color: color), title: '直播预约', ), ], diff --git a/lib/pages/dynamics_detail/view.dart b/lib/pages/dynamics_detail/view.dart index 8d815dfd7..1f754520f 100644 --- a/lib/pages/dynamics_detail/view.dart +++ b/lib/pages/dynamics_detail/view.dart @@ -293,7 +293,7 @@ class _DynamicDetailPageState extends CommonDynPageState { ), Expanded( child: textIconButton( - icon: CustomIcon.share_node, + icon: CustomIcons.share_node, text: '分享', stat: null, onPressed: () => Utils.shareText( diff --git a/lib/pages/dynamics_select_topic/widgets/item.dart b/lib/pages/dynamics_select_topic/widgets/item.dart index 3df4ccf5b..54ec85a0b 100644 --- a/lib/pages/dynamics_select_topic/widgets/item.dart +++ b/lib/pages/dynamics_select_topic/widgets/item.dart @@ -28,7 +28,7 @@ class DynTopicItem extends StatelessWidget { child: Padding( padding: EdgeInsets.only(right: 5), child: Icon( - CustomIcon.topic_tag, + CustomIcons.topic_tag, size: 18, ), ), diff --git a/lib/pages/dynamics_topic/view.dart b/lib/pages/dynamics_topic/view.dart index 043aa3b53..74365efa9 100644 --- a/lib/pages/dynamics_topic/view.dart +++ b/lib/pages/dynamics_topic/view.dart @@ -58,7 +58,7 @@ class _DynTopicPageState extends State with DynMixin { SmartDialog.showToast('账号未登录'); } }, - icon: const Icon(CustomIcon.topic_tag, size: 20), + icon: const Icon(CustomIcons.topic_tag, size: 20), label: const Text('参与话题'), ), body: refreshIndicator( diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 4aa209231..73253b5ba 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'dart:ui'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; +import 'package:PiliPlus/common/widgets/custom_icon.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/scroll_physics.dart'; @@ -798,12 +799,12 @@ class _LiveRoomPageState extends State icon: enableShowLiveDanmaku ? const Icon( size: 22, - Icons.subtitles_outlined, + CustomIcons.dm_on, color: Color(0xFFEEEEEE), ) : const Icon( size: 22, - Icons.subtitles_off_outlined, + CustomIcons.dm_off, color: Color(0xFFEEEEEE), ), ), diff --git a/lib/pages/live_room/widgets/bottom_control.dart b/lib/pages/live_room/widgets/bottom_control.dart index d5dbcb913..bd4cda145 100644 --- a/lib/pages/live_room/widgets/bottom_control.dart +++ b/lib/pages/live_room/widgets/bottom_control.dart @@ -1,3 +1,4 @@ +import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/pages/live_room/controller.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart'; import 'package:PiliPlus/plugin/pl_player/models/video_fit_type.dart'; @@ -76,12 +77,12 @@ class BottomControl extends StatelessWidget { icon: enableShowLiveDanmaku ? const Icon( size: 18, - Icons.subtitles_outlined, + CustomIcons.dm_on, color: Colors.white, ) : const Icon( size: 18, - Icons.subtitles_off_outlined, + CustomIcons.dm_off, color: Colors.white, ), onTap: () { diff --git a/lib/pages/music/view.dart b/lib/pages/music/view.dart index 5a872c911..9d6c6db00 100644 --- a/lib/pages/music/view.dart +++ b/lib/pages/music/view.dart @@ -286,7 +286,7 @@ class _MusicDetailPageState extends CommonDynPageState { // ), Expanded( child: textIconButton( - icon: CustomIcon.share_node, + icon: CustomIcons.share_node, text: '分享', onPressed: () => Utils.shareText(controller.shareUrl), diff --git a/lib/pages/pgc_review/child/view.dart b/lib/pages/pgc_review/child/view.dart index 5c028e224..aad333d0a 100644 --- a/lib/pages/pgc_review/child/view.dart +++ b/lib/pages/pgc_review/child/view.dart @@ -254,13 +254,13 @@ class _PgcReviewChildPageState extends State (index) { if (index <= item.score - 1) { return const Icon( - CustomIcon.star_favorite_solid, + CustomIcons.star_favorite_solid, size: 13, color: Color(0xFFFFAD35), ); } return const Icon( - CustomIcon.star_favorite_line, + CustomIcons.star_favorite_line, size: 14, color: Colors.grey, ); diff --git a/lib/pages/pgc_review/post/view.dart b/lib/pages/pgc_review/post/view.dart index 2ecf59eac..94ecd8e69 100644 --- a/lib/pages/pgc_review/post/view.dart +++ b/lib/pages/pgc_review/post/view.dart @@ -94,12 +94,12 @@ class _PgcReviewPostPanelState extends State { return Obx( () => index <= _score.value - 1 ? const Icon( - CustomIcon.star_favorite_solid, + CustomIcons.star_favorite_solid, size: 50, color: Color(0xFFFFAD35), ) : const Icon( - CustomIcon.star_favorite_line, + CustomIcons.star_favorite_line, size: 50, color: Colors.grey, ), diff --git a/lib/pages/setting/models/extra_settings.dart b/lib/pages/setting/models/extra_settings.dart index dccccc491..7ed06e5fc 100644 --- a/lib/pages/setting/models/extra_settings.dart +++ b/lib/pages/setting/models/extra_settings.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'dart:math' show pi, max; +import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/image/custom_grid_view.dart' show CustomGridView, ImageModel; import 'package:PiliPlus/common/widgets/pendant_avatar.dart'; @@ -243,7 +244,7 @@ List get extraSettings => [ title: '弹幕行高', subtitle: '默认1.6', setKey: SettingBoxKey.danmakuLineHeight, - leading: const Icon(Icons.subtitles_outlined), + leading: const Icon(CustomIcons.dm_settings), getTrailing: () => Text( Pref.danmakuLineHeight.toString(), style: Get.theme.textTheme.titleSmall, diff --git a/lib/pages/setting/models/play_settings.dart b/lib/pages/setting/models/play_settings.dart index be087727f..c733f69f9 100644 --- a/lib/pages/setting/models/play_settings.dart +++ b/lib/pages/setting/models/play_settings.dart @@ -24,7 +24,7 @@ List get playSettings => [ settingsType: SettingsType.sw1tch, title: '弹幕开关', subtitle: '是否展示弹幕', - leading: Icon(CustomIcon.dm_settings), + leading: Icon(CustomIcons.dm_settings), setKey: SettingBoxKey.enableShowDanmaku, defaultVal: true, ), @@ -204,7 +204,7 @@ List get playSettings => [ settingsType: SettingsType.sw1tch, title: '画中画不加载弹幕', subtitle: '当弹幕开关开启时,小窗屏蔽弹幕以获得较好的体验', - leading: Icon(Icons.subtitles_off_outlined), + leading: Icon(CustomIcons.dm_off), setKey: SettingBoxKey.pipNoDanmaku, defaultVal: false, ), diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 69462ab02..424217ebb 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -1490,6 +1490,13 @@ class _VideoDetailPageVState extends State ? ugcIntroController : pgcIntroController, onSendDanmaku: videoDetailController.showShootDanmakuSheet, + canPlay: () { + if (videoDetailController.autoPlay.value) { + return true; + } + handlePlay(); + return false; + }, child: child, ); return videoDetailController.plPlayerController.darkVideoPage @@ -1627,8 +1634,8 @@ class _VideoDetailPageVState extends State icon: Icon( size: 22, enableShowDanmaku - ? CustomIcon.dm_on - : CustomIcon.dm_off, + ? CustomIcons.dm_on + : CustomIcons.dm_off, color: enableShowDanmaku ? themeData.colorScheme.secondary : themeData.colorScheme.outline, diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index b73618d53..cdf9c44e2 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -100,7 +100,7 @@ class HeaderControlState extends TripleState { @override void dispose() { - clock?.cancel(); + cancelClock(); super.dispose(); } @@ -416,7 +416,7 @@ class HeaderControlState extends TripleState { Get.back(); showSetDanmaku(); }, - leading: const Icon(CustomIcon.dm_settings, size: 20), + leading: const Icon(CustomIcons.dm_settings, size: 20), title: const Text('弹幕设置', style: titleStyle), ), ListTile( @@ -780,7 +780,7 @@ class HeaderControlState extends TripleState { Icons.done, color: theme.colorScheme.primary, ) - : const SizedBox.shrink(), + : null, ), ], ], @@ -857,7 +857,7 @@ class HeaderControlState extends TripleState { Icons.done, color: theme.colorScheme.primary, ) - : const SizedBox.shrink(), + : null, ), ], ], @@ -1819,7 +1819,7 @@ class HeaderControlState extends TripleState { Icons.done, color: theme.colorScheme.primary, ) - : const SizedBox.shrink(), + : null, ), ], ], @@ -1835,376 +1835,369 @@ class HeaderControlState extends TripleState { void startClock() { clock ??= Timer.periodic(const Duration(seconds: 1), (Timer t) { if (!mounted) { - clock?.cancel(); + cancelClock(); return; } now.value = _format.format(DateTime.now()); }); } - Widget _buildHeader(bool showFSActionItem) => AppBar( - elevation: 0, - scrolledUnderElevation: 0, - backgroundColor: Colors.transparent, - foregroundColor: Colors.white, - primary: false, - automaticallyImplyLeading: false, - toolbarHeight: showFSActionItem && isFullScreen ? 112 : null, - flexibleSpace: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(height: 11), - Row( - children: [ - SizedBox( - width: 42, - height: 34, - child: IconButton( - tooltip: '返回', - icon: const Icon( - FontAwesomeIcons.arrowLeft, - size: 15, - color: Colors.white, - ), - onPressed: () { - if (isFullScreen) { - plPlayerController.triggerFullScreen(status: false); - } else if (!horizontalScreen && !isPortrait) { - verticalScreenForTwoSeconds(); - } else { - Get.back(); - } - }, - ), - ), - if (!isFullScreen || !isPortrait) + void cancelClock() { + clock?.cancel(); + clock = null; + } + + @override + Widget build(BuildContext context) { + final showFSActionItem = + plPlayerController.showFSActionItem && isFullScreen; + return AppBar( + elevation: 0, + scrolledUnderElevation: 0, + backgroundColor: Colors.transparent, + foregroundColor: Colors.white, + primary: false, + automaticallyImplyLeading: false, + toolbarHeight: showFSActionItem ? 112 : null, + flexibleSpace: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 11), + Row( + children: [ SizedBox( width: 42, height: 34, child: IconButton( - tooltip: '返回主页', + tooltip: '返回', icon: const Icon( - FontAwesomeIcons.house, + FontAwesomeIcons.arrowLeft, size: 15, color: Colors.white, ), onPressed: () { - videoDetailCtr.plPlayerController.backToHome = true; - Get.until((route) => route.isFirst); + if (isFullScreen) { + plPlayerController.triggerFullScreen(status: false); + } else if (!horizontalScreen && !isPortrait) { + verticalScreenForTwoSeconds(); + } else { + Get.back(); + } }, ), ), - if ((introController.videoDetail.value.title != null) && - (isFullScreen || (!horizontalScreen && !isPortrait))) - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: isPortrait - ? EdgeInsets.zero - : const EdgeInsets.only(right: 10), - child: Obx( - () { - final videoDetail = introController.videoDetail.value; - final String title; - if (videoDetail.videos == 1) { - title = videoDetail.title!; - } else { - title = - videoDetail.pages - ?.firstWhereOrNull( - (e) => e.cid == videoDetailCtr.cid.value, - ) - ?.pagePart ?? - videoDetail.title!; - } - return MarqueeText( - title, - spacing: 30, - velocity: 30, + if (!isFullScreen || !isPortrait) + SizedBox( + width: 42, + height: 34, + child: IconButton( + tooltip: '返回主页', + icon: const Icon( + FontAwesomeIcons.house, + size: 15, + color: Colors.white, + ), + onPressed: () { + videoDetailCtr.plPlayerController.backToHome = true; + Get.until((route) => route.isFirst); + }, + ), + ), + if ((introController.videoDetail.value.title != null) && + (isFullScreen || (!horizontalScreen && !isPortrait))) + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: isPortrait + ? EdgeInsets.zero + : const EdgeInsets.only(right: 10), + child: Obx( + () { + final videoDetail = + introController.videoDetail.value; + final String title; + if (videoDetail.videos == 1) { + title = videoDetail.title!; + } else { + title = + videoDetail.pages + ?.firstWhereOrNull( + (e) => + e.cid == videoDetailCtr.cid.value, + ) + ?.pagePart ?? + videoDetail.title!; + } + return MarqueeText( + title, + spacing: 30, + velocity: 30, + style: const TextStyle( + color: Colors.white, + fontSize: 16, + ), + provider: provider, + ); + }, + ), + ), + if (introController.isShowOnlineTotal) + Obx( + () => Text( + '${introController.total.value}人正在看', style: const TextStyle( color: Colors.white, - fontSize: 16, + fontSize: 11, ), - provider: provider, - ); - }, - ), - ), - if (introController.isShowOnlineTotal) - Obx( - () => Text( - '${introController.total.value}人正在看', - style: const TextStyle( - color: Colors.white, - fontSize: 11, ), ), - ), - ], - ), - ) - else - const Spacer(), - // show current datetime - Obx( - () { - if ((isFullScreen || !horizontalScreen) && !isPortrait) { - startClock(); - return Text( - now.value, - style: const TextStyle( - color: Colors.white, - fontSize: 13, - ), - ); - } - clock?.cancel(); - clock = null; - return const SizedBox.shrink(); - }, - ), - if (plPlayerController.enableSponsorBlock == true) - SizedBox( - width: 42, - height: 34, - child: IconButton( - tooltip: '提交片段', - style: const ButtonStyle( - padding: WidgetStatePropertyAll(EdgeInsets.zero), - ), - onPressed: () => videoDetailCtr.onBlock(context), - icon: const Stack( - clipBehavior: Clip.none, - alignment: Alignment.center, - children: [ - Icon( - Icons.shield_outlined, - size: 19, - color: Colors.white, - ), - Icon( - Icons.play_arrow_rounded, - size: 13, - color: Colors.white, - ), ], ), - ), - ), - Obx( - () => videoDetailCtr.segmentList.isNotEmpty - ? SizedBox( - width: 42, - height: 34, - child: IconButton( - tooltip: '片段信息', - style: const ButtonStyle( - padding: WidgetStatePropertyAll(EdgeInsets.zero), - ), - onPressed: () => videoDetailCtr.showSBDetail(context), - icon: const Icon( - MdiIcons.advertisements, - size: 19, - color: Colors.white, - ), - ), - ) - : const SizedBox.shrink(), - ), - SizedBox( - width: 42, - height: 34, - child: IconButton( - tooltip: '发弹幕', - style: const ButtonStyle( - padding: WidgetStatePropertyAll(EdgeInsets.zero), - ), - onPressed: videoDetailCtr.showShootDanmakuSheet, - icon: const Icon( - Icons.comment_outlined, - size: 19, - color: Colors.white, - ), - ), - ), - SizedBox( - width: 42, - height: 34, - child: Obx( + ) + else + const Spacer(), + // show current datetime + Obx( () { - final enableShowDanmaku = - plPlayerController.enableShowDanmaku.value; - return IconButton( - tooltip: "${enableShowDanmaku ? '关闭' : '开启'}弹幕", + if ((isFullScreen || !horizontalScreen) && !isPortrait) { + startClock(); + return Text( + now.value, + style: const TextStyle( + color: Colors.white, + fontSize: 13, + ), + ); + } + cancelClock(); + return const SizedBox.shrink(); + }, + ), + if (plPlayerController.enableSponsorBlock == true) + SizedBox( + width: 42, + height: 34, + child: IconButton( + tooltip: '提交片段', style: const ButtonStyle( padding: WidgetStatePropertyAll(EdgeInsets.zero), ), - onPressed: () { - final newVal = !enableShowDanmaku; - plPlayerController.enableShowDanmaku.value = newVal; - if (!plPlayerController.tempPlayerConf) { - setting.put(SettingBoxKey.enableShowDanmaku, newVal); - } - }, - icon: Icon( - enableShowDanmaku - ? Icons.subtitles_outlined - : Icons.subtitles_off_outlined, - size: 19, - color: Colors.white, + onPressed: () => videoDetailCtr.onBlock(context), + icon: const Stack( + clipBehavior: Clip.none, + alignment: Alignment.center, + children: [ + Icon( + Icons.shield_outlined, + size: 19, + color: Colors.white, + ), + Icon( + Icons.play_arrow_rounded, + size: 13, + color: Colors.white, + ), + ], ), - ); - }, + ), + ), + Obx( + () => videoDetailCtr.segmentList.isNotEmpty + ? SizedBox( + width: 42, + height: 34, + child: IconButton( + tooltip: '片段信息', + style: const ButtonStyle( + padding: WidgetStatePropertyAll(EdgeInsets.zero), + ), + onPressed: () => videoDetailCtr.showSBDetail(context), + icon: const Icon( + MdiIcons.advertisements, + size: 19, + color: Colors.white, + ), + ), + ) + : const SizedBox.shrink(), ), - ), - if (Platform.isAndroid) SizedBox( width: 42, height: 34, child: IconButton( - tooltip: '画中画', + tooltip: '发弹幕', style: const ButtonStyle( padding: WidgetStatePropertyAll(EdgeInsets.zero), ), - onPressed: () async { - bool canUsePiP = await Floating().isPipAvailable; - plPlayerController.hiddenControls(false); - if (canUsePiP) { - if (!videoPlayerServiceHandler!.enableBackgroundPlay && - mounted) { - final theme = Theme.of(context); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Column( - children: [ - const Row( - children: [ - Icon( - Icons.check, - color: Colors.green, - ), - SizedBox(width: 10), - Text( - '画中画', - style: TextStyle( - fontSize: 15, - height: 1.5, - ), - ), - ], - ), - const SizedBox(height: 10), - const Text( - '建议开启【后台音频服务】\n' - '避免画中画没有暂停按钮', - style: TextStyle(fontSize: 12.5, height: 1.5), - ), - Row( - children: [ - TextButton( - style: ButtonStyle( - foregroundColor: WidgetStatePropertyAll( - theme.snackBarTheme.actionTextColor, - ), - ), - onPressed: () { - plPlayerController.setBackgroundPlay( - true, - ); - SmartDialog.showToast("请重新载入本页面刷新"); - }, - child: const Text('启用后台音频服务'), - ), - const SizedBox(width: 10), - TextButton( - style: ButtonStyle( - foregroundColor: WidgetStatePropertyAll( - theme.snackBarTheme.actionTextColor, - ), - ), - onPressed: () {}, - child: const Text('不启用'), - ), - ], - ), - ], - ), - duration: const Duration(seconds: 2), - showCloseIcon: true, - ), - ); - await Future.delayed(const Duration(seconds: 3)); - } - if (!context.mounted) return; - PageUtils.enterPip( - width: widget.videoDetailCtr.firstVideo.width, - height: widget.videoDetailCtr.firstVideo.height, - ); - } - }, + onPressed: videoDetailCtr.showShootDanmakuSheet, icon: const Icon( - Icons.picture_in_picture_outlined, + Icons.comment_outlined, size: 19, color: Colors.white, ), ), ), - SizedBox( - width: 42, - height: 34, - child: IconButton( - tooltip: "更多设置", - style: const ButtonStyle( - padding: WidgetStatePropertyAll(EdgeInsets.zero), - ), - onPressed: showSettingSheet, - icon: const Icon( - Icons.more_vert_outlined, - size: 19, - color: Colors.white, - ), - ), - ), - ], - ), - if (showFSActionItem && isFullScreen) - Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ SizedBox( width: 42, height: 34, child: Obx( - () => ActionItem( - expand: false, + () { + final enableShowDanmaku = + plPlayerController.enableShowDanmaku.value; + return IconButton( + tooltip: "${enableShowDanmaku ? '关闭' : '开启'}弹幕", + style: const ButtonStyle( + padding: WidgetStatePropertyAll(EdgeInsets.zero), + ), + onPressed: () { + final newVal = !enableShowDanmaku; + plPlayerController.enableShowDanmaku.value = newVal; + if (!plPlayerController.tempPlayerConf) { + setting.put(SettingBoxKey.enableShowDanmaku, newVal); + } + }, + icon: enableShowDanmaku + ? const Icon( + size: 20, + CustomIcons.dm_on, + color: Colors.white, + ) + : const Icon( + size: 20, + CustomIcons.dm_off, + color: Colors.white, + ), + ); + }, + ), + ), + if (Platform.isAndroid) + SizedBox( + width: 42, + height: 34, + child: IconButton( + tooltip: '画中画', + style: const ButtonStyle( + padding: WidgetStatePropertyAll(EdgeInsets.zero), + ), + onPressed: () async { + bool canUsePiP = await Floating().isPipAvailable; + plPlayerController.hiddenControls(false); + if (canUsePiP) { + if (context.mounted && + !videoPlayerServiceHandler!.enableBackgroundPlay) { + final theme = Theme.of(context); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Column( + children: [ + const Row( + children: [ + Icon( + Icons.check, + color: Colors.green, + ), + SizedBox(width: 10), + Text( + '画中画', + style: TextStyle( + fontSize: 15, + height: 1.5, + ), + ), + ], + ), + const SizedBox(height: 10), + const Text( + '建议开启【后台音频服务】\n' + '避免画中画没有暂停按钮', + style: TextStyle( + fontSize: 12.5, + height: 1.5, + ), + ), + Row( + children: [ + TextButton( + style: ButtonStyle( + foregroundColor: + WidgetStatePropertyAll( + theme + .snackBarTheme + .actionTextColor, + ), + ), + onPressed: () { + plPlayerController.setBackgroundPlay( + true, + ); + SmartDialog.showToast("请重新载入本页面刷新"); + }, + child: const Text('启用后台音频服务'), + ), + const SizedBox(width: 10), + TextButton( + style: ButtonStyle( + foregroundColor: + WidgetStatePropertyAll( + theme + .snackBarTheme + .actionTextColor, + ), + ), + onPressed: () {}, + child: const Text('不启用'), + ), + ], + ), + ], + ), + duration: const Duration(seconds: 2), + showCloseIcon: true, + ), + ); + await Future.delayed(const Duration(seconds: 3)); + } + if (!context.mounted) return; + PageUtils.enterPip( + width: widget.videoDetailCtr.firstVideo.width, + height: widget.videoDetailCtr.firstVideo.height, + ); + } + }, icon: const Icon( - FontAwesomeIcons.thumbsUp, + Icons.picture_in_picture_outlined, + size: 19, color: Colors.white, ), - selectIcon: const Icon( - FontAwesomeIcons.solidThumbsUp, - ), - selectStatus: introController.hasLike.value, - semanticsLabel: '点赞', - animation: tripleAnimation, - onStartTriple: () { - plPlayerController.tripling = true; - onStartTriple(); - }, - onCancelTriple: ([bool isTap = false]) { - plPlayerController - ..tripling = false - ..hideTaskControls(); - onCancelTriple(isTap); - }, + ), + ), + SizedBox( + width: 42, + height: 34, + child: IconButton( + tooltip: "更多设置", + style: const ButtonStyle( + padding: WidgetStatePropertyAll(EdgeInsets.zero), + ), + onPressed: showSettingSheet, + icon: const Icon( + Icons.more_vert_outlined, + size: 19, + color: Colors.white, ), ), ), - if (introController case UgcIntroController ugc) + ], + ), + if (showFSActionItem) + Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ SizedBox( width: 42, height: 34, @@ -2212,82 +2205,106 @@ class HeaderControlState extends TripleState { () => ActionItem( expand: false, icon: const Icon( - FontAwesomeIcons.thumbsDown, + FontAwesomeIcons.thumbsUp, color: Colors.white, ), selectIcon: const Icon( - FontAwesomeIcons.solidThumbsDown, + FontAwesomeIcons.solidThumbsUp, ), - onTap: () => ugc.handleAction(ugc.actionDislikeVideo), - selectStatus: ugc.hasDislike.value, - semanticsLabel: '点踩', + selectStatus: introController.hasLike.value, + semanticsLabel: '点赞', + animation: tripleAnimation, + onStartTriple: () { + plPlayerController.tripling = true; + onStartTriple(); + }, + onCancelTriple: ([bool isTap = false]) { + plPlayerController + ..tripling = false + ..hideTaskControls(); + onCancelTriple(isTap); + }, ), ), ), - SizedBox( - width: 42, - height: 34, - child: Obx( - () => ActionItem( + if (introController case UgcIntroController ugc) + SizedBox( + width: 42, + height: 34, + child: Obx( + () => ActionItem( + expand: false, + icon: const Icon( + FontAwesomeIcons.thumbsDown, + color: Colors.white, + ), + selectIcon: const Icon( + FontAwesomeIcons.solidThumbsDown, + ), + onTap: () => ugc.handleAction(ugc.actionDislikeVideo), + selectStatus: ugc.hasDislike.value, + semanticsLabel: '点踩', + ), + ), + ), + SizedBox( + width: 42, + height: 34, + child: Obx( + () => ActionItem( + expand: false, + animation: tripleAnimation, + icon: const Icon( + FontAwesomeIcons.b, + color: Colors.white, + ), + selectIcon: const Icon(FontAwesomeIcons.b), + onTap: introController.actionCoinVideo, + selectStatus: introController.hasCoin, + semanticsLabel: '投币', + ), + ), + ), + SizedBox( + width: 42, + height: 34, + child: Obx( + () => ActionItem( + expand: false, + animation: tripleAnimation, + icon: const Icon( + FontAwesomeIcons.star, + color: Colors.white, + ), + selectIcon: const Icon(FontAwesomeIcons.solidStar), + onTap: () => introController.showFavBottomSheet(context), + onLongPress: () => introController.showFavBottomSheet( + context, + isLongPress: true, + ), + selectStatus: introController.hasFav.value, + semanticsLabel: '收藏', + ), + ), + ), + SizedBox( + width: 42, + height: 34, + child: ActionItem( expand: false, - animation: tripleAnimation, icon: const Icon( - FontAwesomeIcons.b, + FontAwesomeIcons.shareFromSquare, color: Colors.white, ), - selectIcon: const Icon(FontAwesomeIcons.b), - onTap: introController.actionCoinVideo, - selectStatus: introController.hasCoin, - semanticsLabel: '投币', + onTap: () => introController.actionShareVideo(context), + semanticsLabel: '分享', ), ), - ), - SizedBox( - width: 42, - height: 34, - child: Obx( - () => ActionItem( - expand: false, - animation: tripleAnimation, - icon: const Icon( - FontAwesomeIcons.star, - color: Colors.white, - ), - selectIcon: const Icon(FontAwesomeIcons.solidStar), - onTap: () => introController.showFavBottomSheet(context), - onLongPress: () => introController.showFavBottomSheet( - context, - isLongPress: true, - ), - selectStatus: introController.hasFav.value, - semanticsLabel: '收藏', - ), - ), - ), - SizedBox( - width: 42, - height: 34, - child: ActionItem( - expand: false, - icon: const Icon( - FontAwesomeIcons.shareFromSquare, - color: Colors.white, - ), - onTap: () => introController.actionShareVideo(context), - semanticsLabel: '分享', - ), - ), - ], - ), - ], - ), - ); - - @override - Widget build(BuildContext context) { - return plPlayerController.showFSActionItem - ? Obx(() => _buildHeader(true)) - : _buildHeader(false); + ], + ), + ], + ), + ); } } diff --git a/lib/pages/video/widgets/player_focus.dart b/lib/pages/video/widgets/player_focus.dart index deb1a29aa..fd7e9adc7 100644 --- a/lib/pages/video/widgets/player_focus.dart +++ b/lib/pages/video/widgets/player_focus.dart @@ -19,12 +19,14 @@ class PlayerFocus extends StatelessWidget { required this.plPlayerController, this.introController, required this.onSendDanmaku, + this.canPlay, }); final Widget child; final PlPlayerController plPlayerController; final CommonIntroController? introController; final VoidCallback onSendDanmaku; + final bool Function()? canPlay; static bool _shouldHandled(KeyEvent event) { return event.logicalKey == LogicalKeyboardKey.tab || @@ -57,8 +59,10 @@ class PlayerFocus extends StatelessWidget { if (event is KeyDownEvent) { switch (key) { case LogicalKeyboardKey.space: - if (hasPlayer) { - plPlayerController.onDoubleTapCenter(); + if (plPlayerController.isLive || canPlay!()) { + if (hasPlayer) { + plPlayerController.onDoubleTapCenter(); + } } return true; diff --git a/lib/utils/reply_utils.dart b/lib/utils/reply_utils.dart index cbf98ee04..7b58d21b0 100644 --- a/lib/utils/reply_utils.dart +++ b/lib/utils/reply_utils.dart @@ -100,36 +100,39 @@ class ReplyUtils { } void showReplyCheckResult(String message, {bool isBan = false}) { Get.dialog( + barrierDismissible: isManual, AlertDialog( title: const Text('评论检查结果'), content: SelectableText(message), - actions: isBan - ? [ - TextButton( - onPressed: () { - Get.back(); - String? uri; - switch (type) { - case 1: - uri = IdUtils.av2bv(oid); - case 17: - uri = 'https://www.bilibili.com/opus/$oid'; - } - if (uri != null) { - Utils.copyText(uri); - } - Get.toNamed( - '/webview', - parameters: { - 'url': - 'https://www.bilibili.com/h5/comment/appeal?native.theme=2&night=${Get.isDarkMode ? 1 : 0}', - }, - ); - }, - child: const Text('申诉'), - ), - ] - : null, + actions: [ + TextButton( + onPressed: () { + Get.back(); + String? uri; + switch (type) { + case 1: + uri = IdUtils.av2bv(oid); + case 17: + uri = 'https://www.bilibili.com/opus/$oid'; + } + if (uri != null) { + Utils.copyText(uri); + } + Get.toNamed( + '/webview', + parameters: { + 'url': + 'https://www.bilibili.com/h5/comment/appeal?native.theme=2&night=${Get.isDarkMode ? 1 : 0}', + }, + ); + }, + child: const Text('申诉'), + ), + TextButton( + onPressed: Get.back, + child: const Text('关闭'), + ), + ], ), ); } diff --git a/lib/utils/request_utils.dart b/lib/utils/request_utils.dart index 7c5b97d08..d982c2cd0 100644 --- a/lib/utils/request_utils.dart +++ b/lib/utils/request_utils.dart @@ -285,7 +285,7 @@ abstract class RequestUtils { static Future insertCreatedDyn(dynamic id) async { try { if (id != null) { - await Future.delayed(const Duration(milliseconds: 200)); + await Future.delayed(const Duration(milliseconds: 450)); var res = await DynamicsHttp.dynamicDetail(id: id); if (res.isSuccess) { final ctr = Get.find(tag: 'all'); @@ -317,31 +317,33 @@ abstract class RequestUtils { await Future.delayed(const Duration(seconds: 5)); } var res = await DynamicsHttp.dynamicDetail(id: id, clearCookie: true); - bool isBan = !res.isSuccess; Get.dialog( + barrierDismissible: isManual, AlertDialog( title: const Text('动态检查结果'), content: SelectableText( - '${!isBan ? '无账号状态下找到了你的动态,动态正常!' : '你的动态被shadow ban(仅自己可见)!'}${dynText != null ? ' \n\n动态内容: $dynText' : ''}', + '${res.isSuccess ? '无账号状态下找到了你的动态,动态正常!' : '你的动态被shadow ban(仅自己可见)!'}${dynText != null ? ' \n\n动态内容: $dynText' : ''}', ), - actions: isBan - ? [ - TextButton( - onPressed: () { - Get.back(); - Utils.copyText('https://www.bilibili.com/opus/$id'); - Get.toNamed( - '/webview', - parameters: { - 'url': - 'https://www.bilibili.com/h5/comment/appeal?native.theme=2&night=${Get.isDarkMode ? 1 : 0}', - }, - ); - }, - child: const Text('申诉'), - ), - ] - : null, + actions: [ + TextButton( + onPressed: () { + Get.back(); + Utils.copyText('https://www.bilibili.com/opus/$id'); + Get.toNamed( + '/webview', + parameters: { + 'url': + 'https://www.bilibili.com/h5/comment/appeal?native.theme=2&night=${Get.isDarkMode ? 1 : 0}', + }, + ); + }, + child: const Text('申诉'), + ), + TextButton( + onPressed: Get.back, + child: const Text('关闭'), + ), + ], ), ); }