From 3fae4ef63200f9977ec4a5ec7bfa9a9c411c9e52 Mon Sep 17 00:00:00 2001 From: dom Date: Sat, 13 Jun 2026 10:17:35 +0800 Subject: [PATCH] opt ui Signed-off-by: dom --- lib/pages/live_room/controller.dart | 29 ++-- lib/pages/live_room/view.dart | 88 +++++------ .../live_room/widgets/bottom_control.dart | 3 + .../live_room/widgets/header_control.dart | 139 +++++++++--------- lib/pages/video/controller.dart | 53 +++---- lib/pages/video/send_danmaku/view.dart | 8 +- lib/pages/video/view.dart | 28 ++-- lib/pages/video/widgets/header_mixin.dart | 24 ++- 8 files changed, 177 insertions(+), 195 deletions(-) diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index cd773ff9a..2e42b4dda 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -632,19 +632,22 @@ class LiveRoomController extends GetxController { PublishRoute( barrierColor: Colors.transparent, pageBuilder: (context, animation, secondaryAnimation) { - return LiveSendDmPanel( - fromEmote: fromEmote, - liveRoomController: this, - items: savedDanmaku, - autofocus: !fromEmote, - onSave: (msg) { - if (msg.isEmpty) { - savedDanmaku?.clear(); - savedDanmaku = null; - } else { - savedDanmaku = msg.toList(); - } - }, + return Theme( + data: ThemeUtils.darkTheme, + child: LiveSendDmPanel( + fromEmote: fromEmote, + liveRoomController: this, + items: savedDanmaku, + autofocus: !fromEmote, + onSave: (msg) { + if (msg.isEmpty) { + savedDanmaku?.clear(); + savedDanmaku = null; + } else { + savedDanmaku = msg.toList(); + } + }, + ), ); }, transitionDuration: fromEmote diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index b1d6eeac3..d931cbf71 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -48,6 +48,7 @@ import 'package:PiliPlus/utils/share_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:cached_network_image_ce/cached_network_image.dart'; import 'package:canvas_danmaku/danmaku_screen.dart'; @@ -57,6 +58,8 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:screen_brightness_platform_interface/screen_brightness_platform_interface.dart'; +const baseWhite = Color(0xFFEEEEEE); + class LiveRoomPage extends StatefulWidget { const LiveRoomPage({super.key}); @@ -233,7 +236,10 @@ class _LiveRoomPageState extends State child: child, ); } - return child; + return Theme( + data: ThemeUtils.darkTheme, + child: child, + ); } Widget videoPlayerPanel( @@ -541,7 +547,6 @@ class _LiveRoomPageState extends State } PreferredSizeWidget _buildAppBar(bool isFullScreen) { - final color = Theme.of(context).colorScheme.onSurfaceVariant; return AppBar( primary: !plPlayerController.removeSafeArea, toolbarHeight: isFullScreen ? 0 : null, @@ -563,7 +568,7 @@ class _LiveRoomPageState extends State Get.toNamed('/member?mid=${roomInfoH5.roomInfo?.uid}'), child: Row( spacing: 10, - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ NetworkImgLayer( width: 34, @@ -623,47 +628,35 @@ class _LiveRoomPageState extends State return [ PopupMenuItem( onTap: () => Utils.copyText(liveUrl), - child: Row( + child: const Row( spacing: 10, - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ - Icon( - Icons.copy, - size: 19, - color: color, - ), - const Text('复制链接'), + Icon(Icons.copy, size: 19), + Text('复制链接'), ], ), ), if (PlatformUtils.isMobile) PopupMenuItem( onTap: () => ShareUtils.shareText(liveUrl), - child: Row( + child: const Row( spacing: 10, - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ - Icon( - Icons.share, - size: 19, - color: color, - ), - const Text('分享直播间'), + Icon(Icons.share, size: 19), + Text('分享直播间'), ], ), ), PopupMenuItem( onTap: () => PageUtils.inAppWebview(liveUrl, off: true), - child: Row( + child: const Row( spacing: 10, - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ - Icon( - Icons.open_in_browser, - size: 19, - color: color, - ), - const Text('浏览器打开'), + Icon(Icons.open_in_browser, size: 19), + Text('浏览器打开'), ], ), ), @@ -690,16 +683,12 @@ class _LiveRoomPageState extends State SmartDialog.showToast(e.toString()); } }, - child: Row( + child: const Row( spacing: 10, - mainAxisSize: MainAxisSize.min, + mainAxisSize: .min, children: [ - Icon( - Icons.forward_to_inbox, - size: 19, - color: color, - ), - const Text('分享至消息'), + Icon(Icons.forward_to_inbox, size: 19), + Text('分享至消息'), ], ), ), @@ -800,25 +789,20 @@ class _LiveRoomPageState extends State Widget get _buildInputWidget { final child = Container( - padding: EdgeInsets.only( - top: 5, - left: 10, - right: 10, - bottom: padding.bottom, - ), + padding: .only(top: 5, left: 10, right: 10, bottom: padding.bottom), height: 70 + padding.bottom, decoration: const BoxDecoration( - borderRadius: BorderRadius.vertical(top: Radius.circular(20)), + borderRadius: .vertical(top: .circular(20)), border: Border(top: BorderSide(color: Color(0x1AFFFFFF))), color: Color(0x1AFFFFFF), ), child: GestureDetector( onTap: _liveRoomController.onSendDanmaku, - behavior: HitTestBehavior.opaque, + behavior: .opaque, child: Padding( - padding: const EdgeInsets.only(top: 5, bottom: 10), + padding: const .only(top: 5, bottom: 10), child: Align( - alignment: Alignment.topCenter, + alignment: .topCenter, child: Row( spacing: 6, children: [ @@ -830,9 +814,7 @@ class _LiveRoomPageState extends State width: 34, height: 34, child: IconButton( - style: IconButton.styleFrom( - padding: EdgeInsets.zero, - ), + style: IconButton.styleFrom(padding: .zero), onPressed: () { final newVal = !enableShowLiveDanmaku; plPlayerController.enableShowDanmaku.value = newVal; @@ -847,12 +829,12 @@ class _LiveRoomPageState extends State ? const Icon( size: 22, CustomIcons.dm_on, - color: Color(0xFFEEEEEE), + color: baseWhite, ) : const Icon( size: 22, CustomIcons.dm_off, - color: Color(0xFFEEEEEE), + color: baseWhite, ), ), ); @@ -861,7 +843,7 @@ class _LiveRoomPageState extends State const Expanded( child: Text( '发送弹幕', - style: TextStyle(color: Color(0xFFEEEEEE)), + style: TextStyle(color: baseWhite), ), ), Builder( @@ -882,7 +864,7 @@ class _LiveRoomPageState extends State dimension: 34, child: Icon( size: 22, - color: Color(0xFFEEEEEE), + color: baseWhite, Icons.thumb_up_off_alt, ), ), @@ -930,7 +912,7 @@ class _LiveRoomPageState extends State onPressed: () => _liveRoomController.onSendDanmaku(true), icon: const Icon( size: 22, - color: Color(0xFFEEEEEE), + color: baseWhite, Icons.emoji_emotions_outlined, ), ), diff --git a/lib/pages/live_room/widgets/bottom_control.dart b/lib/pages/live_room/widgets/bottom_control.dart index 345792da7..2e90bea82 100644 --- a/lib/pages/live_room/widgets/bottom_control.dart +++ b/lib/pages/live_room/widgets/bottom_control.dart @@ -7,6 +7,7 @@ import 'package:PiliPlus/plugin/pl_player/widgets/common_btn.dart'; import 'package:PiliPlus/plugin/pl_player/widgets/play_pause_btn.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; +import 'package:PiliPlus/utils/theme_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -36,6 +37,8 @@ class _BottomControlState extends State with HeaderMixin { late final LiveRoomController liveRoomCtr = widget.liveRoomCtr; @override late final PlPlayerController plPlayerController = widget.plPlayerController; + @override + ThemeData get theme => ThemeUtils.darkTheme; @override Widget build(BuildContext context) { diff --git a/lib/pages/live_room/widgets/header_control.dart b/lib/pages/live_room/widgets/header_control.dart index 8739ef509..43e0ef7b2 100644 --- a/lib/pages/live_room/widgets/header_control.dart +++ b/lib/pages/live_room/widgets/header_control.dart @@ -307,7 +307,6 @@ class _LiveHeaderControlState extends State showModalBottomSheet( context: context, useSafeArea: true, - clipBehavior: .hardEdge, isScrollControlled: true, constraints: BoxConstraints( maxWidth: math.min(640, context.mediaQueryShortestSide), @@ -331,11 +330,7 @@ class _LiveHeaderControlState extends State final currStyle = TextStyle(fontSize: 14, color: secondary); return Theme( data: theme.copyWith(dividerColor: Colors.transparent), - child: ListView( - controller: scrollController, - padding: .only( - bottom: MediaQuery.viewPaddingOf(context).bottom + 100, - ), + child: Column( children: [ InkWell( onTap: Get.back, @@ -354,90 +349,100 @@ class _LiveHeaderControlState extends State ), ), ), - ...controller.stream.indexed.map((stream) { - final isCurrStream = stream.$1 == controller.streamIndex; - final streamColor = isCurrStream - ? secondary - : onSurfaceVariant; - return _ExpansionTile( - initiallyExpanded: isCurrStream, - iconColor: streamColor, - collapsedIconColor: streamColor, - title: Text( - stream.$2.protocolName ?? stream.$1.toString(), - style: isCurrStream - ? currStyle - : const TextStyle(fontSize: 14), + Expanded( + child: ListView( + controller: scrollController, + padding: .only( + bottom: MediaQuery.viewPaddingOf(context).bottom + 100, ), - children: stream.$2.format.indexed.map((format) { - final isCurrFormat = - isCurrStream && format.$1 == controller.formatIndex; - final formatColor = isCurrFormat + children: controller.stream.indexed.map((stream) { + final isCurrStream = + stream.$1 == controller.streamIndex; + final streamColor = isCurrStream ? secondary : onSurfaceVariant; return _ExpansionTile( - initiallyExpanded: isCurrFormat, - iconColor: formatColor, - collapsedIconColor: formatColor, + initiallyExpanded: isCurrStream, + iconColor: streamColor, + collapsedIconColor: streamColor, title: Text( - format.$2.formatName ?? format.$1.toString(), - style: isCurrFormat + stream.$2.protocolName ?? stream.$1.toString(), + style: isCurrStream ? currStyle : const TextStyle(fontSize: 14), ), - children: format.$2.codec.indexed.map((codec) { - final e = codec.$2; - final isCurrCodec = - isCurrFormat && - codec.$1 == controller.codecIndex; - final codecColor = isCurrCodec + children: stream.$2.format.indexed.map((format) { + final isCurrFormat = + isCurrStream && + format.$1 == controller.formatIndex; + final formatColor = isCurrFormat ? secondary : onSurfaceVariant; return _ExpansionTile( - initiallyExpanded: isCurrCodec, - iconColor: codecColor, - collapsedIconColor: codecColor, + initiallyExpanded: isCurrFormat, + iconColor: formatColor, + collapsedIconColor: formatColor, title: Text( - '${e.codecName ?? codec.$1.toString()} (${LiveQuality.fromCode(e.currentQn)?.desc ?? e.currentQn})', - style: isCurrCodec + format.$2.formatName ?? format.$1.toString(), + style: isCurrFormat ? currStyle : const TextStyle(fontSize: 14), ), - children: e.urlInfo.indexed.map((url) { - final isCurrUrl = - (isCurrCodec && - url.$1 == controller.liveUrlIndex); - return ListTile( - dense: true, + children: format.$2.codec.indexed.map((codec) { + final e = codec.$2; + final isCurrCodec = + isCurrFormat && + codec.$1 == controller.codecIndex; + final codecColor = isCurrCodec + ? secondary + : onSurfaceVariant; + return _ExpansionTile( + initiallyExpanded: isCurrCodec, + iconColor: codecColor, + collapsedIconColor: codecColor, title: Text( - '${url.$2.host}${e.baseUrl}...', - style: isCurrUrl - ? const TextStyle(fontSize: 14) - : TextStyle( - fontSize: 14, - color: onSurfaceVariant, - ), + '${e.codecName ?? codec.$1.toString()} (${LiveQuality.fromCode(e.currentQn)?.desc ?? e.currentQn})', + style: isCurrCodec + ? currStyle + : const TextStyle(fontSize: 14), ), - selected: isCurrUrl, - onTap: isCurrUrl - ? null - : () { - Get.back(); - controller.initLiveUrl( - streamIndex: stream.$1, - formatIndex: format.$1, - codecIndex: codec.$1, - liveUrlIndex: url.$1, - ); - }, + children: e.urlInfo.indexed.map((url) { + final isCurrUrl = + (isCurrCodec && + url.$1 == controller.liveUrlIndex); + return ListTile( + dense: true, + title: Text( + '${url.$2.host}${e.baseUrl}...', + style: isCurrUrl + ? const TextStyle(fontSize: 14) + : TextStyle( + fontSize: 14, + color: onSurfaceVariant, + ), + ), + selected: isCurrUrl, + onTap: isCurrUrl + ? null + : () { + Get.back(); + controller.initLiveUrl( + streamIndex: stream.$1, + formatIndex: format.$1, + codecIndex: codec.$1, + liveUrlIndex: url.$1, + ); + }, + ); + }).toList(), ); }).toList(), ); }).toList(), ); }).toList(), - ); - }), + ), + ), ], ), ); diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index 3f1314bed..bc6011a4c 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -644,7 +644,7 @@ class VideoDetailController extends GetxController await Get.key.currentState!.push( PublishRoute( pageBuilder: (buildContext, animation, secondaryAnimation) { - return SendDanmakuPanel( + final child = SendDanmakuPanel( cid: cid.value, bvid: bvid, progress: plPlayerController.position.inMilliseconds, @@ -654,10 +654,13 @@ class VideoDetailController extends GetxController savedDanmaku = null; plPlayerController.danmakuController?.addDanmaku(danmakuModel); }, - darkVideoPage: plPlayerController.darkVideoPage, dmConfig: dmConfig, onSaveDmConfig: (dmConfig) => this.dmConfig = dmConfig, ); + if (plPlayerController.darkVideoPage) { + return Theme(data: ThemeUtils.darkTheme, child: child); + } + return child; }, ), ); @@ -1022,22 +1025,16 @@ class VideoDetailController extends GetxController ); } if (plPlayerController.isFullScreen.value || showVideoSheet) { + final child = PostPanel( + enableSlide: false, + videoDetailController: this, + plPlayerController: plPlayerController, + ); PageUtils.showVideoBottomSheet( context, child: plPlayerController.darkVideoPage - ? Theme( - data: ThemeUtils.darkTheme, - child: PostPanel( - enableSlide: false, - videoDetailController: this, - plPlayerController: plPlayerController, - ), - ) - : PostPanel( - enableSlide: false, - videoDetailController: this, - plPlayerController: plPlayerController, - ), + ? Theme(data: ThemeUtils.darkTheme, child: child) + : child, ); } else { childKey.currentState?.showBottomSheet( @@ -1349,26 +1346,18 @@ class VideoDetailController extends GetxController ).videoDetail.value.title; } catch (_) {} if (plPlayerController.isFullScreen.value || showVideoSheet) { + final child = NoteListPage( + oid: aid, + enableSlide: false, + heroTag: heroTag, + isStein: graphVersion != null, + title: title, + ); PageUtils.showVideoBottomSheet( context, child: plPlayerController.darkVideoPage - ? Theme( - data: ThemeUtils.darkTheme, - child: NoteListPage( - oid: aid, - enableSlide: false, - heroTag: heroTag, - isStein: graphVersion != null, - title: title, - ), - ) - : NoteListPage( - oid: aid, - enableSlide: false, - heroTag: heroTag, - isStein: graphVersion != null, - title: title, - ), + ? Theme(data: ThemeUtils.darkTheme, child: child) + : child, ); } else { childKey.currentState?.showBottomSheet( diff --git a/lib/pages/video/send_danmaku/view.dart b/lib/pages/video/send_danmaku/view.dart index 303b6835a..d34049ebd 100644 --- a/lib/pages/video/send_danmaku/view.dart +++ b/lib/pages/video/send_danmaku/view.dart @@ -10,7 +10,6 @@ import 'package:PiliPlus/pages/danmaku/danmaku_model.dart'; import 'package:PiliPlus/pages/setting/slide_color_picker.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart'; import 'package:PiliPlus/utils/storage_pref.dart'; -import 'package:PiliPlus/utils/theme_utils.dart'; import 'package:canvas_danmaku/models/danmaku_content_item.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter; @@ -24,7 +23,6 @@ class SendDanmakuPanel extends CommonTextPubPage { final dynamic progress; final ValueChanged> onSuccess; - final bool darkVideoPage; // config final ({int? mode, int? fontSize, Color? color})? dmConfig; @@ -38,7 +36,6 @@ class SendDanmakuPanel extends CommonTextPubPage { this.bvid, this.progress, required this.onSuccess, - required this.darkVideoPage, this.dmConfig, this.onSaveDmConfig, }); @@ -138,14 +135,14 @@ class _SendDanmakuPanelState extends CommonTextPubPageState { @override void didChangeDependencies() { super.didChangeDependencies(); - themeData = widget.darkVideoPage ? ThemeUtils.darkTheme : Theme.of(context); + themeData = Theme.of(context); } late ThemeData themeData; @override Widget build(BuildContext context) { - Widget child = ViewSafeArea( + return ViewSafeArea( child: Align( alignment: Alignment.bottomCenter, child: Container( @@ -164,7 +161,6 @@ class _SendDanmakuPanelState extends CommonTextPubPageState { ), ), ); - return widget.darkVideoPage ? Theme(data: themeData, child: child) : child; } @override diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index fcb0fa090..472173c52 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -1983,14 +1983,12 @@ class _VideoDetailPageVState extends State }, ); if (isFullScreen || videoDetailController.showVideoSheet) { + final child = listSheetContent(enableSlide: false); PageUtils.showVideoBottomSheet( context, child: videoDetailController.plPlayerController.darkVideoPage - ? Theme( - data: themeData, - child: listSheetContent(enableSlide: false), - ) - : listSheetContent(enableSlide: false), + ? Theme(data: themeData, child: child) + : child, ); } else { videoDetailController.childKey.currentState?.showBottomSheet( @@ -2062,22 +2060,16 @@ class _VideoDetailPageVState extends State void showViewPoints() { if (isFullScreen || videoDetailController.showVideoSheet) { + final child = ViewPointsPage( + enableSlide: false, + videoDetailController: videoDetailController, + plPlayerController: plPlayerController, + ); PageUtils.showVideoBottomSheet( context, child: videoDetailController.plPlayerController.darkVideoPage - ? Theme( - data: themeData, - child: ViewPointsPage( - enableSlide: false, - videoDetailController: videoDetailController, - plPlayerController: plPlayerController, - ), - ) - : ViewPointsPage( - enableSlide: false, - videoDetailController: videoDetailController, - plPlayerController: plPlayerController, - ), + ? Theme(data: themeData, child: child) + : child, ); } else { videoDetailController.childKey.currentState?.showBottomSheet( diff --git a/lib/pages/video/widgets/header_mixin.dart b/lib/pages/video/widgets/header_mixin.dart index 6012907df..697bb2e0c 100644 --- a/lib/pages/video/widgets/header_mixin.dart +++ b/lib/pages/video/widgets/header_mixin.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/plugin/pl_player/controller.dart'; import 'package:PiliPlus/plugin/pl_player/utils/danmaku_options.dart'; import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/theme_utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -12,6 +13,13 @@ mixin HeaderMixin on State { bool get isFullScreen => plPlayerController.isFullScreen.value; + ThemeData? get theme { + if (plPlayerController.darkVideoPage) { + return ThemeUtils.darkTheme; + } + return null; + } + Future? showBottomSheet( StatefulWidgetBuilder builder, { ValueGetter? padding, @@ -21,12 +29,16 @@ mixin HeaderMixin on State { maxWidth: 512, padding: padding, child: StatefulBuilder( - builder: (context, setState) => plPlayerController.darkVideoPage - ? Theme( - data: Theme.of(this.context), - child: builder(this.context, setState), - ) - : builder(context, setState), + builder: (context, setState) { + final theme = this.theme; + if (theme != null) { + return Theme( + data: theme, + child: builder(this.context, setState), + ); + } + return builder(context, setState); + }, ), ); }