From d5aa24813f2c4e0305ca68b336bd1436965a7af8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 14 Dec 2025 16:13:15 +0000 Subject: [PATCH 1/5] feat: Add "More Options" button to live room UI This commit introduces a "More Options" button to the live room UI, which opens a bottom sheet containing various actions. The buttons previously visible on the overlay (e.g., "Send Danmaku", "Audio Only", "PiP") have been successfully moved into this new sheet. Additionally, the "more" functionality is unified by replacing the AppBar's PopupMenuButton with an icon that also triggers this same bottom sheet, creating a more consistent user experience. Finally, the D-pad menu button is integrated to open the sheet via the PlayerFocus widget. --- lib/pages/live_room/view.dart | 100 +------- .../live_room/widgets/header_control.dart | 241 ++++++++++++------ 2 files changed, 178 insertions(+), 163 deletions(-) diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index b0310754b5..f25ac6760e 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -199,6 +199,9 @@ class _LiveRoomPageState extends State child = PlayerFocus( plPlayerController: plPlayerController, onSendDanmaku: _liveRoomController.onSendDanmaku, + onShowMenu: () => + (_liveRoomController.headerKey.currentState as LiveHeaderControlState?) + ?.showSettingSheet(), child: child, ); } @@ -559,95 +562,14 @@ class _LiveRoomPageState extends State // onPressed: _liveRoomController.queryLiveUrl, // icon: const Icon(Icons.refresh, size: 20), // ), - PopupMenuButton( - icon: const Icon(Icons.more_vert, size: 20), - itemBuilder: (BuildContext context) { - final liveUrl = - 'https://live.bilibili.com/${_liveRoomController.roomId}'; - return [ - PopupMenuItem( - onTap: () => Utils.copyText(liveUrl), - child: Row( - spacing: 10, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.copy, - size: 19, - color: color, - ), - const Text('复制链接'), - ], - ), - ), - if (Utils.isMobile) - PopupMenuItem( - onTap: () => Utils.shareText(liveUrl), - child: Row( - spacing: 10, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.share, - size: 19, - color: color, - ), - const Text('分享直播间'), - ], - ), - ), - PopupMenuItem( - onTap: () => PageUtils.inAppWebview(liveUrl, off: true), - child: Row( - spacing: 10, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.open_in_browser, - size: 19, - color: color, - ), - const Text('浏览器打开'), - ], - ), - ), - if (_liveRoomController.roomInfoH5.value != null) - PopupMenuItem( - onTap: () { - try { - RoomInfoH5Data roomInfo = - _liveRoomController.roomInfoH5.value!; - PageUtils.pmShare( - this.context, - content: { - "cover": roomInfo.roomInfo!.cover!, - "sourceID": _liveRoomController.roomId.toString(), - "title": roomInfo.roomInfo!.title!, - "url": liveUrl, - "authorID": roomInfo.roomInfo!.uid.toString(), - "source": "直播", - "desc": roomInfo.roomInfo!.title!, - "author": roomInfo.anchorInfo!.baseInfo!.uname, - }, - ); - } catch (e) { - SmartDialog.showToast(e.toString()); - } - }, - child: Row( - spacing: 10, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.forward_to_inbox, - size: 19, - color: color, - ), - const Text('分享至消息'), - ], - ), - ), - ]; + Builder( + builder: (context) { + return IconButton( + icon: const Icon(Icons.more_vert, size: 20), + onPressed: () => (_liveRoomController.headerKey.currentState + as LiveHeaderControlState?) + ?.showSettingSheet(), + ); }, ), ], diff --git a/lib/pages/live_room/widgets/header_control.dart b/lib/pages/live_room/widgets/header_control.dart index f311968444..05fd86dd99 100644 --- a/lib/pages/live_room/widgets/header_control.dart +++ b/lib/pages/live_room/widgets/header_control.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:PiliPlus/common/widgets/marquee.dart'; +import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart'; import 'package:PiliPlus/pages/live_room/controller.dart'; import 'package:PiliPlus/pages/video/widgets/header_control.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart'; @@ -9,6 +10,7 @@ import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; @@ -34,11 +36,171 @@ class LiveHeaderControl extends StatefulWidget { final LiveRoomController liveController; @override - State createState() => _LiveHeaderControlState(); + State createState() => LiveHeaderControlState(); } -class _LiveHeaderControlState extends State +class LiveHeaderControlState extends State with TimeBatteryMixin { + void showSettingSheet() { + final liveUrl = 'https://live.bilibili.com/${widget.liveController.roomId}'; + PageUtils.showVideoBottomSheet( + context, + isFullScreen: () => isFullScreen, + child: Material( + color: Colors.transparent, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 10), + child: Wrap( + spacing: 12, + runSpacing: 10, + children: [ + ComBtn( + height: 30, + tooltip: '发弹幕', + icon: const Icon( + size: 18, + Icons.comment_outlined, + color: Colors.white, + ), + onTap: widget.onSendDanmaku, + ), + Obx( + () { + final onlyPlayAudio = plPlayerController.onlyPlayAudio.value; + return ComBtn( + height: 30, + tooltip: '仅播放音频', + onTap: () { + plPlayerController.onlyPlayAudio.value = !onlyPlayAudio; + widget.onPlayAudio(); + }, + icon: onlyPlayAudio + ? const Icon( + size: 18, + MdiIcons.musicCircle, + color: Colors.white, + ) + : const Icon( + size: 18, + MdiIcons.musicCircleOutline, + color: Colors.white, + ), + ); + }, + ), + if (Platform.isAndroid || (Utils.isDesktop && !isFullScreen)) + ComBtn( + height: 30, + tooltip: '画中画', + onTap: () async { + if (Utils.isDesktop) { + plPlayerController.toggleDesktopPip(); + return; + } + if (await Floating().isPipAvailable) { + plPlayerController + ..showControls.value = false + ..enterPip(); + } + }, + icon: const Icon( + size: 18, + Icons.picture_in_picture_outlined, + color: Colors.white, + ), + ), + ComBtn( + height: 30, + tooltip: '定时关闭', + onTap: () => PageUtils.scheduleExit(context, isFullScreen, true), + icon: const Icon( + size: 18, + Icons.schedule, + color: Colors.white, + ), + ), + ComBtn( + height: 30, + tooltip: '播放信息', + onTap: () => HeaderControlState.showPlayerInfo( + context, + plPlayerController: plPlayerController, + ), + icon: const Icon( + size: 18, + Icons.info_outline, + color: Colors.white, + ), + ), + ComBtn( + height: 30, + tooltip: '复制链接', + onTap: () => Utils.copyText(liveUrl), + icon: const Icon( + size: 18, + Icons.copy, + color: Colors.white, + ), + ), + if (Utils.isMobile) + ComBtn( + height: 30, + tooltip: '分享直播间', + onTap: () => Utils.shareText(liveUrl), + icon: const Icon( + size: 18, + Icons.share, + color: Colors.white, + ), + ), + ComBtn( + height: 30, + tooltip: '浏览器打开', + onTap: () => PageUtils.inAppWebview(liveUrl, off: true), + icon: const Icon( + size: 18, + Icons.open_in_browser, + color: Colors.white, + ), + ), + if (widget.liveController.roomInfoH5.value != null) + ComBtn( + height: 30, + tooltip: '分享至消息', + onTap: () { + try { + RoomInfoH5Data roomInfo = + widget.liveController.roomInfoH5.value!; + PageUtils.pmShare( + context, + content: { + "cover": roomInfo.roomInfo!.cover!, + "sourceID": widget.liveController.roomId.toString(), + "title": roomInfo.roomInfo!.title!, + "url": liveUrl, + "authorID": roomInfo.roomInfo!.uid.toString(), + "source": "直播", + "desc": roomInfo.roomInfo!.title!, + "author": roomInfo.anchorInfo!.baseInfo!.uname, + }, + ); + } catch (e) { + SmartDialog.showToast(e.toString()); + } + }, + icon: const Icon( + size: 18, + Icons.forward_to_inbox, + color: Colors.white, + ), + ), + ], + ), + ), + ), + ); + } + @override late final plPlayerController = widget.plPlayerController; @@ -123,79 +285,10 @@ class _LiveHeaderControlState extends State const SizedBox(width: 10), ComBtn( height: 30, - tooltip: '发弹幕', - icon: const Icon( - size: 18, - Icons.comment_outlined, - color: Colors.white, - ), - onTap: widget.onSendDanmaku, - ), - Obx( - () { - final onlyPlayAudio = plPlayerController.onlyPlayAudio.value; - return ComBtn( - height: 30, - tooltip: '仅播放音频', - onTap: () { - plPlayerController.onlyPlayAudio.value = !onlyPlayAudio; - widget.onPlayAudio(); - }, - icon: onlyPlayAudio - ? const Icon( - size: 18, - MdiIcons.musicCircle, - color: Colors.white, - ) - : const Icon( - size: 18, - MdiIcons.musicCircleOutline, - color: Colors.white, - ), - ); - }, - ), - if (Platform.isAndroid || (Utils.isDesktop && !isFullScreen)) - ComBtn( - height: 30, - tooltip: '画中画', - onTap: () async { - if (Utils.isDesktop) { - plPlayerController.toggleDesktopPip(); - return; - } - if (await Floating().isPipAvailable) { - plPlayerController - ..showControls.value = false - ..enterPip(); - } - }, - icon: const Icon( - size: 18, - Icons.picture_in_picture_outlined, - color: Colors.white, - ), - ), - ComBtn( - height: 30, - tooltip: '定时关闭', - onTap: () => PageUtils.scheduleExit(context, isFullScreen, true), - icon: const Icon( - size: 18, - Icons.schedule, - color: Colors.white, - ), - ), - ComBtn( - height: 30, - tooltip: '播放信息', - onTap: () => HeaderControlState.showPlayerInfo( - context, - plPlayerController: plPlayerController, - ), + tooltip: '更多', + onTap: showSettingSheet, icon: const Icon( - size: 18, - Icons.info_outline, + Icons.more_vert_outlined, color: Colors.white, ), ), From bfbce50695e33713eafe3f17899d4ec6fe0245f3 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 14 Dec 2025 16:33:36 +0000 Subject: [PATCH 2/5] feat: Add "More Options" button to live room UI This commit introduces a "More Options" button to the live room UI, which opens a bottom sheet containing various actions. The buttons previously visible on the overlay (e.g., "Send Danmaku", "Audio Only", "PiP") have been successfully moved into this new sheet. Additionally, the "more" functionality is unified by replacing the AppBar's PopupMenuButton with an icon that also triggers this same bottom sheet, creating a more consistent user experience. Finally, the D-pad menu button is integrated to open the sheet via the PlayerFocus widget. --- lib/pages/live_room/view.dart | 104 ++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 10 deletions(-) diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index f25ac6760e..11ab19de73 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -199,9 +199,12 @@ class _LiveRoomPageState extends State child = PlayerFocus( plPlayerController: plPlayerController, onSendDanmaku: _liveRoomController.onSendDanmaku, - onShowMenu: () => + onShowMenu: () { + if (isFullScreen) { (_liveRoomController.headerKey.currentState as LiveHeaderControlState?) - ?.showSettingSheet(), + ?.showSettingSheet(); + } + }, child: child, ); } @@ -562,14 +565,95 @@ class _LiveRoomPageState extends State // onPressed: _liveRoomController.queryLiveUrl, // icon: const Icon(Icons.refresh, size: 20), // ), - Builder( - builder: (context) { - return IconButton( - icon: const Icon(Icons.more_vert, size: 20), - onPressed: () => (_liveRoomController.headerKey.currentState - as LiveHeaderControlState?) - ?.showSettingSheet(), - ); + PopupMenuButton( + icon: const Icon(Icons.more_vert, size: 20), + itemBuilder: (BuildContext context) { + final liveUrl = + 'https://live.bilibili.com/${_liveRoomController.roomId}'; + return [ + PopupMenuItem( + onTap: () => Utils.copyText(liveUrl), + child: Row( + spacing: 10, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.copy, + size: 19, + color: color, + ), + const Text('复制链接'), + ], + ), + ), + if (Utils.isMobile) + PopupMenuItem( + onTap: () => Utils.shareText(liveUrl), + child: Row( + spacing: 10, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.share, + size: 19, + color: color, + ), + const Text('分享直播间'), + ], + ), + ), + PopupMenuItem( + onTap: () => PageUtils.inAppWebview(liveUrl, off: true), + child: Row( + spacing: 10, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.open_in_browser, + size: 19, + color: color, + ), + const Text('浏览器打开'), + ], + ), + ), + if (_liveRoomController.roomInfoH5.value != null) + PopupMenuItem( + onTap: () { + try { + RoomInfoH5Data roomInfo = + _liveRoomController.roomInfoH5.value!; + PageUtils.pmShare( + this.context, + content: { + "cover": roomInfo.roomInfo!.cover!, + "sourceID": _liveRoomController.roomId.toString(), + "title": roomInfo.roomInfo!.title!, + "url": liveUrl, + "authorID": roomInfo.roomInfo!.uid.toString(), + "source": "直播", + "desc": roomInfo.roomInfo!.title!, + "author": roomInfo.anchorInfo!.baseInfo!.uname, + }, + ); + } catch (e) { + SmartDialog.showToast(e.toString()); + } + }, + child: Row( + spacing: 10, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.forward_to_inbox, + size: 19, + color: color, + ), + const Text('分享至消息'), + ], + ), + ), + ]; }, ), ], From 3a877c94eac31f0d60dbd1811738dd6c489a3c53 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 14 Dec 2025 16:38:02 +0000 Subject: [PATCH 3/5] feat: Add D-pad support for "More Options" menu This commit adds D-pad support for the "More Options" menu in the fullscreen live player. - The `ComBtn` widget is now focusable, providing visual feedback for D-pad navigation. - The first button in the "More Options" menu is autofocused when the menu is opened. --- lib/pages/live_room/widgets/header_control.dart | 2 +- lib/plugin/pl_player/widgets/common_btn.dart | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/pages/live_room/widgets/header_control.dart b/lib/pages/live_room/widgets/header_control.dart index 05fd86dd99..6c7c2a685c 100644 --- a/lib/pages/live_room/widgets/header_control.dart +++ b/lib/pages/live_room/widgets/header_control.dart @@ -57,6 +57,7 @@ class LiveHeaderControlState extends State ComBtn( height: 30, tooltip: '发弹幕', + autofocus: true, icon: const Icon( size: 18, Icons.comment_outlined, @@ -221,7 +222,6 @@ class LiveHeaderControlState extends State Widget child; child = Obx( () => MarqueeText( - key: titleKey, liveController.title.value, spacing: 30, velocity: 30, diff --git a/lib/plugin/pl_player/widgets/common_btn.dart b/lib/plugin/pl_player/widgets/common_btn.dart index e56ee7ce13..8d742f6dbe 100644 --- a/lib/plugin/pl_player/widgets/common_btn.dart +++ b/lib/plugin/pl_player/widgets/common_btn.dart @@ -4,20 +4,20 @@ class ComBtn extends StatelessWidget { final Widget icon; final VoidCallback? onTap; final VoidCallback? onLongPress; - final VoidCallback? onSecondaryTap; final double width; final double height; final String? tooltip; + final bool autofocus; const ComBtn({ super.key, required this.icon, this.onTap, this.onLongPress, - this.onSecondaryTap, this.width = 34, this.height = 34, this.tooltip, + this.autofocus = false, }); @override @@ -25,12 +25,11 @@ class ComBtn extends StatelessWidget { final child = SizedBox( width: width, height: height, - child: GestureDetector( + child: InkWell( onTap: onTap, onLongPress: onLongPress, - onSecondaryTap: onSecondaryTap, - behavior: HitTestBehavior.opaque, - child: icon, + autofocus: autofocus, + child: Center(child: icon), ), ); if (tooltip != null) { From bdf9f0a8b1141bf11aa7ad03a0782b1d4daf2f20 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 14 Dec 2025 16:43:55 +0000 Subject: [PATCH 4/5] fix: Re-add onSecondaryTap to ComBtn to fix build This commit re-adds the `onSecondaryTap` parameter to the `ComBtn` widget. This parameter was accidentally removed in a previous commit, which caused the CI build to fail. --- lib/plugin/pl_player/widgets/common_btn.dart | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/plugin/pl_player/widgets/common_btn.dart b/lib/plugin/pl_player/widgets/common_btn.dart index 8d742f6dbe..103bdd76ed 100644 --- a/lib/plugin/pl_player/widgets/common_btn.dart +++ b/lib/plugin/pl_player/widgets/common_btn.dart @@ -4,6 +4,7 @@ class ComBtn extends StatelessWidget { final Widget icon; final VoidCallback? onTap; final VoidCallback? onLongPress; + final VoidCallback? onSecondaryTap; final double width; final double height; final String? tooltip; @@ -14,6 +15,7 @@ class ComBtn extends StatelessWidget { required this.icon, this.onTap, this.onLongPress, + this.onSecondaryTap, this.width = 34, this.height = 34, this.tooltip, @@ -25,11 +27,14 @@ class ComBtn extends StatelessWidget { final child = SizedBox( width: width, height: height, - child: InkWell( - onTap: onTap, - onLongPress: onLongPress, - autofocus: autofocus, - child: Center(child: icon), + child: GestureDetector( + onSecondaryTap: onSecondaryTap, + child: InkWell( + onTap: onTap, + onLongPress: onLongPress, + autofocus: autofocus, + child: Center(child: icon), + ), ), ); if (tooltip != null) { From 95113454393f512117f7d13da99df5d02b1c8c65 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 14 Dec 2025 17:07:09 +0000 Subject: [PATCH 5/5] feat: Move quality and other buttons to "More Options" menu This commit moves the quality button and its peer buttons from the bottom control bar to the "More Options" menu in the fullscreen live player. This further consolidates the controls and cleans up the UI. --- .../live_room/widgets/bottom_control.dart | 130 ---------------- .../live_room/widgets/header_control.dart | 140 ++++++++++++++++++ 2 files changed, 140 insertions(+), 130 deletions(-) diff --git a/lib/pages/live_room/widgets/bottom_control.dart b/lib/pages/live_room/widgets/bottom_control.dart index f510270c0c..f902ae2b02 100644 --- a/lib/pages/live_room/widgets/bottom_control.dart +++ b/lib/pages/live_room/widgets/bottom_control.dart @@ -61,136 +61,6 @@ class _BottomControlState extends State with HeaderMixin { onTap: widget.onRefresh, ), const Spacer(), - ComBtn( - height: 30, - tooltip: '屏蔽', - icon: const Icon( - size: 18, - Icons.block, - color: Colors.white, - ), - onTap: () { - if (liveRoomCtr.isLogin) { - Get.toNamed( - '/liveDmBlockPage', - parameters: { - 'roomId': liveRoomCtr.roomId.toString(), - }, - ); - } else { - SmartDialog.showToast('账号未登录'); - } - }, - ), - const SizedBox(width: 3), - Obx( - () { - final enableShowLiveDanmaku = - plPlayerController.enableShowDanmaku.value; - return ComBtn( - height: 30, - tooltip: "${enableShowLiveDanmaku ? '关闭' : '开启'}弹幕", - icon: enableShowLiveDanmaku - ? const Icon( - size: 18, - CustomIcons.dm_on, - color: Colors.white, - ) - : const Icon( - size: 18, - CustomIcons.dm_off, - color: Colors.white, - ), - onTap: () { - final newVal = !enableShowLiveDanmaku; - plPlayerController.enableShowDanmaku.value = newVal; - if (!plPlayerController.tempPlayerConf) { - GStorage.setting.put( - SettingBoxKey.enableShowLiveDanmaku, - newVal, - ); - } - }, - ); - }, - ), - ComBtn( - height: 30, - tooltip: '弹幕设置', - icon: const Icon( - size: 18, - CustomIcons.dm_settings, - color: Colors.white, - ), - onTap: () => showSetDanmaku(isLive: true), - ), - Obx( - () => PopupMenuButton( - tooltip: '画面比例', - initialValue: plPlayerController.videoFit.value, - color: Colors.black.withValues(alpha: 0.8), - itemBuilder: (context) { - return VideoFitType.values - .map( - (boxFit) => PopupMenuItem( - height: 35, - padding: const EdgeInsets.only(left: 30), - value: boxFit, - onTap: () => plPlayerController.toggleVideoFit(boxFit), - child: Text( - boxFit.desc, - style: const TextStyle( - color: Colors.white, - fontSize: 13, - ), - ), - ), - ) - .toList(); - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10), - child: Text( - plPlayerController.videoFit.value.desc, - style: const TextStyle(color: Colors.white, fontSize: 13), - ), - ), - ), - ), - Obx( - () => PopupMenuButton( - tooltip: '画质', - padding: EdgeInsets.zero, - initialValue: liveRoomCtr.currentQn, - color: Colors.black.withValues(alpha: 0.8), - itemBuilder: (context) { - return liveRoomCtr.acceptQnList - .map( - (e) => PopupMenuItem( - height: 35, - padding: const EdgeInsets.only(left: 30), - value: e.code, - onTap: () => liveRoomCtr.changeQn(e.code), - child: Text( - e.desc, - style: const TextStyle( - color: Colors.white, - fontSize: 13, - ), - ), - ), - ) - .toList(); - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10), - child: Text( - liveRoomCtr.currentQnDesc.value, - style: const TextStyle(color: Colors.white, fontSize: 13), - ), - ), - ), - ), if (!plPlayerController.isDesktopPip) ComBtn( height: 30, diff --git a/lib/pages/live_room/widgets/header_control.dart b/lib/pages/live_room/widgets/header_control.dart index 6c7c2a685c..747f25a197 100644 --- a/lib/pages/live_room/widgets/header_control.dart +++ b/lib/pages/live_room/widgets/header_control.dart @@ -1,12 +1,16 @@ import 'dart:io'; +import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/marquee.dart'; import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart'; import 'package:PiliPlus/pages/live_room/controller.dart'; import 'package:PiliPlus/pages/video/widgets/header_control.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart'; +import 'package:PiliPlus/plugin/pl_player/models/video_fit_type.dart'; import 'package:PiliPlus/plugin/pl_player/widgets/common_btn.dart'; import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/storage.dart'; +import 'package:PiliPlus/utils/storage_key.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; @@ -195,6 +199,142 @@ class LiveHeaderControlState extends State color: Colors.white, ), ), + ComBtn( + height: 30, + tooltip: '屏蔽', + icon: const Icon( + size: 18, + Icons.block, + color: Colors.white, + ), + onTap: () { + if (widget.liveController.isLogin) { + Get.toNamed( + '/liveDmBlockPage', + parameters: { + 'roomId': widget.liveController.roomId.toString(), + }, + ); + } else { + SmartDialog.showToast('账号未登录'); + } + }, + ), + Obx( + () { + final enableShowLiveDanmaku = + plPlayerController.enableShowDanmaku.value; + return ComBtn( + height: 30, + tooltip: "${enableShowLiveDanmaku ? '关闭' : '开启'}弹幕", + icon: enableShowLiveDanmaku + ? const Icon( + size: 18, + CustomIcons.dm_on, + color: Colors.white, + ) + : const Icon( + size: 18, + CustomIcons.dm_off, + color: Colors.white, + ), + onTap: () { + final newVal = !enableShowLiveDanmaku; + plPlayerController.enableShowDanmaku.value = newVal; + if (!plPlayerController.tempPlayerConf) { + GStorage.setting.put( + SettingBoxKey.enableShowLiveDanmaku, + newVal, + ); + } + }, + ); + }, + ), + ComBtn( + height: 30, + tooltip: '弹幕设置', + icon: const Icon( + size: 18, + CustomIcons.dm_settings, + color: Colors.white, + ), + onTap: () => (context as Element) + .findAncestorStateOfType>() + ?.setState(() { + (widget.liveController.headerKey.currentContext as Element) + .findAncestorStateOfType() + ?.showSetDanmaku(isLive: true); + }), + ), + Obx( + () => PopupMenuButton( + tooltip: '画面比例', + initialValue: plPlayerController.videoFit.value, + color: Colors.black.withValues(alpha: 0.8), + itemBuilder: (context) { + return VideoFitType.values + .map( + (boxFit) => PopupMenuItem( + height: 35, + padding: const EdgeInsets.only(left: 30), + value: boxFit, + onTap: () => + plPlayerController.toggleVideoFit(boxFit), + child: Text( + boxFit.desc, + style: const TextStyle( + color: Colors.white, + fontSize: 13, + ), + ), + ), + ) + .toList(); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Text( + plPlayerController.videoFit.value.desc, + style: const TextStyle(color: Colors.white, fontSize: 13), + ), + ), + ), + ), + Obx( + () => PopupMenuButton( + tooltip: '画质', + padding: EdgeInsets.zero, + initialValue: widget.liveController.currentQn, + color: Colors.black.withValues(alpha: 0.8), + itemBuilder: (context) { + return widget.liveController.acceptQnList + .map( + (e) => PopupMenuItem( + height: 35, + padding: const EdgeInsets.only(left: 30), + value: e.code, + onTap: () => widget.liveController.changeQn(e.code), + child: Text( + e.desc, + style: const TextStyle( + color: Colors.white, + fontSize: 13, + ), + ), + ), + ) + .toList(); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Text( + widget.liveController.currentQnDesc.value, + style: const TextStyle(color: Colors.white, fontSize: 13), + ), + ), + ), + ), ], ), ),