diff --git a/lib/common/widgets/custom_tooltip.dart b/lib/common/widgets/custom_tooltip.dart index 7e95600b1..c665fce0d 100644 --- a/lib/common/widgets/custom_tooltip.dart +++ b/lib/common/widgets/custom_tooltip.dart @@ -1,6 +1,3 @@ -import 'dart:math' as math; -import 'dart:ui' show clampDouble; - import 'package:PiliPlus/utils/platform_utils.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart' @@ -10,18 +7,14 @@ import 'package:flutter/rendering.dart' MultiChildLayoutParentData; import 'package:flutter/widgets.dart'; -enum TooltipType { top, right } - class CustomTooltip extends StatefulWidget { const CustomTooltip({ super.key, - this.type = TooltipType.top, required this.overlayWidget, required this.child, required this.indicator, }); - final TooltipType type; final Widget child; final ValueGetter overlayWidget; final ValueGetter indicator; @@ -51,27 +44,20 @@ class _CustomTooltipState extends State { longPressRecognizer.addPointer(event); } - Widget _buildCustomTooltipOverlay(BuildContext context) { - final OverlayState overlayState = Overlay.of( - context, - debugRequiredFor: widget, + Widget _buildCustomTooltipOverlay( + BuildContext context, + OverlayChildLayoutInfo layoutInfo, + ) { + final target = MatrixUtils.transformPoint( + layoutInfo.childPaintTransform, + layoutInfo.childSize.topCenter(Offset.zero), ); - final RenderBox box = this.context.findRenderObject()! as RenderBox; - final Offset target = box.localToGlobal( - box.size.center(Offset.zero), - ancestor: overlayState.context.findRenderObject(), - ); - final _CustomTooltipOverlay overlayChild = _CustomTooltipOverlay( - verticalOffset: box.size.height / 2, - horizontalOffset: box.size.width / 2, - type: widget.type, target: target, onDismiss: _scheduleDismissTooltip, overlayWidget: widget.overlayWidget, indicator: widget.indicator, ); - return SelectionContainer.maybeOf(context) == null ? overlayChild : SelectionContainer.disabled(child: overlayChild); @@ -105,7 +91,7 @@ class _CustomTooltipState extends State { child: widget.child, ); } - return OverlayPortal( + return OverlayPortal.overlayChildLayoutBuilder( controller: _overlayController, overlayChildBuilder: _buildCustomTooltipOverlay, child: result, @@ -117,18 +103,12 @@ enum _ChildType { overlay, indicator } class _CustomTooltipOverlay extends StatelessWidget { const _CustomTooltipOverlay({ - required this.verticalOffset, - required this.horizontalOffset, - required this.type, required this.target, required this.onDismiss, required this.overlayWidget, required this.indicator, }); - final double verticalOffset; - final double horizontalOffset; - final TooltipType type; final Offset target; final VoidCallback onDismiss; final ValueGetter overlayWidget; @@ -137,10 +117,7 @@ class _CustomTooltipOverlay extends StatelessWidget { @override Widget build(BuildContext context) { return _ToolTip( - type: type, target: target, - verticalOffset: verticalOffset, - horizontalOffset: horizontalOffset, preferBelow: false, onTap: PlatformUtils.isMobile ? onDismiss : null, children: [ @@ -161,28 +138,19 @@ class _ToolTip extends MultiChildRenderObjectWidget { const _ToolTip({ super.children, this.onTap, - required this.type, required this.target, - required this.verticalOffset, - required this.horizontalOffset, required this.preferBelow, }); final VoidCallback? onTap; - final TooltipType type; final Offset target; - final double verticalOffset; - final double horizontalOffset; final bool preferBelow; @override RenderObject createRenderObject(BuildContext context) { return _RenderToolTip( onTap: onTap, - type: type, target: target, - verticalOffset: verticalOffset, - horizontalOffset: horizontalOffset, preferBelow: preferBelow, ); } @@ -192,8 +160,6 @@ class _ToolTip extends MultiChildRenderObjectWidget { renderObject ..onTap = onTap ..target = target - ..verticalOffset = verticalOffset - ..horizontalOffset = horizontalOffset ..preferBelow = preferBelow; } } @@ -204,15 +170,9 @@ class _RenderToolTip extends RenderBox RenderBoxContainerDefaultsMixin { _RenderToolTip({ VoidCallback? onTap, - required TooltipType type, required Offset target, - required double verticalOffset, - required double horizontalOffset, required bool preferBelow, - }) : _type = type, - _target = target, - _verticalOffset = verticalOffset, - _horizontalOffset = horizontalOffset, + }) : _target = target, _preferBelow = preferBelow, _hitTestSelf = onTap != null { if (onTap != null) { @@ -246,8 +206,6 @@ class _RenderToolTip extends RenderBox } } - final TooltipType _type; - Offset _target; Offset get target => _target; set target(Offset value) { @@ -256,22 +214,6 @@ class _RenderToolTip extends RenderBox markNeedsPaint(); } - double _verticalOffset; - double get verticalOffset => _verticalOffset; - set verticalOffset(double value) { - if (_verticalOffset == value) return; - _verticalOffset = value; - markNeedsPaint(); - } - - double _horizontalOffset; - double get horizontalOffset => _horizontalOffset; - set horizontalOffset(double value) { - if (_horizontalOffset == value) return; - _horizontalOffset = value; - markNeedsPaint(); - } - bool _preferBelow; bool get preferBelow => _preferBelow; set preferBelow(bool value) { @@ -302,40 +244,18 @@ class _RenderToolTip extends RenderBox indicator.parentData as MultiChildLayoutParentData; final overlayParentData = overlay.parentData as MultiChildLayoutParentData; - switch (_type) { - case TooltipType.top: - Offset offset = _positionDependentBox( - type: _type, - size: size, - childSize: overlaySize, - target: target, - verticalOffset: verticalOffset, - horizontalOffset: horizontalOffset, - preferBelow: preferBelow, - ); - offset = Offset(offset.dx, offset.dy - indicatorSize.height + 1); - overlayParentData.offset = offset; - indicatorParentData.offset = Offset( - target.dx - indicatorSize.width / 2, - offset.dy + overlaySize.height - 1, - ); - case TooltipType.right: - Offset offset = _positionDependentBox( - type: _type, - size: size, - childSize: overlaySize, - target: target, - verticalOffset: verticalOffset, - horizontalOffset: horizontalOffset, - preferBelow: preferBelow, - ); - offset = Offset(offset.dx + indicatorSize.height - 1, offset.dy); - overlayParentData.offset = offset; - Offset( - offset.dx - indicatorSize.width + 1, - target.dy - indicatorSize.height / 2, - ); - } + Offset offset = positionDependentBox( + size: size, + childSize: overlaySize, + target: target, + preferBelow: preferBelow, + ); + offset = Offset(offset.dx, offset.dy - indicatorSize.height + 1); + overlayParentData.offset = offset; + indicatorParentData.offset = Offset( + target.dx - indicatorSize.width / 2, + offset.dy + overlaySize.height - 1, + ); } @override @@ -357,19 +277,16 @@ class Triangle extends LeafRenderObjectWidget { super.key, required this.color, required this.size, - this.type = .top, }); final Color color; final Size size; - final TooltipType type; @override RenderObject createRenderObject(BuildContext context) { return RenderTriangle( color: color, preferredSize: size, - type: type, ); } @@ -388,10 +305,8 @@ class RenderTriangle extends RenderBox { RenderTriangle({ required Color color, required Size preferredSize, - required TooltipType type, }) : _color = color, - _preferredSize = preferredSize, - _type = type; + _preferredSize = preferredSize; Color _color; Color get color => _color; @@ -408,8 +323,6 @@ class RenderTriangle extends RenderBox { markNeedsLayout(); } - final TooltipType _type; - @override void performLayout() { size = constraints.constrain(_preferredSize); @@ -422,21 +335,11 @@ class RenderTriangle extends RenderBox { ..color = color ..style = PaintingStyle.fill; - Path path; - switch (_type) { - case TooltipType.top: - path = Path() - ..moveTo(0, 0) - ..lineTo(size.width, 0) - ..lineTo(size.width / 2, size.height) - ..close(); - case TooltipType.right: - path = Path() - ..moveTo(0, size.height / 2) - ..lineTo(size.width, 0) - ..lineTo(size.width, size.height) - ..close(); - } + final path = Path() + ..moveTo(0, 0) + ..lineTo(size.width, 0) + ..lineTo(size.width / 2, size.height) + ..close(); context.canvas.drawPath(path, paint); } @@ -444,50 +347,3 @@ class RenderTriangle extends RenderBox { @override bool get isRepaintBoundary => true; } - -Offset _positionDependentBox({ - required TooltipType type, - required Size size, - required Size childSize, - required Offset target, - required bool preferBelow, - double verticalOffset = 0.0, - double horizontalOffset = 0.0, - double margin = 10.0, -}) { - switch (type) { - case TooltipType.top: - // VERTICAL DIRECTION - final bool fitsBelow = - target.dy + verticalOffset + childSize.height <= size.height - margin; - final bool fitsAbove = - target.dy - verticalOffset - childSize.height >= margin; - final bool tooltipBelow = fitsAbove == fitsBelow - ? preferBelow - : fitsBelow; - final double y; - if (tooltipBelow) { - y = math.min(target.dy + verticalOffset, size.height - margin); - } else { - y = math.max(target.dy - verticalOffset - childSize.height, margin); - } // HORIZONTAL DIRECTION - final double flexibleSpace = size.width - childSize.width; - final double x = flexibleSpace <= 2 * margin - // If there's not enough horizontal space for margin + child, center the - // child. - ? flexibleSpace / 2.0 - : clampDouble( - target.dx - childSize.width / 2, - margin, - flexibleSpace - margin, - ); - return Offset(x, y); - case TooltipType.right: - final double dy = math.max(margin, target.dy - childSize.height / 2); - final double dx = math.min( - target.dx + horizontalOffset, - size.width - childSize.width - margin, - ); - return Offset(dx, dy); - } -} diff --git a/lib/pages/common/slide/common_slide_page.dart b/lib/pages/common/slide/common_slide_page.dart index a991e9906..66c54b03b 100644 --- a/lib/pages/common/slide/common_slide_page.dart +++ b/lib/pages/common/slide/common_slide_page.dart @@ -40,12 +40,12 @@ mixin CommonSlideMixin on State, TickerProvider { final isRTL = dx >= _maxWidth - offset; if (isLTR || isRTL) { _isRTL = isRTL; - _downDx = dx; return true; } return false; }, ) + ..onStart = _onDragStart ..onUpdate = _onDragUpdate ..onEnd = _onDragEnd ..onCancel = _onDragEnd; @@ -101,6 +101,10 @@ mixin CommonSlideMixin on State, TickerProvider { _downDx = null; } + void _onDragStart(DragStartDetails details) { + _downDx = details.localPosition.dx; + } + void _onDragUpdate(DragUpdateDetails details) { final from = _downDx!; final to = details.localPosition.dx; diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 6a385775e..b35962e4e 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -1344,13 +1344,13 @@ class _VideoDetailPageVState extends State required double height, bool isPipMode = false, }) => PopScope( + key: videoDetailController.videoPlayerKey, canPop: !isFullScreen && !videoDetailController.plPlayerController.isDesktopPip && (videoDetailController.horizontalScreen || isPortrait), onPopInvokedWithResult: _onPopInvokedWithResult, child: Obx( - key: videoDetailController.videoPlayerKey, () => videoDetailController.videoState.value is! Success || !videoDetailController.autoPlay.value || diff --git a/lib/utils/reply_utils.dart b/lib/utils/reply_utils.dart index 41a7413b8..c1cf9702a 100644 --- a/lib/utils/reply_utils.dart +++ b/lib/utils/reply_utils.dart @@ -98,46 +98,47 @@ abstract final class ReplyUtils { await Future.delayed(const Duration(seconds: 8)); } void showReplyCheckResult(String message, {bool isBan = false}) { + final actions = [ + if (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?${Utils.themeUrl(Get.isDarkMode)}', + }, + ); + }, + child: const Text('申诉'), + ), + if (!isManual) + TextButton( + onPressed: Get.back, + child: Text( + '关闭', + style: TextStyle(color: Get.theme.colorScheme.outline), + ), + ), + ]; showDialog( context: Get.context!, barrierDismissible: isManual, builder: (context) => AlertDialog( title: const Text('评论检查结果'), content: SelectableText(message), - actions: [ - if (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?${Utils.themeUrl(Get.isDarkMode)}', - }, - ); - }, - child: const Text('申诉'), - ), - if (!isManual) - TextButton( - onPressed: Get.back, - child: Text( - '关闭', - style: TextStyle(color: Get.theme.colorScheme.outline), - ), - ), - ], + actions: actions.isEmpty ? null : actions, ), ); } diff --git a/lib/utils/request_utils.dart b/lib/utils/request_utils.dart index 6118c1dd0..a215116fe 100644 --- a/lib/utils/request_utils.dart +++ b/lib/utils/request_utils.dart @@ -316,6 +316,31 @@ abstract final class RequestUtils { clearCookie: true, ); final isSuccess = res.isSuccess; + final actions = [ + if (!isSuccess) + TextButton( + onPressed: () { + Get.back(); + Utils.copyText('https://www.bilibili.com/opus/$id'); + Get.toNamed( + '/webview', + parameters: { + 'url': + 'https://www.bilibili.com/h5/comment/appeal?${Utils.themeUrl(Get.isDarkMode)}', + }, + ); + }, + child: const Text('申诉'), + ), + if (!isManual) + TextButton( + onPressed: Get.back, + child: Text( + '关闭', + style: TextStyle(color: Get.theme.colorScheme.outline), + ), + ), + ]; showDialog( context: Get.context!, barrierDismissible: isManual, @@ -324,31 +349,7 @@ abstract final class RequestUtils { content: SelectableText( '${isSuccess ? '无账号状态下找到了你的动态,动态正常!' : '你的动态被shadow ban(仅自己可见)!'}${dynText != null ? ' \n\n动态内容: $dynText' : ''}', ), - actions: [ - if (!isSuccess) - TextButton( - onPressed: () { - Get.back(); - Utils.copyText('https://www.bilibili.com/opus/$id'); - Get.toNamed( - '/webview', - parameters: { - 'url': - 'https://www.bilibili.com/h5/comment/appeal?${Utils.themeUrl(Get.isDarkMode)}', - }, - ); - }, - child: const Text('申诉'), - ), - if (!isManual) - TextButton( - onPressed: Get.back, - child: Text( - '关闭', - style: TextStyle(color: Get.theme.colorScheme.outline), - ), - ), - ], + actions: actions.isEmpty ? null : actions, ), ); }