|
|
|
@@ -5,7 +5,7 @@
|
|
|
|
|
* Datei- und Kamera-Upload.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
|
|
|
import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
|
|
|
|
|
import {
|
|
|
|
|
View,
|
|
|
|
|
Text,
|
|
|
|
@@ -369,42 +369,8 @@ const ChatScreen: React.FC = () => {
|
|
|
|
|
return () => { if (saveTimer.current) clearTimeout(saveTimer.current); };
|
|
|
|
|
}, [messages]);
|
|
|
|
|
|
|
|
|
|
// Auto-Scroll: immer zur letzten Nachricht springen
|
|
|
|
|
const shouldAutoScroll = useRef(true);
|
|
|
|
|
const lastMessageCount = useRef(0);
|
|
|
|
|
|
|
|
|
|
// Bei neuen Nachrichten oder App-Start: nach unten springen
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (messages.length > 0 && shouldAutoScroll.current) {
|
|
|
|
|
const isInitial = lastMessageCount.current === 0;
|
|
|
|
|
const scrollToBottom = () => {
|
|
|
|
|
try {
|
|
|
|
|
flatListRef.current?.scrollToIndex({
|
|
|
|
|
index: messages.length - 1,
|
|
|
|
|
animated: !isInitial,
|
|
|
|
|
viewPosition: 1, // 1 = Item am unteren Rand
|
|
|
|
|
});
|
|
|
|
|
} catch {
|
|
|
|
|
// Fallback wenn Index nicht berechnet werden kann
|
|
|
|
|
flatListRef.current?.scrollToEnd({ animated: !isInitial });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const delays = isInitial ? [200, 500, 1000] : [150];
|
|
|
|
|
for (const delay of delays) {
|
|
|
|
|
setTimeout(scrollToBottom, delay);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lastMessageCount.current = messages.length;
|
|
|
|
|
}, [messages]);
|
|
|
|
|
|
|
|
|
|
const handleScrollBeginDrag = useCallback(() => {
|
|
|
|
|
shouldAutoScroll.current = false;
|
|
|
|
|
}, []);
|
|
|
|
|
const handleScrollEndDrag = useCallback((e: any) => {
|
|
|
|
|
const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent;
|
|
|
|
|
const isAtBottom = contentOffset.y + layoutMeasurement.height >= contentSize.height - 50;
|
|
|
|
|
shouldAutoScroll.current = isAtBottom;
|
|
|
|
|
}, []);
|
|
|
|
|
// Inverted FlatList: neueste Nachrichten unten, kein manuelles Scrollen noetig
|
|
|
|
|
const invertedMessages = useMemo(() => [...messages].reverse(), [messages]);
|
|
|
|
|
|
|
|
|
|
// GPS-Position holen (optional)
|
|
|
|
|
const getCurrentLocation = useCallback((): Promise<{ lat: number; lon: number } | null> => {
|
|
|
|
@@ -693,18 +659,12 @@ const ChatScreen: React.FC = () => {
|
|
|
|
|
{/* Nachrichtenliste */}
|
|
|
|
|
<FlatList
|
|
|
|
|
ref={flatListRef}
|
|
|
|
|
data={searchQuery ? messages.filter(m => m.text.toLowerCase().includes(searchQuery.toLowerCase())) : messages}
|
|
|
|
|
inverted
|
|
|
|
|
data={searchQuery ? messages.filter(m => m.text.toLowerCase().includes(searchQuery.toLowerCase())).reverse() : invertedMessages}
|
|
|
|
|
keyExtractor={item => item.id}
|
|
|
|
|
renderItem={renderMessage}
|
|
|
|
|
contentContainerStyle={styles.messageList}
|
|
|
|
|
showsVerticalScrollIndicator={false}
|
|
|
|
|
onScrollBeginDrag={handleScrollBeginDrag}
|
|
|
|
|
onScrollEndDrag={handleScrollEndDrag}
|
|
|
|
|
onScrollToIndexFailed={(info) => {
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
flatListRef.current?.scrollToEnd({ animated: false });
|
|
|
|
|
}, 200);
|
|
|
|
|
}}
|
|
|
|
|
ListEmptyComponent={
|
|
|
|
|
<View style={styles.emptyContainer}>
|
|
|
|
|
<Text style={styles.emptyIcon}>{'\uD83E\uDD16'}</Text>
|
|
|
|
|