diff --git a/lib/pages/article/view.dart b/lib/pages/article/view.dart index b2fd69ef4..8ec816210 100644 --- a/lib/pages/article/view.dart +++ b/lib/pages/article/view.dart @@ -20,7 +20,6 @@ import 'package:PiliPlus/pages/article/widgets/opus_content.dart'; import 'package:PiliPlus/pages/common/dyn/common_dyn_page.dart'; import 'package:PiliPlus/pages/dynamics_repost/view.dart'; import 'package:PiliPlus/pages/video/reply/widgets/reply_item_grpc.dart'; -import 'package:PiliPlus/utils/context_ext.dart'; import 'package:PiliPlus/utils/date_util.dart'; import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/grid.dart'; @@ -70,19 +69,18 @@ class _ArticlePageState extends CommonDynPageState { @override Widget build(BuildContext context) { final theme = Theme.of(context); - final isPortrait = context.isPortrait; + final size = MediaQuery.sizeOf(context); + final maxWidth = size.width; + final isPortrait = size.height >= maxWidth; return Scaffold( resizeToAvoidBottomInset: false, - appBar: _buildAppBar(isPortrait), + appBar: _buildAppBar(isPortrait, maxWidth), body: Padding( - padding: EdgeInsets.only( - left: padding.left, - right: padding.right, - ), + padding: EdgeInsets.only(left: padding.left, right: padding.right), child: Stack( clipBehavior: Clip.none, children: [ - _buildPage(theme, isPortrait), + _buildPage(theme, isPortrait, maxWidth), _buildBottom(theme), ], ), @@ -90,101 +88,89 @@ class _ArticlePageState extends CommonDynPageState { ); } - Widget _buildPage(ThemeData theme, bool isPortrait) { - return LayoutBuilder( - builder: (context, constraints) { - double padding = max( - context.width / 2 - Grid.smallCardWidth, - 0, - ); - - if (isPortrait) { - final maxWidth = constraints.maxWidth - 2 * padding - 24; - return Padding( - padding: EdgeInsets.symmetric(horizontal: padding), - child: CustomScrollView( - controller: controller.scrollController, - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - _buildContent(theme, maxWidth), - SliverToBoxAdapter( - child: Divider( - thickness: 8, - color: theme.dividerColor.withValues( - alpha: 0.05, - ), - ), - ), - buildReplyHeader(theme), - Obx( - () => _buildReplyList( - theme, - controller.loadingState.value, - ), - ), - ], + Widget _buildPage(ThemeData theme, bool isPortrait, double maxWidth) { + double padding = max(maxWidth / 2 - Grid.smallCardWidth, 0); + if (isPortrait) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: padding), + child: CustomScrollView( + controller: controller.scrollController, + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + _buildContent( + theme, + maxWidth - this.padding.horizontal - 2 * padding - 24, ), - ); - } - - padding = padding / 4; - final flex = controller.ratio[0].toInt(); - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - flex: flex, - child: CustomScrollView( - controller: controller.scrollController, - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - SliverPadding( - padding: EdgeInsets.only( - left: padding, - bottom: this.padding.bottom + 100, - ), - sliver: _buildContent( - theme, - constraints.maxWidth * flex - padding - 24, - ), - ), - ], - ), - ), - VerticalDivider( - thickness: 8, - color: theme.dividerColor.withValues(alpha: 0.05), - ), - Expanded( - flex: controller.ratio[1].toInt(), - child: Scaffold( - key: scaffoldKey, - backgroundColor: Colors.transparent, - resizeToAvoidBottomInset: false, - body: refreshIndicator( - onRefresh: controller.onRefresh, - child: Padding( - padding: EdgeInsets.only(right: padding), - child: CustomScrollView( - controller: controller.scrollController, - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - buildReplyHeader(theme), - Obx( - () => _buildReplyList( - theme, - controller.loadingState.value, - ), - ), - ], - ), - ), - ), + SliverToBoxAdapter( + child: Divider( + thickness: 8, + color: theme.dividerColor.withValues(alpha: 0.05), ), ), + buildReplyHeader(theme), + Obx(() => _buildReplyList(theme, controller.loadingState.value)), ], - ); - }, + ), + ); + } + + padding = padding / 4; + final flex = controller.ratio[0].toInt(); + final flex1 = controller.ratio[1].toInt(); + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: flex, + child: CustomScrollView( + controller: controller.scrollController, + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverPadding( + padding: EdgeInsets.only( + left: padding, + bottom: this.padding.bottom + 100, + ), + sliver: _buildContent( + theme, + (maxWidth - this.padding.horizontal) * flex / (flex + flex1) - + padding - + 32, + ), + ), + ], + ), + ), + VerticalDivider( + thickness: 8, + color: theme.dividerColor.withValues(alpha: 0.05), + ), + Expanded( + flex: flex1, + child: Padding( + padding: EdgeInsets.only(right: padding), + child: Scaffold( + key: scaffoldKey, + backgroundColor: Colors.transparent, + resizeToAvoidBottomInset: false, + body: refreshIndicator( + onRefresh: controller.onRefresh, + child: CustomScrollView( + controller: controller.scrollController, + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + buildReplyHeader(theme), + Obx( + () => + _buildReplyList(theme, controller.loadingState.value), + ), + ], + ), + ), + ), + ), + ), + ], ); } @@ -484,7 +470,7 @@ class _ArticlePageState extends CommonDynPageState { }; } - PreferredSizeWidget _buildAppBar(bool isPortrait) => AppBar( + PreferredSizeWidget _buildAppBar(bool isPortrait, double maxWidth) => AppBar( title: Obx(() { if (controller.isLoaded.value && controller.showTitle.value) { return Text(controller.summary.title ?? ''); @@ -505,7 +491,7 @@ class _ArticlePageState extends CommonDynPageState { top: 56, right: 16, ), - width: context.width / 4, + width: maxWidth / 4, height: 32, child: Builder( builder: (context) => Slider( diff --git a/lib/pages/common/dyn/common_dyn_page.dart b/lib/pages/common/dyn/common_dyn_page.dart index bd4113c10..0e31326a8 100644 --- a/lib/pages/common/dyn/common_dyn_page.dart +++ b/lib/pages/common/dyn/common_dyn_page.dart @@ -163,42 +163,39 @@ abstract class CommonDynPageState extends State EasyThrottle.throttle('replyReply', const Duration(milliseconds: 500), () { int oid = replyItem.oid.toInt(); int rpid = replyItem.id.toInt(); - Widget replyReplyPage({bool showBackBtn = true}) => Padding( - padding: EdgeInsets.only(right: padding.right), - child: Scaffold( - resizeToAvoidBottomInset: false, - appBar: AppBar( - primary: showBackBtn, - toolbarHeight: showBackBtn ? null : 45, - title: const Text('评论详情'), - titleSpacing: showBackBtn ? null : 12, - automaticallyImplyLeading: showBackBtn, - actions: showBackBtn - ? null - : [ - IconButton( - tooltip: '关闭', - icon: const Icon(Icons.close, size: 20), - onPressed: Get.back, - ), - ], - shape: Border( - bottom: BorderSide( - color: Theme.of( - context, - ).colorScheme.outline.withValues(alpha: 0.1), - ), + Widget replyReplyPage({bool showBackBtn = true}) => Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBar( + primary: showBackBtn, + toolbarHeight: showBackBtn ? null : 45, + title: const Text('评论详情'), + titleSpacing: showBackBtn ? null : 12, + automaticallyImplyLeading: showBackBtn, + actions: showBackBtn + ? null + : [ + IconButton( + tooltip: '关闭', + icon: const Icon(Icons.close, size: 20), + onPressed: Get.back, + ), + ], + shape: Border( + bottom: BorderSide( + color: Theme.of( + context, + ).colorScheme.outline.withValues(alpha: 0.1), ), ), - body: VideoReplyReplyPanel( - enableSlide: false, - id: id, - oid: oid, - rpid: rpid, - isVideoDetail: false, - replyType: controller.replyType, - firstFloor: replyItem, - ), + ), + body: VideoReplyReplyPanel( + enableSlide: false, + id: id, + oid: oid, + rpid: rpid, + isVideoDetail: false, + replyType: controller.replyType, + firstFloor: replyItem, ), ); if (this.context.isPortrait) { diff --git a/lib/pages/dynamics_detail/view.dart b/lib/pages/dynamics_detail/view.dart index 2cfe2eb40..fdd15871a 100644 --- a/lib/pages/dynamics_detail/view.dart +++ b/lib/pages/dynamics_detail/view.dart @@ -9,7 +9,6 @@ import 'package:PiliPlus/pages/dynamics/widgets/author_panel.dart'; import 'package:PiliPlus/pages/dynamics/widgets/dynamic_panel.dart'; import 'package:PiliPlus/pages/dynamics_detail/controller.dart'; import 'package:PiliPlus/pages/dynamics_repost/view.dart'; -import 'package:PiliPlus/utils/context_ext.dart'; import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:PiliPlus/utils/num_util.dart'; @@ -54,117 +53,159 @@ class _DynamicDetailPageState extends CommonDynPageState { @override Widget build(BuildContext context) { final theme = Theme.of(context); - final isPortrait = context.isPortrait; + final size = MediaQuery.sizeOf(context); + final maxWidth = size.width; + final isPortrait = size.height >= maxWidth; return Scaffold( resizeToAvoidBottomInset: false, - appBar: AppBar( - title: Padding( - padding: const EdgeInsets.only(right: 12), - child: Obx( - () { - final showTitle = controller.showTitle.value; - return AnimatedOpacity( - opacity: showTitle ? 1 : 0, - duration: const Duration(milliseconds: 300), - child: IgnorePointer( - ignoring: !showTitle, - child: AuthorPanel( - item: controller.dynItem, - isDetail: true, - ), - ), - ); - }, - ), - ), - actions: isPortrait - ? null - : [ - IconButton( - tooltip: '页面比例调节', - onPressed: () => showDialog( - context: context, - builder: (context) => Align( - alignment: Alignment.topRight, - child: Container( - margin: const EdgeInsets.only( - top: 56, - right: 16, - ), - width: context.width / 4, - height: 32, - child: Builder( - builder: (context) => Slider( - min: 1, - max: 100, - value: controller.ratio.first, - onChanged: (value) { - if (value >= 10 && value <= 90) { - value = value.toPrecision(2); - controller.ratio - ..[0] = value - ..[1] = 100 - value; - GStorage.setting.put( - SettingBoxKey.dynamicDetailRatio, - controller.ratio, - ); - (context as Element).markNeedsBuild(); - setState(() {}); - } - }, - ), - ), - ), - ), - ), - icon: Transform.rotate( - angle: pi / 2, - child: const Icon(Icons.splitscreen, size: 19), - ), - ), - const SizedBox(width: 16), - ], - ), + appBar: _buildAppBar(isPortrait, maxWidth), body: Padding( - padding: EdgeInsets.only( - left: padding.left, - right: padding.right, - ), + padding: EdgeInsets.only(left: padding.left, right: padding.right), child: isPortrait ? refreshIndicator( onRefresh: controller.onRefresh, - child: _buildBody(isPortrait, theme), + child: _buildBody(theme, isPortrait, maxWidth), ) - : _buildBody(isPortrait, theme), + : _buildBody(theme, isPortrait, maxWidth), ), ); } - Widget _buildBody(bool isPortrait, ThemeData theme) => Stack( - clipBehavior: Clip.none, - children: [ - Builder( - builder: (context) { - double padding = max(context.width / 2 - Grid.smallCardWidth, 0); - if (isPortrait) { - return CustomScrollView( + PreferredSizeWidget _buildAppBar(bool isPortrait, double maxWidth) => AppBar( + title: Padding( + padding: const EdgeInsets.only(right: 12), + child: Obx( + () { + final showTitle = controller.showTitle.value; + return AnimatedOpacity( + opacity: showTitle ? 1 : 0, + duration: const Duration(milliseconds: 300), + child: IgnorePointer( + ignoring: !showTitle, + child: AuthorPanel( + item: controller.dynItem, + isDetail: true, + ), + ), + ); + }, + ), + ), + actions: isPortrait + ? null + : [ + IconButton( + tooltip: '页面比例调节', + onPressed: () => showDialog( + context: context, + builder: (context) => Align( + alignment: Alignment.topRight, + child: Container( + margin: const EdgeInsets.only(top: 56, right: 16), + width: maxWidth / 4, + height: 32, + child: Builder( + builder: (context) => Slider( + min: 1, + max: 100, + value: controller.ratio.first, + onChanged: (value) { + if (value >= 10 && value <= 90) { + value = value.toPrecision(2); + controller.ratio + ..[0] = value + ..[1] = 100 - value; + GStorage.setting.put( + SettingBoxKey.dynamicDetailRatio, + controller.ratio, + ); + (context as Element).markNeedsBuild(); + setState(() {}); + } + }, + ), + ), + ), + ), + ), + icon: Transform.rotate( + angle: pi / 2, + child: const Icon(Icons.splitscreen, size: 19), + ), + ), + const SizedBox(width: 16), + ], + ); + + Widget _buildBody(ThemeData theme, bool isPortrait, double maxWidth) { + double padding = max(maxWidth / 2 - Grid.smallCardWidth, 0); + Widget child; + if (isPortrait) { + child = Padding( + padding: EdgeInsets.symmetric(horizontal: padding), + child: CustomScrollView( + controller: controller.scrollController, + physics: const AlwaysScrollableScrollPhysics(), + slivers: [ + SliverToBoxAdapter( + child: DynamicPanel( + item: controller.dynItem, + isDetail: true, + callback: imageCallback, + maxWidth: maxWidth - this.padding.horizontal - 2 * padding, + ), + ), + buildReplyHeader(theme), + Obx(() => replyList(theme, controller.loadingState.value)), + ], + ), + ); + } else { + padding = padding / 4; + final flex = controller.ratio[0].toInt(); + final flex1 = controller.ratio[1].toInt(); + child = Row( + children: [ + Expanded( + flex: flex, + child: CustomScrollView( controller: controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( - padding: EdgeInsets.symmetric(horizontal: padding), - sliver: SliverMainAxisGroup( + padding: EdgeInsets.only( + left: padding, + bottom: this.padding.bottom + 100, + ), + sliver: SliverToBoxAdapter( + child: DynamicPanel( + item: controller.dynItem, + isDetail: true, + callback: imageCallback, + maxWidth: + (maxWidth - this.padding.horizontal) * + (flex / (flex + flex1)) - + padding, + ), + ), + ), + ], + ), + ), + Expanded( + flex: flex1, + child: Padding( + padding: EdgeInsets.only(right: padding), + child: Scaffold( + key: scaffoldKey, + backgroundColor: Colors.transparent, + resizeToAvoidBottomInset: false, + body: refreshIndicator( + onRefresh: controller.onRefresh, + child: CustomScrollView( + controller: controller.scrollController, + physics: const AlwaysScrollableScrollPhysics(), slivers: [ - SliverToBoxAdapter( - child: LayoutBuilder( - builder: (_, constrains) => DynamicPanel( - item: controller.dynItem, - isDetail: true, - callback: imageCallback, - maxWidth: constrains.maxWidth, - ), - ), - ), buildReplyHeader(theme), Obx( () => replyList(theme, controller.loadingState.value), @@ -172,74 +213,20 @@ class _DynamicDetailPageState extends CommonDynPageState { ], ), ), - ], - ); - } else { - return Row( - children: [ - Expanded( - flex: controller.ratio[0].toInt(), - child: CustomScrollView( - controller: controller.scrollController, - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - SliverPadding( - padding: EdgeInsets.only( - left: padding / 4, - bottom: this.padding.bottom + 100, - ), - sliver: SliverToBoxAdapter( - child: LayoutBuilder( - builder: (_, constraints) => DynamicPanel( - item: controller.dynItem, - isDetail: true, - callback: imageCallback, - maxWidth: constraints.maxWidth, - ), - ), - ), - ), - ], - ), - ), - Expanded( - flex: controller.ratio[1].toInt(), - child: Scaffold( - key: scaffoldKey, - backgroundColor: Colors.transparent, - resizeToAvoidBottomInset: false, - body: refreshIndicator( - onRefresh: controller.onRefresh, - child: CustomScrollView( - controller: controller.scrollController, - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - SliverPadding( - padding: EdgeInsets.only(right: padding / 4), - sliver: buildReplyHeader(theme), - ), - SliverPadding( - padding: EdgeInsets.only(right: padding / 4), - sliver: Obx( - () => replyList( - theme, - controller.loadingState.value, - ), - ), - ), - ], - ), - ), - ), - ), - ], - ); - } - }, - ), - _buildBottom(theme), - ], - ); + ), + ), + ), + ], + ); + } + return Stack( + clipBehavior: Clip.none, + children: [ + child, + _buildBottom(theme), + ], + ); + } Widget _buildBottom(ThemeData theme) { return Positioned( diff --git a/lib/pages/save_panel/view.dart b/lib/pages/save_panel/view.dart index d2baee123..b325061f7 100644 --- a/lib/pages/save_panel/view.dart +++ b/lib/pages/save_panel/view.dart @@ -297,6 +297,7 @@ class _SavePanelState extends State { Widget build(BuildContext context) { final theme = Theme.of(context); final padding = MediaQuery.viewPaddingOf(context); + final maxWidth = context.mediaQueryShortestSide; return GestureDetector( behavior: HitTestBehavior.opaque, onTap: Get.back, @@ -312,17 +313,15 @@ class _SavePanelState extends State { child: GestureDetector( onTap: () {}, child: Container( - width: context.mediaQueryShortestSide, - margin: const EdgeInsets.symmetric(horizontal: 12), + width: maxWidth, + padding: const EdgeInsets.symmetric(horizontal: 12), child: RepaintBoundary( key: boundaryKey, child: Container( clipBehavior: Clip.hardEdge, decoration: BoxDecoration( color: theme.colorScheme.surface, - borderRadius: const BorderRadius.all( - Radius.circular(12), - ), + borderRadius: const BorderRadius.all(Radius.circular(12)), ), child: AnimatedSize( curve: Curves.easeInOut, @@ -343,13 +342,11 @@ class _SavePanelState extends State { ) else if (_item is DynamicItemModel) IgnorePointer( - child: LayoutBuilder( - builder: (_, constrains) => DynamicPanel( - item: _item, - isDetail: true, - isSave: true, - maxWidth: constrains.maxWidth, - ), + child: DynamicPanel( + item: _item, + isDetail: true, + isSave: true, + maxWidth: maxWidth - 24, ), ), if (cover?.isNotEmpty == true && diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index 026150621..7992b59af 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -414,6 +414,7 @@ class VideoDetailController extends GetxController } else { childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => panel(), ); } @@ -1381,6 +1382,7 @@ class VideoDetailController extends GetxController } else { childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => PostPanel( videoDetailController: this, plPlayerController: plPlayerController, @@ -1689,6 +1691,7 @@ class VideoDetailController extends GetxController } else { childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => NoteListPage( oid: aid, heroTag: heroTag, diff --git a/lib/pages/video/note/view.dart b/lib/pages/video/note/view.dart index 597692f69..55d6a5c7a 100644 --- a/lib/pages/video/note/view.dart +++ b/lib/pages/video/note/view.dart @@ -143,6 +143,7 @@ class _NoteListPageState extends CommonSlidePageState { return; } _key.currentState?.showBottomSheet( + constraints: const BoxConstraints(), (context) => WebviewPage( oid: widget.oid, title: widget.title, diff --git a/lib/pages/video/reply_reply/view.dart b/lib/pages/video/reply_reply/view.dart index d56c9cf92..a6f0b09ac 100644 --- a/lib/pages/video/reply_reply/view.dart +++ b/lib/pages/video/reply_reply/view.dart @@ -362,6 +362,7 @@ class _VideoReplyReplyPanelState upMid: _controller.upMid, showDialogue: () => _key.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => VideoReplyReplyPanel( oid: replyItem.oid.toInt(), rpid: replyItem.root.toInt(), diff --git a/lib/pages/video/send_danmaku/view.dart b/lib/pages/video/send_danmaku/view.dart index e88776917..8e7c6ca00 100644 --- a/lib/pages/video/send_danmaku/view.dart +++ b/lib/pages/video/send_danmaku/view.dart @@ -87,50 +87,48 @@ class _SendDanmakuPanelState extends CommonTextPubPageState { super.dispose(); } - Expanded get _buildColorPanel => Expanded( + Widget get _buildColorPanel => Expanded( child: Obx( - () => LayoutBuilder( - key: ValueKey(_color.value), - builder: (context, constraints) { - final int crossAxisCount = (constraints.maxWidth / 40).toInt(); - final bool isCustomColor = !_colorList.contains(_color.value); - final int length = _colorList.length + (isCustomColor ? 1 : 0) + 1; - return GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - padding: EdgeInsets.zero, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount, - crossAxisSpacing: 4, - mainAxisSpacing: 4, - ), - itemCount: length, - itemBuilder: (context, index) { - if (index == length - 1) { - return GestureDetector( - onTap: _showColorPicker, - child: Container( - decoration: BoxDecoration( - color: themeData.colorScheme.secondaryContainer, - borderRadius: const BorderRadius.all(Radius.circular(8)), - ), - alignment: Alignment.center, - margin: const EdgeInsets.all(2), - child: Icon( - size: 22, - Icons.edit, - color: themeData.colorScheme.onSecondaryContainer, + () { + final bool isCustomColor = !_colorList.contains(_color.value); + final int length = _colorList.length + (isCustomColor ? 1 : 0) + 1; + return GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 42, + crossAxisSpacing: 4, + mainAxisSpacing: 4, + ), + itemCount: length, + itemBuilder: (context, index) { + if (index == length - 1) { + return GestureDetector( + onTap: _showColorPicker, + child: Container( + decoration: BoxDecoration( + color: themeData.colorScheme.secondaryContainer, + borderRadius: const BorderRadius.all( + Radius.circular(8), ), ), - ); - } else if (index == length - 2 && isCustomColor) { - return _buildColorItem(_color.value); - } - return _buildColorItem(_colorList[index]); - }, - ); - }, - ), + alignment: Alignment.center, + margin: const EdgeInsets.all(2), + child: Icon( + size: 22, + Icons.edit, + color: themeData.colorScheme.onSecondaryContainer, + ), + ), + ); + } else if (index == length - 2 && isCustomColor) { + return _buildColorItem(_color.value); + } + return _buildColorItem(_colorList[index]); + }, + ); + }, ), ); diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index fbd55870f..0aa62131f 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -2028,6 +2028,7 @@ class _VideoDetailPageVState extends State int rpid = replyItem.id.toInt(); videoDetailController.childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => VideoReplyReplyPanel( id: id, oid: oid, @@ -2046,6 +2047,7 @@ class _VideoDetailPageVState extends State void showAiBottomSheet() { videoDetailController.childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => AiConclusionPanel(item: ugcIntroController.aiConclusionResult!), ); @@ -2057,6 +2059,7 @@ class _VideoDetailPageVState extends State ) { videoDetailController.childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => PgcIntroPanel( item: videoDetail, videoTags: videoTags, @@ -2126,6 +2129,7 @@ class _VideoDetailPageVState extends State } else { videoDetailController.childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => listSheetContent(), ); } @@ -2217,6 +2221,7 @@ class _VideoDetailPageVState extends State } else { videoDetailController.childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, + constraints: const BoxConstraints(), (context) => ViewPointsPage( videoDetailController: videoDetailController, plPlayerController: plPlayerController, @@ -2241,6 +2246,7 @@ class _VideoDetailPageVState extends State void onShowMemberPage(int? mid) { videoDetailController.childKey.currentState?.showBottomSheet( shape: const RoundedRectangleBorder(), + constraints: const BoxConstraints(), (context) { return HorizontalMemberPage( mid: mid, diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 45093711d..9d6023057 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -1378,6 +1378,8 @@ class _PLVideoPlayerState extends State child: widget.bottomControl ?? BottomControl( + maxWidth: maxWidth, + isFullScreen: isFullScreen, controller: plPlayerController, buildBottomControl: () => buildBottomControl(maxWidth > maxHeight), diff --git a/lib/plugin/pl_player/widgets/bottom_control.dart b/lib/plugin/pl_player/widgets/bottom_control.dart index 0d24f9ccc..02906c495 100644 --- a/lib/plugin/pl_player/widgets/bottom_control.dart +++ b/lib/plugin/pl_player/widgets/bottom_control.dart @@ -11,11 +11,15 @@ import 'package:get/get.dart'; class BottomControl extends StatelessWidget { const BottomControl({ + super.key, + required this.maxWidth, + required this.isFullScreen, required this.controller, required this.buildBottomControl, - super.key, }); + final double maxWidth; + final bool isFullScreen; final PlPlayerController controller; final Widget Function() buildBottomControl; @@ -33,130 +37,125 @@ class BottomControl extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.fromLTRB(10, 0, 10, 7), - child: LayoutBuilder( - builder: (context, constraints) { - final maxWidth = constraints.maxWidth; - return Obx( - () => Stack( - clipBehavior: Clip.none, - alignment: Alignment.bottomCenter, - children: [ - Obx(() { - final int value = - controller.sliderPositionSeconds.value; - final int max = - controller.durationSeconds.value.inSeconds; - final int buffer = controller.bufferedSeconds.value; - if (value > max || max <= 0) { - return const SizedBox.shrink(); + child: Obx( + () => Stack( + clipBehavior: Clip.none, + alignment: Alignment.bottomCenter, + children: [ + Obx(() { + final int value = controller.sliderPositionSeconds.value; + final int max = controller.durationSeconds.value.inSeconds; + final int buffer = controller.bufferedSeconds.value; + if (value > max || max <= 0) { + return const SizedBox.shrink(); + } + return ProgressBar( + progress: Duration(seconds: value), + buffered: Duration(seconds: buffer), + total: Duration(seconds: max), + progressBarColor: colorTheme, + baseBarColor: Colors.white.withValues(alpha: 0.2), + bufferedBarColor: colorTheme.withValues(alpha: 0.4), + timeLabelLocation: TimeLabelLocation.none, + thumbColor: colorTheme, + barHeight: 3.5, + thumbRadius: 7, + onDragStart: (duration) { + feedBack(); + controller.onChangedSliderStart(duration.timeStamp); + }, + onDragUpdate: (duration) { + if (controller.showSeekPreview) { + controller.updatePreviewIndex( + duration.timeStamp.inSeconds, + ); } - return ProgressBar( - progress: Duration(seconds: value), - buffered: Duration(seconds: buffer), - total: Duration(seconds: max), - progressBarColor: colorTheme, - baseBarColor: Colors.white.withValues(alpha: 0.2), - bufferedBarColor: colorTheme.withValues(alpha: 0.4), - timeLabelLocation: TimeLabelLocation.none, - thumbColor: colorTheme, - barHeight: 3.5, - thumbRadius: 7, - onDragStart: (duration) { - feedBack(); - controller.onChangedSliderStart(duration.timeStamp); - }, - onDragUpdate: (duration) { - if (controller.showSeekPreview) { - controller.updatePreviewIndex( - duration.timeStamp.inSeconds, + double newProgress = duration.timeStamp.inSeconds / max; + if ((newProgress - lastAnnouncedValue).abs() > 0.02) { + accessibilityDebounce?.cancel(); + accessibilityDebounce = Timer( + const Duration(milliseconds: 200), + () { + SemanticsService.announce( + "${(newProgress * 100).round()}%", + TextDirection.ltr, ); - } - double newProgress = - duration.timeStamp.inSeconds / max; - if ((newProgress - lastAnnouncedValue).abs() > - 0.02) { - accessibilityDebounce?.cancel(); - accessibilityDebounce = Timer( - const Duration(milliseconds: 200), - () { - SemanticsService.announce( - "${(newProgress * 100).round()}%", - TextDirection.ltr, - ); - lastAnnouncedValue = newProgress; - }, - ); - } - controller.onUpdatedSliderProgress( - duration.timeStamp, - ); - }, - onSeek: (duration) { - if (controller.showSeekPreview) { - controller.showPreview.value = false; - } - controller - ..onChangedSliderEnd() - ..onChangedSlider(duration.inSeconds.toDouble()) - ..seekTo( - Duration(seconds: duration.inSeconds), - isSeek: false, - ); - SemanticsService.announce( - "${(duration.inSeconds / max * 100).round()}%", - TextDirection.ltr, - ); - }, + lastAnnouncedValue = newProgress; + }, + ); + } + controller.onUpdatedSliderProgress( + duration.timeStamp, ); - }), - if (controller.segmentList.isNotEmpty) - Positioned( - left: 0, - right: 0, - bottom: 5.25, - child: IgnorePointer( - child: RepaintBoundary( - child: CustomPaint( - key: const Key('segmentList'), - size: const Size(double.infinity, 3.5), - painter: SegmentProgressBar( - segmentColors: controller.segmentList, - ), - ), + }, + onSeek: (duration) { + if (controller.showSeekPreview) { + controller.showPreview.value = false; + } + controller + ..onChangedSliderEnd() + ..onChangedSlider(duration.inSeconds.toDouble()) + ..seekTo( + Duration(seconds: duration.inSeconds), + isSeek: false, + ); + SemanticsService.announce( + "${(duration.inSeconds / max * 100).round()}%", + TextDirection.ltr, + ); + }, + ); + }), + if (controller.segmentList.isNotEmpty) + Positioned( + left: 0, + right: 0, + bottom: 5.25, + child: IgnorePointer( + child: RepaintBoundary( + child: CustomPaint( + key: const Key('segmentList'), + size: const Size(double.infinity, 3.5), + painter: SegmentProgressBar( + segmentColors: controller.segmentList, ), ), ), - if (controller.viewPointList.isNotEmpty && - controller.showVP.value) ...[ - Positioned( - left: 0, - right: 0, - bottom: 5.25, - child: IgnorePointer( - child: RepaintBoundary( - child: CustomPaint( - key: const Key('viewPointList'), - size: const Size(double.infinity, 3.5), - painter: SegmentProgressBar( - segmentColors: controller.viewPointList, - ), - ), + ), + ), + if (controller.viewPointList.isNotEmpty && + controller.showVP.value) ...[ + Positioned( + left: 0, + right: 0, + bottom: 5.25, + child: IgnorePointer( + child: RepaintBoundary( + child: CustomPaint( + key: const Key('viewPointList'), + size: const Size(double.infinity, 3.5), + painter: SegmentProgressBar( + segmentColors: controller.viewPointList, ), ), ), - buildViewPointWidget( - controller, - 8.75, - maxWidth, - ), - ], - if (controller.dmTrend.isNotEmpty && - controller.showDmTreandChart.value) - buildDmChart(theme, controller, 4.5), - ], - ), - ); - }, + ), + ), + buildViewPointWidget( + controller, + 8.75, + maxWidth - + 40 - + (isFullScreen + ? MediaQuery.viewPaddingOf(context).horizontal + : 0), + ), + ], + if (controller.dmTrend.isNotEmpty && + controller.showDmTreandChart.value) + buildDmChart(theme, controller, 4.5), + ], + ), ), ), buildBottomControl(),