mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-26 21:40:11 +08:00
@@ -11,7 +11,7 @@ Widget dynTextMenuBuilder(
|
|||||||
ContextMenuButtonItem(
|
ContextMenuButtonItem(
|
||||||
label: '文本',
|
label: '文本',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
state.hideToolbar();
|
state.hideAndClear();
|
||||||
_showTextDialog(text);
|
_showTextDialog(text);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -21,9 +21,7 @@ Widget dynTextMenuBuilder(
|
|||||||
ContextMenuButtonItem(
|
ContextMenuButtonItem(
|
||||||
label: '表情',
|
label: '表情',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
state
|
state.hideAndClear();
|
||||||
..hideToolbar()
|
|
||||||
..clearSelection();
|
|
||||||
_showEmoteDialog(moduleDynamic);
|
_showEmoteDialog(moduleDynamic);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
40
lib/common/widgets/context_menu/live_menu_helper.dart
Normal file
40
lib/common/widgets/context_menu/live_menu_helper.dart
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
part of 'package:PiliPlus/pages/live_room/superchat/superchat_card.dart';
|
||||||
|
|
||||||
|
Widget scMenuBuilder(
|
||||||
|
BuildContext context,
|
||||||
|
SelectableRegionState state,
|
||||||
|
) {
|
||||||
|
final buttonItems = state.contextMenuButtonItems;
|
||||||
|
if (state.isUncollapsed) {
|
||||||
|
buttonItems
|
||||||
|
..insertOrAdd(
|
||||||
|
3,
|
||||||
|
ContextMenuButtonItem(
|
||||||
|
label: '视频',
|
||||||
|
onPressed: () {
|
||||||
|
state.onMenuPressed(
|
||||||
|
(text) => PiliScheme.videoPush(null, text),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
..insertOrAdd(
|
||||||
|
4,
|
||||||
|
ContextMenuButtonItem(
|
||||||
|
label: '搜索',
|
||||||
|
onPressed: () {
|
||||||
|
state.onMenuPressed(
|
||||||
|
(text) => Get.toNamed(
|
||||||
|
'/searchResult',
|
||||||
|
parameters: {'keyword': text},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||||
|
buttonItems: buttonItems,
|
||||||
|
anchors: state.contextMenuAnchors,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -46,9 +46,7 @@ void showReplyCopyDialog(
|
|||||||
ContextMenuButtonItem(
|
ContextMenuButtonItem(
|
||||||
label: showEmote ? '文本' : '表情',
|
label: showEmote ? '文本' : '表情',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
state
|
state.hideAndClear();
|
||||||
..hideToolbar()
|
|
||||||
..clearSelection();
|
|
||||||
showEmote = !showEmote;
|
showEmote = !showEmote;
|
||||||
(context as Element).markNeedsBuild();
|
(context as Element).markNeedsBuild();
|
||||||
},
|
},
|
||||||
@@ -58,55 +56,49 @@ void showReplyCopyDialog(
|
|||||||
state.addLaunchMenuIfNeeded(buttonItems, index: 4);
|
state.addLaunchMenuIfNeeded(buttonItems, index: 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
if (state.isUncollapsed) {
|
||||||
if (state.selectionEndpoints.first !=
|
buttonItems.add(
|
||||||
state.selectionEndpoints[1]) {
|
ContextMenuButtonItem(
|
||||||
buttonItems.add(
|
onPressed: () {
|
||||||
ContextMenuButtonItem(
|
String text = RegExp.escape(state.selectedText!);
|
||||||
onPressed: () {
|
if (ReplyGrpc.enableFilter) text = '|$text';
|
||||||
final selectedText = (state as dynamic).selectable
|
|
||||||
?.getSelectedContent()
|
|
||||||
?.plainText;
|
|
||||||
String text = RegExp.escape(selectedText);
|
|
||||||
if (ReplyGrpc.enableFilter) text = '|$text';
|
|
||||||
|
|
||||||
showConfirmDialog(
|
showConfirmDialog(
|
||||||
context: context,
|
context: context,
|
||||||
title: const Text('是否确认评论过滤的变更:'),
|
title: const Text('是否确认评论过滤的变更:'),
|
||||||
content: Text.rich(
|
content: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: ReplyGrpc.replyRegExp.pattern,
|
text: ReplyGrpc.replyRegExp.pattern,
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: text,
|
text: text,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.green,
|
color: Colors.green,
|
||||||
fontWeight: .bold,
|
fontWeight: .bold,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
onConfirm: () {
|
),
|
||||||
final filter = ReplyGrpc.replyRegExp.pattern + text;
|
onConfirm: () {
|
||||||
ReplyGrpc.replyRegExp = RegExp(
|
final filter = ReplyGrpc.replyRegExp.pattern + text;
|
||||||
filter,
|
ReplyGrpc.replyRegExp = RegExp(
|
||||||
caseSensitive: true,
|
filter,
|
||||||
);
|
caseSensitive: true,
|
||||||
ReplyGrpc.enableFilter = true;
|
);
|
||||||
GStorage.setting.put(
|
ReplyGrpc.enableFilter = true;
|
||||||
SettingBoxKey.banWordForReply,
|
GStorage.setting.put(
|
||||||
filter,
|
SettingBoxKey.banWordForReply,
|
||||||
);
|
filter,
|
||||||
SmartDialog.showToast('已保存');
|
);
|
||||||
},
|
SmartDialog.showToast('已保存');
|
||||||
);
|
},
|
||||||
},
|
);
|
||||||
label: '加入过滤',
|
},
|
||||||
),
|
label: '加入过滤',
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
} catch (_) {}
|
}
|
||||||
return AdaptiveTextSelectionToolbar.buttonItems(
|
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||||
buttonItems: buttonItems,
|
buttonItems: buttonItems,
|
||||||
anchors: state.contextMenuAnchors,
|
anchors: state.contextMenuAnchors,
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/selection_text.dart';
|
import 'package:PiliPlus/common/widgets/selection_text.dart';
|
||||||
import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
|
import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
|
||||||
import 'package:PiliPlus/pages/member/widget/medal_widget.dart';
|
import 'package:PiliPlus/pages/member/widget/medal_widget.dart';
|
||||||
|
import 'package:PiliPlus/utils/app_scheme.dart';
|
||||||
import 'package:PiliPlus/utils/color_utils.dart';
|
import 'package:PiliPlus/utils/color_utils.dart';
|
||||||
import 'package:PiliPlus/utils/date_utils.dart';
|
import 'package:PiliPlus/utils/date_utils.dart';
|
||||||
|
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
||||||
|
import 'package:PiliPlus/utils/extension/selectable_region_ext.dart';
|
||||||
import 'package:PiliPlus/utils/image_utils.dart';
|
import 'package:PiliPlus/utils/image_utils.dart';
|
||||||
import 'package:PiliPlus/utils/page_utils.dart';
|
import 'package:PiliPlus/utils/page_utils.dart';
|
||||||
import 'package:PiliPlus/utils/platform_utils.dart';
|
import 'package:PiliPlus/utils/platform_utils.dart';
|
||||||
@@ -15,6 +18,8 @@ import 'package:flutter/foundation.dart' show kDebugMode;
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
part 'package:PiliPlus/common/widgets/context_menu/live_menu_helper.dart';
|
||||||
|
|
||||||
class SuperChatCard extends StatefulWidget {
|
class SuperChatCard extends StatefulWidget {
|
||||||
const SuperChatCard({
|
const SuperChatCard({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -250,6 +255,7 @@ class _SuperChatCardState extends State<SuperChatCard> {
|
|||||||
),
|
),
|
||||||
child: SelectionText(
|
child: SelectionText(
|
||||||
item.message,
|
item.message,
|
||||||
|
contextMenuBuilder: scMenuBuilder,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: ColourUtils.parseColor(item.messageFontColor),
|
color: ColourUtils.parseColor(item.messageFontColor),
|
||||||
// decoration: widget.persistentSC && item.deleted
|
// decoration: widget.persistentSC && item.deleted
|
||||||
|
|||||||
@@ -15,18 +15,21 @@ index 97a41dafb8d..70c55832625 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart
|
diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart
|
||||||
index 59de8bae20b..525bb76c064 100644
|
index 59de8bae20b..17220a77d04 100644
|
||||||
--- a/packages/flutter/lib/src/widgets/selectable_region.dart
|
--- a/packages/flutter/lib/src/widgets/selectable_region.dart
|
||||||
+++ b/packages/flutter/lib/src/widgets/selectable_region.dart
|
+++ b/packages/flutter/lib/src/widgets/selectable_region.dart
|
||||||
@@ -404,6 +404,7 @@ class SelectableRegionState extends State<SelectableRegion>
|
@@ -402,8 +402,10 @@ class SelectableRegionState extends State<SelectableRegion>
|
||||||
|
final LayerLink _endHandleLayerLink = LayerLink();
|
||||||
|
final LayerLink _toolbarLayerLink = LayerLink();
|
||||||
final StaticSelectionContainerDelegate _selectionDelegate = StaticSelectionContainerDelegate();
|
final StaticSelectionContainerDelegate _selectionDelegate = StaticSelectionContainerDelegate();
|
||||||
|
+ StaticSelectionContainerDelegate get selectionDelegate => _selectionDelegate;
|
||||||
// there should only ever be one selectable, which is the SelectionContainer.
|
// there should only ever be one selectable, which is the SelectionContainer.
|
||||||
Selectable? _selectable;
|
Selectable? _selectable;
|
||||||
+ Selectable? get selectable => _selectable;
|
+ Selectable? get selectable => _selectable;
|
||||||
|
|
||||||
bool get _hasSelectionOverlayGeometry =>
|
bool get _hasSelectionOverlayGeometry =>
|
||||||
_selectionDelegate.value.startSelectionPoint != null ||
|
_selectionDelegate.value.startSelectionPoint != null ||
|
||||||
@@ -599,48 +600,32 @@ class SelectableRegionState extends State<SelectableRegion>
|
@@ -599,48 +601,32 @@ class SelectableRegionState extends State<SelectableRegion>
|
||||||
//
|
//
|
||||||
// This method should be used in all instances when details.consecutiveTapCount
|
// This method should be used in all instances when details.consecutiveTapCount
|
||||||
// would be used.
|
// would be used.
|
||||||
@@ -94,7 +97,7 @@ index 59de8bae20b..525bb76c064 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,22 +767,8 @@ class SelectableRegionState extends State<SelectableRegion>
|
@@ -782,22 +768,8 @@ class SelectableRegionState extends State<SelectableRegion>
|
||||||
_selectionStatusNotifier.value = SelectableRegionSelectionStatus.changing;
|
_selectionStatusNotifier.value = SelectableRegionSelectionStatus.changing;
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
@@ -119,7 +122,7 @@ index 59de8bae20b..525bb76c064 100644
|
|||||||
}
|
}
|
||||||
_updateSelectedContentIfNeeded();
|
_updateSelectedContentIfNeeded();
|
||||||
}
|
}
|
||||||
@@ -1049,10 +1020,10 @@ class SelectableRegionState extends State<SelectableRegion>
|
@@ -1049,10 +1021,10 @@ class SelectableRegionState extends State<SelectableRegion>
|
||||||
case TargetPlatform.windows:
|
case TargetPlatform.windows:
|
||||||
// If _lastSecondaryTapDownPosition is within the current selection then
|
// If _lastSecondaryTapDownPosition is within the current selection then
|
||||||
// keep the current selection, if not then collapse it.
|
// keep the current selection, if not then collapse it.
|
||||||
@@ -134,7 +137,7 @@ index 59de8bae20b..525bb76c064 100644
|
|||||||
// Restore _lastSecondaryTapDownPosition since it may be cleared if a user
|
// Restore _lastSecondaryTapDownPosition since it may be cleared if a user
|
||||||
// accesses contextMenuAnchors.
|
// accesses contextMenuAnchors.
|
||||||
_lastSecondaryTapDownPosition = details.globalPosition;
|
_lastSecondaryTapDownPosition = details.globalPosition;
|
||||||
@@ -1957,6 +1928,8 @@ class SelectableRegionState extends State<SelectableRegion>
|
@@ -1957,6 +1929,8 @@ class SelectableRegionState extends State<SelectableRegion>
|
||||||
// the region on non-web platforms.
|
// the region on non-web platforms.
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
_focusNode.unfocus();
|
_focusNode.unfocus();
|
||||||
@@ -143,7 +146,7 @@ index 59de8bae20b..525bb76c064 100644
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: CompositedTransformTarget(
|
child: CompositedTransformTarget(
|
||||||
@@ -2822,7 +2795,10 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai
|
@@ -2822,7 +2796,10 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final buffer = StringBuffer();
|
final buffer = StringBuffer();
|
||||||
|
|||||||
@@ -1,32 +1,52 @@
|
|||||||
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
||||||
import 'package:PiliPlus/utils/page_utils.dart';
|
import 'package:PiliPlus/utils/page_utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart' show Selectable;
|
||||||
|
|
||||||
extension SelectableRegionStateExt on SelectableRegionState {
|
extension SelectableRegionStateExt on SelectableRegionState {
|
||||||
void addLaunchMenuIfNeeded(
|
void addLaunchMenuIfNeeded(
|
||||||
List<ContextMenuButtonItem> buttonItems, {
|
List<ContextMenuButtonItem> buttonItems, {
|
||||||
required int index,
|
required int index,
|
||||||
}) {
|
}) {
|
||||||
try {
|
if (isUncollapsed) {
|
||||||
if (selectionEndpoints.first != selectionEndpoints[1]) {
|
buttonItems.insertOrAdd(
|
||||||
buttonItems.insertOrAdd(
|
index,
|
||||||
index,
|
ContextMenuButtonItem(
|
||||||
ContextMenuButtonItem(
|
label: '打开',
|
||||||
label: '打开',
|
onPressed: () {
|
||||||
onPressed: () {
|
onMenuPressed(
|
||||||
final text = (this as dynamic).selectable
|
PageUtils.launchURL,
|
||||||
?.getSelectedContent()
|
content: () => selectedText?.trim(),
|
||||||
?.plainText
|
);
|
||||||
.trim();
|
},
|
||||||
hideToolbar();
|
),
|
||||||
clearSelection();
|
);
|
||||||
if (text != null && text.isNotEmpty) {
|
}
|
||||||
PageUtils.launchURL(text);
|
}
|
||||||
}
|
|
||||||
},
|
String? get selectedText => ((this as dynamic).selectable as Selectable?)
|
||||||
),
|
?.getSelectedContent()
|
||||||
);
|
?.plainText;
|
||||||
}
|
|
||||||
} catch (_) {}
|
bool get isUncollapsed =>
|
||||||
|
((this as dynamic).selectionDelegate as StaticSelectionContainerDelegate)
|
||||||
|
.value
|
||||||
|
.status ==
|
||||||
|
.uncollapsed;
|
||||||
|
|
||||||
|
void onMenuPressed(
|
||||||
|
ValueChanged<String> callback, {
|
||||||
|
ValueGetter<String?>? content,
|
||||||
|
}) {
|
||||||
|
final text = content?.call() ?? selectedText;
|
||||||
|
hideAndClear();
|
||||||
|
if (text != null && text.isNotEmpty) {
|
||||||
|
callback(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hideAndClear() {
|
||||||
|
hideToolbar();
|
||||||
|
clearSelection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user