sync flutter widgets

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-02-12 11:01:35 +08:00
parent fbf7116edf
commit 483953cf56
31 changed files with 804 additions and 646 deletions

View File

@@ -12,7 +12,7 @@ import 'package:flutter/gestures.dart'
BaseTapAndDragGestureRecognizer,
TapAndHorizontalDragGestureRecognizer,
TapAndPanGestureRecognizer;
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide SelectableRegion;
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
@@ -277,26 +277,28 @@ class SelectableRegion extends StatefulWidget {
required final VoidCallback onSelectAll,
required final VoidCallback? onShare,
}) {
final bool canCopy =
selectionGeometry.status == SelectionStatus.uncollapsed;
final canCopy = selectionGeometry.status == SelectionStatus.uncollapsed;
final bool canSelectAll = selectionGeometry.hasContent;
final bool platformCanShare = switch (defaultTargetPlatform) {
TargetPlatform.android =>
selectionGeometry.status == SelectionStatus.uncollapsed,
TargetPlatform.macOS ||
TargetPlatform.fuchsia ||
TargetPlatform.linux ||
TargetPlatform.windows => false,
// TODO(bleroux): the share button should be shown on iOS but the share
// functionality requires some changes on the engine side because, on iPad,
// it needs an anchor for the popup.
// See: https://github.com/flutter/flutter/issues/141775.
TargetPlatform.iOS => false,
};
// The share button is not supported on the web.
final bool platformCanShare =
!kIsWeb &&
switch (defaultTargetPlatform) {
TargetPlatform.android =>
selectionGeometry.status == SelectionStatus.uncollapsed,
TargetPlatform.macOS ||
TargetPlatform.fuchsia ||
TargetPlatform.linux ||
TargetPlatform.windows => false,
// TODO(bleroux): the share button should be shown on iOS but the share
// functionality requires some changes on the engine side because, on iPad,
// it needs an anchor for the popup.
// See: https://github.com/flutter/flutter/issues/141775.
TargetPlatform.iOS => false,
};
final bool canShare = onShare != null && platformCanShare;
// On Android, the share button is before the select all button.
final bool showShareBeforeSelectAll =
final showShareBeforeSelectAll =
defaultTargetPlatform == TargetPlatform.android;
// Determine which buttons will appear so that the order and total number is
@@ -410,6 +412,16 @@ class SelectableRegionState extends State<SelectableRegion>
Orientation? _lastOrientation;
SelectedContent? _lastSelectedContent;
/// Whether the native browser context menu is enabled.
// TODO(Renzo-Olivares): Re-enable web context menu for Android
// and iOS when https://github.com/flutter/flutter/issues/177123
// is resolved.
bool get _webContextMenuEnabled =>
kIsWeb &&
BrowserContextMenu.enabled &&
defaultTargetPlatform != TargetPlatform.android &&
defaultTargetPlatform != TargetPlatform.iOS;
/// The [SelectionOverlay] that is currently visible on the screen.
///
/// Can be null if there is no visible [SelectionOverlay].
@@ -513,7 +525,7 @@ class SelectableRegionState extends State<SelectableRegion>
void _handleFocusChanged() {
if (!_focusNode.hasFocus) {
if (kIsWeb) {
if (_webContextMenuEnabled) {
PlatformSelectableRegionContextMenu.detach(_selectionDelegate);
}
if (SchedulerBinding.instance.lifecycleState ==
@@ -531,7 +543,7 @@ class SelectableRegionState extends State<SelectableRegion>
_finalizeSelectableRegionStatus();
}
}
if (kIsWeb) {
if (_webContextMenuEnabled) {
PlatformSelectableRegionContextMenu.attach(_selectionDelegate);
}
}
@@ -596,7 +608,7 @@ class SelectableRegionState extends State<SelectableRegion>
// This method should be used in all instances when details.consecutiveTapCount
// would be used.
int _getEffectiveConsecutiveTapCount(int rawCount) {
int maxConsecutiveTap = 3;
var maxConsecutiveTap = 3;
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
@@ -1177,21 +1189,9 @@ class SelectableRegionState extends State<SelectableRegion>
_selectionOverlay != null &&
(_selectionOverlay!.isDraggingStartHandle ||
_selectionOverlay!.isDraggingEndHandle);
if (widget.selectionControls is! TextSelectionHandleControls) {
if (!draggingHandles) {
_selectionOverlay!.hideMagnifier();
_selectionOverlay!.showToolbar();
}
} else {
if (!draggingHandles) {
_selectionOverlay!.hideMagnifier();
_selectionOverlay!.showToolbar(
context: context,
contextMenuBuilder: (BuildContext context) {
return widget.contextMenuBuilder!(context, this);
},
);
}
if (!draggingHandles) {
_selectionOverlay!.hideMagnifier();
_showToolbar();
}
_finalizeSelection();
_updateSelectedContentIfNeeded();
@@ -1335,13 +1335,13 @@ class SelectableRegionState extends State<SelectableRegion>
final Vector3 globalTransform = _selectable!
.getTransformTo(null)
.getTranslation();
final Offset globalTransformAsOffset = Offset(
final globalTransformAsOffset = Offset(
globalTransform.x,
globalTransform.y,
);
final Offset globalSelectionPointPosition =
selectionPoint.localPosition + globalTransformAsOffset;
final Rect caretRect = Rect.fromLTWH(
final caretRect = Rect.fromLTWH(
globalSelectionPointPosition.dx,
globalSelectionPointPosition.dy - selectionPoint.lineHeight,
0,
@@ -1439,7 +1439,7 @@ class SelectableRegionState extends State<SelectableRegion>
// functionality depending on the browser (such as translate). Due to this,
// we should not show a Flutter toolbar for the editable text elements
// unless the browser's context menu is explicitly disabled.
if (kIsWeb && BrowserContextMenu.enabled) {
if (_webContextMenuEnabled) {
return false;
}
@@ -1448,6 +1448,9 @@ class SelectableRegionState extends State<SelectableRegion>
}
_selectionOverlay!.toolbarLocation = location;
// TODO(Renzo-Olivares): Remove the logic below that does a runtimeType
// check for TextSelectionHandleControls when TextSelectionHandleControls
// is fully removed, see: https://github.com/flutter/flutter/pull/124262.
if (widget.selectionControls is! TextSelectionHandleControls) {
_selectionOverlay!.showToolbar();
return true;
@@ -1683,7 +1686,7 @@ class SelectableRegionState extends State<SelectableRegion>
/// for the default context menu buttons.
TextSelectionToolbarAnchors get contextMenuAnchors {
if (_lastSecondaryTapDownPosition != null) {
final TextSelectionToolbarAnchors anchors = TextSelectionToolbarAnchors(
final anchors = TextSelectionToolbarAnchors(
primaryAnchor: _lastSecondaryTapDownPosition!,
);
// Clear the state of _lastSecondaryTapDownPosition after use since a user may
@@ -1691,7 +1694,7 @@ class SelectableRegionState extends State<SelectableRegion>
_lastSecondaryTapDownPosition = null;
return anchors;
}
final RenderBox renderBox = context.findRenderObject()! as RenderBox;
final renderBox = context.findRenderObject()! as RenderBox;
return TextSelectionToolbarAnchors.fromSelection(
renderBox: renderBox,
startGlyphHeight: startGlyphHeight,
@@ -1843,7 +1846,7 @@ class SelectableRegionState extends State<SelectableRegion>
}
List<ContextMenuButtonItem> get _textProcessingActionButtonItems {
final List<ContextMenuButtonItem> buttonItems = <ContextMenuButtonItem>[];
final buttonItems = <ContextMenuButtonItem>[];
final SelectedContent? data = _selectable?.getSelectedContent();
if (data == null) {
return buttonItems;
@@ -2048,7 +2051,7 @@ class SelectableRegionState extends State<SelectableRegion>
child: widget.child,
),
);
if (kIsWeb) {
if (_webContextMenuEnabled) {
result = PlatformSelectableRegionContextMenu(child: result);
}
return CompositedTransformTarget(

View File

@@ -8,7 +8,8 @@ import 'package:PiliPlus/common/widgets/flutter/selectable_text/text_selection.d
import 'package:flutter/cupertino.dart'
hide TextSelectionGestureDetectorBuilder;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart' hide TextSelectionGestureDetectorBuilder;
import 'package:flutter/material.dart'
hide SelectableText, TextSelectionGestureDetectorBuilder;
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
@@ -610,8 +611,9 @@ class _SelectableTextState extends State<SelectableText>
super.didUpdateWidget(oldWidget);
if (widget.data != oldWidget.data ||
widget.textSpan != oldWidget.textSpan) {
_controller.removeListener(_onControllerChanged);
_controller.dispose();
_controller
..removeListener(_onControllerChanged)
..dispose();
_controller = _TextSpanEditingController(
textSpan: widget.textSpan ?? TextSpan(text: widget.data),
);
@@ -766,7 +768,7 @@ class _SelectableTextState extends State<SelectableText>
cupertinoTheme.primaryColor;
selectionColor =
selectionStyle.selectionColor ??
cupertinoTheme.primaryColor.withOpacity(0.40);
cupertinoTheme.primaryColor.withValues(alpha: 0.40);
cursorRadius ??= const Radius.circular(2.0);
cursorOffset = Offset(
iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context),
@@ -785,7 +787,7 @@ class _SelectableTextState extends State<SelectableText>
cupertinoTheme.primaryColor;
selectionColor =
selectionStyle.selectionColor ??
cupertinoTheme.primaryColor.withOpacity(0.40);
cupertinoTheme.primaryColor.withValues(alpha: 0.40);
cursorRadius ??= const Radius.circular(2.0);
cursorOffset = Offset(
iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context),
@@ -804,7 +806,7 @@ class _SelectableTextState extends State<SelectableText>
theme.colorScheme.primary;
selectionColor =
selectionStyle.selectionColor ??
theme.colorScheme.primary.withOpacity(0.40);
theme.colorScheme.primary.withValues(alpha: 0.40);
case TargetPlatform.linux:
case TargetPlatform.windows:
@@ -818,7 +820,7 @@ class _SelectableTextState extends State<SelectableText>
theme.colorScheme.primary;
selectionColor =
selectionStyle.selectionColor ??
theme.colorScheme.primary.withOpacity(0.40);
theme.colorScheme.primary.withValues(alpha: 0.40);
}
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);

View File

@@ -10,6 +10,7 @@ import 'package:flutter/cupertino.dart'
SelectableRegionContextMenuBuilder;
import 'package:flutter/material.dart'
hide
SelectionArea,
SelectableRegion,
SelectableRegionState,
SelectableRegionContextMenuBuilder;

View File

@@ -5,7 +5,8 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/gestures.dart'
hide TapAndHorizontalDragGestureRecognizer;
// Examples can assume:
// void setState(VoidCallback fn) { }
@@ -823,7 +824,7 @@ sealed class BaseTapAndDragGestureRecognizer
untransformedDelta: localDelta,
untransformedEndPosition: correctedLocalPosition,
);
final OffsetPair updateDelta = OffsetPair(
final updateDelta = OffsetPair(
local: localDelta,
global: globalUpdateDelta,
);
@@ -870,7 +871,7 @@ sealed class BaseTapAndDragGestureRecognizer
return;
}
final TapDragDownDetails details = TapDragDownDetails(
final details = TapDragDownDetails(
globalPosition: event.position,
localPosition: event.localPosition,
kind: getKindForPointer(event.pointer),
@@ -889,7 +890,7 @@ sealed class BaseTapAndDragGestureRecognizer
return;
}
final TapDragUpDetails upDetails = TapDragUpDetails(
final upDetails = TapDragUpDetails(
kind: event.kind,
globalPosition: event.position,
localPosition: event.localPosition,
@@ -908,7 +909,7 @@ sealed class BaseTapAndDragGestureRecognizer
void _checkDragStart(PointerEvent event) {
if (onDragStart != null) {
final TapDragStartDetails details = TapDragStartDetails(
final details = TapDragStartDetails(
sourceTimeStamp: event.timeStamp,
globalPosition: _initialPosition.global,
localPosition: _initialPosition.local,
@@ -926,7 +927,7 @@ sealed class BaseTapAndDragGestureRecognizer
final Offset globalPosition = corrected?.global ?? event.position;
final Offset localPosition = corrected?.local ?? event.localPosition;
final TapDragUpdateDetails details = TapDragUpdateDetails(
final details = TapDragUpdateDetails(
sourceTimeStamp: event.timeStamp,
delta: event.localDelta,
globalPosition: globalPosition,
@@ -962,7 +963,7 @@ sealed class BaseTapAndDragGestureRecognizer
_handleDragUpdateThrottled();
}
final TapDragEndDetails endDetails = TapDragEndDetails(
final endDetails = TapDragEndDetails(
globalPosition: globalPosition,
localPosition: localPosition,
primaryVelocity: 0.0,

View File

@@ -11,7 +11,7 @@ import 'package:flutter/gestures.dart'
BaseTapAndDragGestureRecognizer,
TapAndHorizontalDragGestureRecognizer,
TapAndPanGestureRecognizer;
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide TextSelectionGestureDetector;
class CustomTextSelectionGestureDetectorBuilder
extends TextSelectionGestureDetectorBuilder {
@@ -310,8 +310,7 @@ class _TextSelectionGestureDetectorState
@override
Widget build(BuildContext context) {
final Map<Type, GestureRecognizerFactory> gestures =
<Type, GestureRecognizerFactory>{};
final gestures = <Type, GestureRecognizerFactory>{};
gestures[TapGestureRecognizer] =
GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(