fix(chat): voice bubble preview in action menu + popup positioning
- previewNode: add audio case → VoiceNoteBubble renders correctly in blur overlay when long-pressing a voice message (was rendering empty/null) - MessageActionMenu: account for input bar (bottomInset=90) in positioning — menu no longer slides behind input bar on bottom messages; barTop clamped to never overlap the menu; both above/below paths respect usableH Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
603ed9f392
commit
1dc4e4f9cd
@ -290,10 +290,13 @@ export function ChatBubble({
|
|||||||
{ backgroundColor: bubbleBg },
|
{ backgroundColor: bubbleBg },
|
||||||
!msg.isOwn && styles.bubbleOtherBorder,
|
!msg.isOwn && styles.bubbleOtherBorder,
|
||||||
isImageOnly && { padding: 4 },
|
isImageOnly && { padding: 4 },
|
||||||
|
isAudioMsg && { paddingHorizontal: 6, paddingTop: 6, paddingBottom: 4 },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{msg.attachmentUrl && msg.attachmentType === 'image' ? (
|
{msg.attachmentUrl && msg.attachmentType === 'image' ? (
|
||||||
<Image source={{ uri: msg.attachmentUrl }} style={styles.image} contentFit="cover" cachePolicy="memory-disk" />
|
<Image source={{ uri: msg.attachmentUrl }} style={styles.image} contentFit="cover" cachePolicy="memory-disk" />
|
||||||
|
) : msg.attachmentUrl && msg.attachmentType === 'audio' ? (
|
||||||
|
<VoiceNoteBubble url={msg.attachmentUrl} duration={msg.attachmentName ?? '0:00'} isOwn={msg.isOwn} />
|
||||||
) : msg.content !== '' ? (
|
) : msg.content !== '' ? (
|
||||||
<Text style={[styles.content, { color: bubbleText }]}>{msg.content}</Text>
|
<Text style={[styles.content, { color: bubbleText }]}>{msg.content}</Text>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
@ -92,15 +92,26 @@ export function MessageActionMenu({
|
|||||||
const barH = showReactions ? 60 : 0;
|
const barH = showReactions ? 60 : 0;
|
||||||
const estMenuH = actions.length * 52 + 12;
|
const estMenuH = actions.length * 52 + 12;
|
||||||
|
|
||||||
// Menü unter der Bubble, sonst darüber.
|
// Input-Bar + Safe-Area am unteren Bildschirmrand (Popup darf nie darunter)
|
||||||
const belowSpace = screenH - (anchor.y + anchor.height);
|
const bottomInset = 90;
|
||||||
const placeBelow = belowSpace > estMenuH + 40;
|
const usableH = screenH - bottomInset;
|
||||||
const menuTop = placeBelow
|
|
||||||
? anchor.y + anchor.height + 10
|
|
||||||
: Math.max(topSafe + barH + 10, anchor.y - estMenuH - 10);
|
|
||||||
|
|
||||||
// Reaktions-Leiste über der Bubble (geclampt unter die Safe-Area).
|
// Menü unter der Bubble wenn genug Platz, sonst darüber — Input-Bar berücksichtigt
|
||||||
const barTop = Math.max(topSafe, anchor.y - barH - 4);
|
const belowSpace = usableH - (anchor.y + anchor.height);
|
||||||
|
const placeBelow = belowSpace >= estMenuH + 8;
|
||||||
|
|
||||||
|
const menuTopIdeal = placeBelow
|
||||||
|
? anchor.y + anchor.height + 8
|
||||||
|
: anchor.y - estMenuH - 8;
|
||||||
|
// Clampen: nie über Safe-Area oben, nie unter Input-Bar unten
|
||||||
|
const menuTop = Math.min(
|
||||||
|
Math.max(topSafe + barH + 8, menuTopIdeal),
|
||||||
|
usableH - estMenuH,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Reaktions-Leiste über der Bubble — nie über topSafe, nie das Menü überlappen
|
||||||
|
const barTopIdeal = Math.max(topSafe, anchor.y - barH - 4);
|
||||||
|
const barTop = Math.min(barTopIdeal, menuTop - barH - 8);
|
||||||
|
|
||||||
// Horizontale Ausrichtung an der Bubble-Seite.
|
// Horizontale Ausrichtung an der Bubble-Seite.
|
||||||
const sideStyle = isOwn
|
const sideStyle = isOwn
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user