feat: at user

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-06-24 21:01:30 +08:00
parent fcf758e290
commit 7be3774675
35 changed files with 14468 additions and 207 deletions

View File

@@ -0,0 +1,236 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// @docImport 'package:flutter/material.dart';
library;
import 'package:PiliPlus/common/widgets/text_field/editable_text.dart';
import 'package:flutter/cupertino.dart' hide EditableText, EditableTextState;
import 'package:flutter/foundation.dart' show defaultTargetPlatform;
import 'package:flutter/rendering.dart';
/// The default Cupertino context menu for text selection for the current
/// platform with the given children.
///
/// {@template flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.platforms}
/// Builds the mobile Cupertino context menu on all mobile platforms, not just
/// iOS, and builds the desktop Cupertino context menu on all desktop platforms,
/// not just MacOS. For a widget that builds the native-looking context menu for
/// all platforms, see [AdaptiveTextSelectionToolbar].
/// {@endtemplate}
///
/// See also:
///
/// * [AdaptiveTextSelectionToolbar], which does the same thing as this widget
/// but for all platforms, not just the Cupertino-styled platforms.
/// * [CupertinoAdaptiveTextSelectionToolbar.getAdaptiveButtons], which builds
/// the Cupertino button Widgets for the current platform given
/// [ContextMenuButtonItem]s.
class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget {
/// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the
/// given [children].
///
/// See also:
///
/// {@template flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.buttonItems}
/// * [CupertinoAdaptiveTextSelectionToolbar.buttonItems], which takes a list
/// of [ContextMenuButtonItem]s instead of [children] widgets.
/// {@endtemplate}
/// {@template flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.editable}
/// * [CupertinoAdaptiveTextSelectionToolbar.editable], which builds the
/// default Cupertino children for an editable field.
/// {@endtemplate}
/// {@template flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.editableText}
/// * [CupertinoAdaptiveTextSelectionToolbar.editableText], which builds the
/// default Cupertino children for an [EditableText].
/// {@endtemplate}
/// {@template flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.selectable}
/// * [CupertinoAdaptiveTextSelectionToolbar.selectable], which builds the
/// Cupertino children for content that is selectable but not editable.
/// {@endtemplate}
const CupertinoAdaptiveTextSelectionToolbar({
super.key,
required this.children,
required this.anchors,
}) : buttonItems = null;
/// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] whose
/// children will be built from the given [buttonItems].
///
/// See also:
///
/// {@template flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.new}
/// * [CupertinoAdaptiveTextSelectionToolbar.new], which takes the children
/// directly as a list of widgets.
/// {@endtemplate}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.editable}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.editableText}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.selectable}
const CupertinoAdaptiveTextSelectionToolbar.buttonItems({
super.key,
required this.buttonItems,
required this.anchors,
}) : children = null;
/// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the
/// default children for an editable field.
///
/// If a callback is null, then its corresponding button will not be built.
///
/// See also:
///
/// * [AdaptiveTextSelectionToolbar.editable], which is similar to this but
/// includes Material and Cupertino toolbars.
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.new}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.editableText}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.buttonItems}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.selectable}
CupertinoAdaptiveTextSelectionToolbar.editable({
super.key,
required ClipboardStatus clipboardStatus,
required VoidCallback? onCopy,
required VoidCallback? onCut,
required VoidCallback? onPaste,
required VoidCallback? onSelectAll,
required VoidCallback? onLookUp,
required VoidCallback? onSearchWeb,
required VoidCallback? onShare,
required VoidCallback? onLiveTextInput,
required this.anchors,
}) : children = null,
buttonItems = EditableText.getEditableButtonItems(
clipboardStatus: clipboardStatus,
onCopy: onCopy,
onCut: onCut,
onPaste: onPaste,
onSelectAll: onSelectAll,
onLookUp: onLookUp,
onSearchWeb: onSearchWeb,
onShare: onShare,
onLiveTextInput: onLiveTextInput,
);
/// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the
/// default children for an [EditableText].
///
/// See also:
///
/// * [AdaptiveTextSelectionToolbar.editableText], which is similar to this
/// but includes Material and Cupertino toolbars.
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.new}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.editable}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.buttonItems}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.selectable}
CupertinoAdaptiveTextSelectionToolbar.editableText({
super.key,
required EditableTextState editableTextState,
}) : children = null,
buttonItems = editableTextState.contextMenuButtonItems,
anchors = editableTextState.contextMenuAnchors;
/// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the
/// default children for selectable, but not editable, content.
///
/// See also:
///
/// * [AdaptiveTextSelectionToolbar.selectable], which is similar to this but
/// includes Material and Cupertino toolbars.
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.new}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.buttonItems}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.editable}
/// {@macro flutter.cupertino.CupertinoAdaptiveTextSelectionToolbar.editableText}
CupertinoAdaptiveTextSelectionToolbar.selectable({
super.key,
required VoidCallback onCopy,
required VoidCallback onSelectAll,
required SelectionGeometry selectionGeometry,
required this.anchors,
}) : children = null,
buttonItems = SelectableRegion.getSelectableButtonItems(
selectionGeometry: selectionGeometry,
onCopy: onCopy,
onSelectAll: onSelectAll,
onShare:
null, // See https://github.com/flutter/flutter/issues/141775.
);
/// {@macro flutter.material.AdaptiveTextSelectionToolbar.anchors}
final TextSelectionToolbarAnchors anchors;
/// The children of the toolbar, typically buttons.
final List<Widget>? children;
/// The [ContextMenuButtonItem]s that will be turned into the correct button
/// widgets for the current platform.
final List<ContextMenuButtonItem>? buttonItems;
/// Returns a List of Widgets generated by turning [buttonItems] into the
/// default context menu buttons for Cupertino on the current platform.
///
/// This is useful when building a text selection toolbar with the default
/// button appearance for the given platform, but where the toolbar and/or the
/// button actions and labels may be custom.
///
/// Does not build Material buttons. On non-Apple platforms, Cupertino buttons
/// will still be used, because the Cupertino library does not access the
/// Material library. To get the native-looking buttons on every platform,
/// use [AdaptiveTextSelectionToolbar.getAdaptiveButtons] in the Material
/// library.
///
/// See also:
///
/// * [AdaptiveTextSelectionToolbar.getAdaptiveButtons], which is the Material
/// equivalent of this class and builds only the Material buttons. It
/// includes a live example of using `getAdaptiveButtons`.
static Iterable<Widget> getAdaptiveButtons(
BuildContext context,
List<ContextMenuButtonItem> buttonItems,
) {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.iOS:
return buttonItems.map((ContextMenuButtonItem buttonItem) {
return CupertinoTextSelectionToolbarButton.buttonItem(
buttonItem: buttonItem);
});
case TargetPlatform.linux:
case TargetPlatform.windows:
case TargetPlatform.macOS:
return buttonItems.map((ContextMenuButtonItem buttonItem) {
return CupertinoDesktopTextSelectionToolbarButton.buttonItem(
buttonItem: buttonItem);
});
}
}
@override
Widget build(BuildContext context) {
// If there aren't any buttons to build, build an empty toolbar.
if ((children?.isEmpty ?? false) || (buttonItems?.isEmpty ?? false)) {
return const SizedBox.shrink();
}
final List<Widget> resultChildren =
children ?? getAdaptiveButtons(context, buttonItems!).toList();
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
case TargetPlatform.fuchsia:
return CupertinoTextSelectionToolbar(
anchorAbove: anchors.primaryAnchor,
anchorBelow: anchors.secondaryAnchor ?? anchors.primaryAnchor,
children: resultChildren,
);
case TargetPlatform.linux:
case TargetPlatform.windows:
case TargetPlatform.macOS:
return CupertinoDesktopTextSelectionToolbar(
anchor: anchors.primaryAnchor,
children: resultChildren,
);
}
}
}

View File

@@ -0,0 +1,162 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// @docImport 'package:flutter/material.dart';
library;
import 'package:PiliPlus/common/widgets/text_field/editable_text.dart';
import 'package:flutter/cupertino.dart' hide EditableText, EditableTextState;
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart'
show SelectionChangedCause, SuggestionSpan;
/// iOS only shows 3 spell check suggestions in the toolbar.
const int _kMaxSuggestions = 3;
/// The default spell check suggestions toolbar for iOS.
///
/// Tries to position itself below the [anchors], but if it doesn't fit, then it
/// readjusts to fit above bottom view insets.
///
/// See also:
/// * [SpellCheckSuggestionsToolbar], which is similar but for both the
/// Material and Cupertino libraries.
class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget {
/// Constructs a [CupertinoSpellCheckSuggestionsToolbar].
///
/// [buttonItems] must not contain more than three items.
const CupertinoSpellCheckSuggestionsToolbar({
super.key,
required this.anchors,
required this.buttonItems,
}) : assert(buttonItems.length <= _kMaxSuggestions);
/// Constructs a [CupertinoSpellCheckSuggestionsToolbar] with the default
/// children for an [EditableText].
///
/// See also:
/// * [SpellCheckSuggestionsToolbar.editableText], which is similar but
/// builds an Android-style toolbar.
CupertinoSpellCheckSuggestionsToolbar.editableText({
super.key,
required EditableTextState editableTextState,
}) : buttonItems =
buildButtonItems(editableTextState) ?? <ContextMenuButtonItem>[],
anchors = editableTextState.contextMenuAnchors;
/// The location on which to anchor the menu.
final TextSelectionToolbarAnchors anchors;
/// The [ContextMenuButtonItem]s that will be turned into the correct button
/// widgets and displayed in the spell check suggestions toolbar.
///
/// Must not contain more than three items.
///
/// See also:
///
/// * [AdaptiveTextSelectionToolbar.buttonItems], the list of
/// [ContextMenuButtonItem]s that are used to build the buttons of the
/// text selection toolbar.
/// * [SpellCheckSuggestionsToolbar.buttonItems], the list of
/// [ContextMenuButtonItem]s used to build the Material style spell check
/// suggestions toolbar.
final List<ContextMenuButtonItem> buttonItems;
/// Builds the button items for the toolbar based on the available
/// spell check suggestions.
static List<ContextMenuButtonItem>? buildButtonItems(
EditableTextState editableTextState) {
// Determine if composing region is misspelled.
final SuggestionSpan? spanAtCursorIndex =
editableTextState.findSuggestionSpanAtCursorIndex(
editableTextState.currentTextEditingValue.selection.baseOffset,
);
if (spanAtCursorIndex == null) {
return null;
}
if (spanAtCursorIndex.suggestions.isEmpty) {
assert(debugCheckHasCupertinoLocalizations(editableTextState.context));
final CupertinoLocalizations localizations = CupertinoLocalizations.of(
editableTextState.context,
);
return <ContextMenuButtonItem>[
ContextMenuButtonItem(
onPressed: null,
label: localizations.noSpellCheckReplacementsLabel),
];
}
final List<ContextMenuButtonItem> buttonItems = <ContextMenuButtonItem>[];
// Build suggestion buttons.
for (final String suggestion
in spanAtCursorIndex.suggestions.take(_kMaxSuggestions)) {
buttonItems.add(
ContextMenuButtonItem(
onPressed: () {
if (!editableTextState.mounted) {
return;
}
_replaceText(
editableTextState, suggestion, spanAtCursorIndex.range);
},
label: suggestion,
),
);
}
return buttonItems;
}
static void _replaceText(
EditableTextState editableTextState,
String text,
TextRange replacementRange,
) {
// Replacement cannot be performed if the text is read only or obscured.
assert(!editableTextState.widget.readOnly &&
!editableTextState.widget.obscureText);
final TextEditingValue newValue = editableTextState.textEditingValue
.replaced(replacementRange, text)
.copyWith(
selection: TextSelection.collapsed(
offset: replacementRange.start + text.length));
editableTextState.userUpdateTextEditingValue(
newValue, SelectionChangedCause.toolbar);
// Schedule a call to bringIntoView() after renderEditable updates.
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
if (editableTextState.mounted) {
editableTextState
.bringIntoView(editableTextState.textEditingValue.selection.extent);
}
}, debugLabel: 'SpellCheckSuggestions.bringIntoView');
editableTextState.hideToolbar();
}
/// Builds the toolbar buttons based on the [buttonItems].
List<Widget> _buildToolbarButtons(BuildContext context) {
return buttonItems.map((ContextMenuButtonItem buttonItem) {
return CupertinoTextSelectionToolbarButton.buttonItem(
buttonItem: buttonItem);
}).toList();
}
@override
Widget build(BuildContext context) {
if (buttonItems.isEmpty) {
return const SizedBox.shrink();
}
final List<Widget> children = _buildToolbarButtons(context);
return CupertinoTextSelectionToolbar(
anchorAbove: anchors.primaryAnchor,
anchorBelow: anchors.secondaryAnchor == null
? anchors.primaryAnchor
: anchors.secondaryAnchor!,
children: children,
);
}
}

File diff suppressed because it is too large Load Diff