feat(ui): Refactor context menu with platform-specific styling

feat(navigation): migrate to super_drag_and_drop for folder drag and drop
feat(ui): Add context menu preview builders for chat and notes
refactor(ui): Remove preview builders and simplify note card rendering
This commit is contained in:
cogwheel
2025-12-20 18:26:03 +05:30
parent 622dcf9142
commit 97ace86b12
13 changed files with 1032 additions and 724 deletions

View File

@@ -1817,18 +1817,15 @@ class _ChatPageState extends ConsumerState<ChatPage> {
),
);
} else if (displayConversationTitle != null) {
titlePill = GestureDetector(
onTap: () {
final conversation = ref.read(
activeConversationProvider,
);
if (conversation == null) return;
showConversationContextMenu(
context: context,
ref: ref,
conversation: conversation,
);
},
final conversation = ref.read(
activeConversationProvider,
);
titlePill = ConduitContextMenu(
actions: buildConversationActions(
context: context,
ref: ref,
conversation: conversation,
),
child: _buildAppBarPill(
context: context,
child: Padding(

View File

@@ -433,51 +433,32 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble> {
super.dispose();
}
Future<void> _showMessageMenu(BuildContext context) async {
// Don't show menu while editing - use the visible Save/Cancel buttons instead
if (_isEditing) return;
List<ConduitContextMenuAction> _buildMessageActions(BuildContext context) {
// Don't show menu while editing - return empty list
if (_isEditing) return [];
final l10n = AppLocalizations.of(context)!;
HapticFeedback.selectionClick();
// Get the position of the bubble to show menu below it
Offset? menuPosition;
final RenderBox? renderBox =
_bubbleKey.currentContext?.findRenderObject() as RenderBox?;
if (renderBox != null) {
final position = renderBox.localToGlobal(Offset.zero);
final size = renderBox.size;
// Position menu at bottom-right of the bubble
menuPosition = Offset(
position.dx + size.width,
position.dy + size.height,
);
}
await showConduitContextMenu(
context: context,
position: menuPosition,
actions: [
ConduitContextMenuAction(
cupertinoIcon: CupertinoIcons.pencil,
materialIcon: Icons.edit_outlined,
label: l10n.edit,
onBeforeClose: () => HapticFeedback.selectionClick(),
onSelected: () async => _startInlineEdit(),
),
ConduitContextMenuAction(
cupertinoIcon: CupertinoIcons.doc_on_clipboard,
materialIcon: Icons.content_copy,
label: l10n.copy,
onBeforeClose: () => HapticFeedback.selectionClick(),
onSelected: () async {
if (widget.onCopy != null) {
widget.onCopy!();
}
},
),
],
);
return [
ConduitContextMenuAction(
cupertinoIcon: CupertinoIcons.pencil,
materialIcon: Icons.edit_outlined,
label: l10n.edit,
onBeforeClose: () => HapticFeedback.selectionClick(),
onSelected: () async => _startInlineEdit(),
),
ConduitContextMenuAction(
cupertinoIcon: CupertinoIcons.doc_on_clipboard,
materialIcon: Icons.content_copy,
label: l10n.copy,
onBeforeClose: () => HapticFeedback.selectionClick(),
onSelected: () async {
if (widget.onCopy != null) {
widget.onCopy!();
}
},
),
];
}
@override
@@ -505,9 +486,8 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble> {
final isMultiline = content.length > 50 || content.contains('\n');
final bubbleRadius = isMultiline ? AppBorderRadius.xl : AppBorderRadius.pill;
return GestureDetector(
onLongPress: () => _showMessageMenu(context),
behavior: HitTestBehavior.translucent,
return ConduitContextMenu(
actions: _buildMessageActions(context),
child: Container(
width: double.infinity,
margin: const EdgeInsets.only(