Compare commits

...

3 Commits

Author SHA1 Message Date
duffyduck 853f2737f1 release: bump version to 0.1.4.2 2026-05-14 22:29:31 +02:00
duffyduck 7c61107f87 release: bump version to 0.1.4.1 2026-05-14 22:16:17 +02:00
duffyduck 7a22474efd feat(chat): Jump-down-Button + Sprung-an-Text-Anfang + Vision-Issue raus
Drei kleine UX-Fixes im Chat:

1. Jump-Down-Button (↓): Bei inverted FlatList erscheint rechts ueber
   der Eingabe ein blauer FAB, sobald man mehr als 250px von der
   neuesten Nachricht weg gescrollt ist. Tap → scrollToOffset(0)
   animated → wieder unten. Auto-hide wenn man unten ist.

2. Such-Sprung landet jetzt am TEXT-ANFANG der Treffer-Bubble:
   viewPosition 0.5 (Mitte) → 0 (Item-Top am Viewport-Top). Plus
   Retry-Folge (180/420/800ms) gegen Layout-Race bei langen Listen.
   Vorher musste man oft nochmal hoch scrollen um den Anfang zu sehen.
   onScrollToIndexFailed-Fallback genauso mit viewPosition 0.

3. issue.md: "Bilder: Claude Vision direkt nutzen" raus aus den
   offenen Punkten — ist durch Stufe E (Memory-Anhaenge, Read-Tool
   multi-modal) längst geloest. ARIA sieht Bilder echt.

Folge-Etappen: Such-Sprung-Resilienz war Teil davon (mehrere Retries
abgedeckt). Naechste Brocken: Doppel-Send-Haenger, AsyncStorage-Race,
Offline-Queue mit Idempotenz.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 22:10:26 +02:00
4 changed files with 65 additions and 14 deletions
+2 -2
View File
@@ -79,8 +79,8 @@ android {
applicationId "com.ariacockpit"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 10400
versionName "0.1.4.0"
versionCode 10402
versionName "0.1.4.2"
// Fallback fuer Libraries mit Product Flavors
missingDimensionStrategy 'react-native-camera', 'general'
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "aria-cockpit",
"version": "0.1.4.0",
"version": "0.1.4.2",
"private": true,
"scripts": {
"android": "react-native run-android",
+62 -10
View File
@@ -236,6 +236,7 @@ const ChatScreen: React.FC = () => {
const [fullscreenImage, setFullscreenImage] = useState<string | null>(null);
const [memoryDetailId, setMemoryDetailId] = useState<string | null>(null);
const [inboxVisible, setInboxVisible] = useState(false);
const [showJumpDown, setShowJumpDown] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [searchVisible, setSearchVisible] = useState(false);
const [searchIndex, setSearchIndex] = useState(0); // welcher Treffer aktiv ist
@@ -1052,9 +1053,10 @@ const ChatScreen: React.FC = () => {
}, [searchQuery]);
// Bei Index-Wechsel zu der entsprechenden Bubble scrollen.
// FlatList ist `inverted` viewPosition 0.5 (mitte) ist beim inverted-Render
// tatsaechlich die Mitte des sichtbaren Bereichs. Wir verzoegern minimal
// damit Layout sicher fertig ist.
// FlatList ist `inverted`. viewPosition 0 = Item-Top oben am Viewport →
// Treffer-Bubble liegt mit dem Anfang direkt oben sichtbar, kein
// weiteres Hochscrollen noetig. Plus mehrere Retries da Layout bei
// langen Listen zeitversetzt fertig wird.
useEffect(() => {
if (!searchMatchIds.length) return;
const id = searchMatchIds[searchIndex];
@@ -1063,13 +1065,16 @@ const ChatScreen: React.FC = () => {
if (idx < 0 || !flatListRef.current) return;
const tryScroll = () => {
try {
flatListRef.current?.scrollToIndex({ index: idx, animated: true, viewPosition: 0.5 });
flatListRef.current?.scrollToIndex({ index: idx, animated: true, viewPosition: 0 });
} catch {
// wird von onScrollToIndexFailed nochmal versucht
}
};
// requestAnimationFrame statt setTimeout 0 — wartet auf naechsten Layout-Frame
// requestAnimationFrame fuer den ersten Versuch, dann setTimeout-Folge
// damit auch bei tiefen Indizes (viel ungelayoutete Items dazwischen)
// der Sprung am Ende sitzt.
requestAnimationFrame(tryScroll);
[180, 420, 800].forEach(d => setTimeout(tryScroll, d));
}, [searchIndex, searchMatchIds, invertedMessages]);
const activeSearchId = searchMatchIds[searchIndex] || '';
@@ -1726,15 +1731,27 @@ const ChatScreen: React.FC = () => {
ref={flatListRef}
inverted
data={invertedMessages}
onScroll={(e) => {
// Bei inverted FlatList: contentOffset.y > 0 = weg von "unten"
// (= aelter scrollen). Wir zeigen den Jump-Down-Button ab ~250px.
const y = e.nativeEvent.contentOffset.y;
setShowJumpDown(y > 250);
}}
scrollEventThrottle={120}
onScrollToIndexFailed={(info) => {
// FlatList kennt das Item-Layout noch nicht. Zuerst grob in die
// Naehe scrollen (Average-Item-Hoehe-Schaetzung), dann nach 250ms
// praezise nochmal versuchen.
// Naehe scrollen (Average-Item-Hoehe-Schaetzung), dann mehrfach
// praezise nachsetzen — bei langem Chat braucht's manchmal mehrere
// Runden bis die Layouts gemessen sind.
const offset = info.averageItemLength * info.index;
try { flatListRef.current?.scrollToOffset({ offset, animated: false }); } catch {}
setTimeout(() => {
try { flatListRef.current?.scrollToIndex({ index: info.index, animated: true, viewPosition: 0.5 }); } catch {}
}, 250);
// viewPosition 0 = Item-Top oben am Viewport → Stefan landet am
// Text-Anfang der Bubble, nicht in der Mitte oder am Ende.
[120, 320, 600].forEach(delay => {
setTimeout(() => {
try { flatListRef.current?.scrollToIndex({ index: info.index, animated: true, viewPosition: 0 }); } catch {}
}, delay);
});
}}
keyExtractor={item => item.id}
renderItem={renderMessage}
@@ -1801,6 +1818,24 @@ const ChatScreen: React.FC = () => {
</View>
)}
{/* Jump-to-Bottom-Button — erscheint wenn man weg von der neuesten
Nachricht gescrollt hat. Bei inverted FlatList ist scrollToOffset
0 == neueste Nachricht visuell unten. */}
{showJumpDown && (
<TouchableOpacity
style={styles.jumpDownBtn}
activeOpacity={0.85}
onPress={() => {
try {
flatListRef.current?.scrollToOffset({ offset: 0, animated: true });
} catch {}
setShowJumpDown(false);
}}
>
<Text style={{color:'#fff', fontSize:18, fontWeight:'700'}}>{'↓'}</Text>
</TouchableOpacity>
)}
{/* Eingabebereich */}
<View style={styles.inputContainer}>
{/* Datei-Buttons */}
@@ -2341,6 +2376,23 @@ const styles = StyleSheet.create({
color: '#555570',
fontSize: 10,
},
jumpDownBtn: {
position: 'absolute',
right: 16,
bottom: 80,
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: '#0096FF',
alignItems: 'center',
justifyContent: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.4,
shadowRadius: 4,
elevation: 5,
zIndex: 100,
},
bubbleTrash: {
position: 'absolute',
top: 4,
-1
View File
@@ -348,7 +348,6 @@ Skills mit Tool-Use.
- [ ] Custom-Wake-Word-Upload via Diagnostic (eigene .onnx-Files ohne App-Rebuild)
### Architektur
- [ ] Bilder: Claude Vision direkt nutzen (aktuell nur Dateipfad an ARIA)
- [ ] Diagnostic: System-Info Tab (Container-Status, Disk, RAM, CPU)
- [ ] RVS Zombie-Connections endgueltig loesen
- [ ] Gamebox: kleine Web-Oberflaeche fuer Credentials/Server-Config oder zentral aus Diagnostic per RVS push