diff --git a/apps/rebreak-native/app/dm.tsx b/apps/rebreak-native/app/dm.tsx index 6948759..2ef4de2 100644 --- a/apps/rebreak-native/app/dm.tsx +++ b/apps/rebreak-native/app/dm.tsx @@ -10,6 +10,9 @@ import { ActivityIndicator, StyleSheet, Keyboard, + Modal, + ScrollView, + Dimensions, type FlatList as FlatListType, } from 'react-native'; import { KeyboardStickyView } from 'react-native-keyboard-controller'; @@ -88,6 +91,8 @@ export default function DmScreen() { const [keyboardVisible, setKeyboardVisible] = useState(false); const [keyboardHeight, setKeyboardHeight] = useState(0); const [inputBarHeight, setInputBarHeight] = useState(60); + const [infoSheetOpen, setInfoSheetOpen] = useState(false); + const [lightboxUri, setLightboxUri] = useState(null); // Reset aller conversation-spezifischen States wenn userId wechselt (Stack-Reuse) useEffect(() => { @@ -162,8 +167,11 @@ export default function DmScreen() { deleted: m.deleted ?? false, })); setMessages(msgs); + // Dreistufiges Scroll-to-bottom: rAF + 100ms + 300ms deckt + // Fälle ab wo Bilder nachgeladen werden und Content-Höhe wächst. requestAnimationFrame(() => flatListRef.current?.scrollToEnd({ animated: false })); setTimeout(() => flatListRef.current?.scrollToEnd({ animated: false }), 100); + setTimeout(() => flatListRef.current?.scrollToEnd({ animated: false }), 300); return data; } catch (err: any) { console.error('[dm] history fetch failed:', err?.message ?? err); @@ -460,13 +468,17 @@ export default function DmScreen() { return ( - + router.back()} hitSlop={8} activeOpacity={0.7}> - + + {/* Avatar + Name — tap → Profil */} + userId && router.push(`/profile/${userId}` as any)} + > {userId && } - + + + {/* Info-Button */} + setInfoSheetOpen(true)} + > + + @@ -610,10 +632,180 @@ export default function DmScreen() { + + {/* ── Info-Sheet ─────────────────────────────────────────────── */} + setInfoSheetOpen(false)} + partner={partner} + messages={messages} + onImagePress={(uri) => setLightboxUri(uri)} + onViewProfile={() => { + setInfoSheetOpen(false); + setTimeout(() => userId && router.push(`/profile/${userId}` as any), 250); + }} + colors={colors} + t={t} + /> + + {/* ── Lightbox ───────────────────────────────────────────────── */} + setLightboxUri(null)}> + setLightboxUri(null)} + > + {lightboxUri && ( + + )} + setLightboxUri(null)} + activeOpacity={0.7} + > + + + + ); } +// ─── DmInfoSheet ───────────────────────────────────────────────────────────── + +const MEDIA_COL = 3; +const MEDIA_GAP = 2; +const MEDIA_SIZE = (Dimensions.get('window').width - MEDIA_GAP * (MEDIA_COL + 1)) / MEDIA_COL; + +function DmInfoSheet({ + visible, + onClose, + partner, + messages, + onImagePress, + onViewProfile, + colors, + t, +}: { + visible: boolean; + onClose: () => void; + partner: { id: string; nickname: string; avatar?: string | null } | null; + messages: ChatMsg[]; + onImagePress: (uri: string) => void; + onViewProfile: () => void; + colors: ReturnType; + t: ReturnType['t']; +}) { + const sharedMedia = messages.filter( + (m) => m.attachmentType === 'image' && m.attachmentUrl, + ); + + return ( + + + {/* Header */} + + + {t('chat.info')} + + + + + + + + {/* Partner-Karte */} + + {partner?.avatar ? ( + + ) : ( + + + {partner?.nickname?.[0]?.toUpperCase() ?? '?'} + + + )} + + + {partner?.nickname ?? '…'} + + + {t('dm.view_profile', { defaultValue: 'Profil anzeigen' })} + + + + + + + + {/* Geteilte Medien */} + + + {t('dm.shared_media', { defaultValue: 'Geteilte Medien' })} + {sharedMedia.length > 0 && ( + + {' '}{sharedMedia.length} + + )} + + + + {sharedMedia.length === 0 ? ( + + + + {t('dm.no_shared_media', { defaultValue: 'Keine geteilten Medien' })} + + + ) : ( + + {[...sharedMedia].reverse().map((m) => ( + onImagePress(m.attachmentUrl!)} + > + + + ))} + + )} + + + + ); +} + function makeStyles(colors: ReturnType) { return StyleSheet.create({ container: { flex: 1, backgroundColor: colors.bg }, @@ -622,8 +814,6 @@ function makeStyles(colors: ReturnType) { alignItems: 'center', paddingHorizontal: 12, paddingVertical: 10, - borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: colors.border, }, backBtn: { padding: 8, @@ -636,6 +826,11 @@ function makeStyles(colors: ReturnType) { alignItems: 'center', marginLeft: 8, }, + infoBtn: { + padding: 8, + alignItems: 'center', + justifyContent: 'center', + }, headerName: { fontSize: 15, fontFamily: 'Nunito_700Bold', diff --git a/apps/rebreak-native/components/chat/ChatBubble.tsx b/apps/rebreak-native/components/chat/ChatBubble.tsx index d32c82f..114282f 100644 --- a/apps/rebreak-native/components/chat/ChatBubble.tsx +++ b/apps/rebreak-native/components/chat/ChatBubble.tsx @@ -146,7 +146,7 @@ export function ChatBubble({ ]} > {msg.attachmentUrl && msg.attachmentType === 'image' ? ( - + ) : msg.content !== '' ? ( {msg.content} ) : null} diff --git a/apps/rebreak-native/locales/ar.json b/apps/rebreak-native/locales/ar.json index 26e7fd1..41420ce 100644 --- a/apps/rebreak-native/locales/ar.json +++ b/apps/rebreak-native/locales/ar.json @@ -1013,6 +1013,11 @@ "photo_access_title": "الوصول إلى الصور", "photo_access_body": "يرجى السماح بالوصول إلى الصور في الإعدادات." }, + "dm": { + "view_profile": "عرض الملف الشخصي", + "shared_media": "الوسائط المشتركة", + "no_shared_media": "لا توجد وسائط مشتركة" + }, "community": { "compose_placeholder": "ما الذي يشغلك الآن؟", "compose_default_user": "أنت", diff --git a/apps/rebreak-native/locales/de.json b/apps/rebreak-native/locales/de.json index 5bf8d7f..2fa5378 100644 --- a/apps/rebreak-native/locales/de.json +++ b/apps/rebreak-native/locales/de.json @@ -1078,6 +1078,11 @@ "photo_access_title": "Foto-Zugriff", "photo_access_body": "Bitte erlaube den Foto-Zugriff in den Einstellungen." }, + "dm": { + "view_profile": "Profil anzeigen", + "shared_media": "Geteilte Medien", + "no_shared_media": "Keine geteilten Medien" + }, "community": { "compose_placeholder": "Was bewegt dich gerade?", "compose_default_user": "Du", diff --git a/apps/rebreak-native/locales/en.json b/apps/rebreak-native/locales/en.json index 9dbafdc..cc9ff16 100644 --- a/apps/rebreak-native/locales/en.json +++ b/apps/rebreak-native/locales/en.json @@ -1078,6 +1078,11 @@ "photo_access_title": "Photo access", "photo_access_body": "Please allow photo access in Settings." }, + "dm": { + "view_profile": "View profile", + "shared_media": "Shared Media", + "no_shared_media": "No shared media yet" + }, "community": { "compose_placeholder": "What's on your mind?", "compose_default_user": "You", diff --git a/apps/rebreak-native/locales/fr.json b/apps/rebreak-native/locales/fr.json index 0cc2082..4ee22a7 100644 --- a/apps/rebreak-native/locales/fr.json +++ b/apps/rebreak-native/locales/fr.json @@ -1000,6 +1000,11 @@ "photo_access_title": "Accès aux photos", "photo_access_body": "Veuillez autoriser l'accès aux photos dans les paramètres." }, + "dm": { + "view_profile": "Voir le profil", + "shared_media": "Médias partagés", + "no_shared_media": "Aucun média partagé" + }, "community": { "compose_placeholder": "Qu'est-ce qui vous préoccupe en ce moment ?", "compose_default_user": "Vous",