diff --git a/android/src/screens/ChatScreen.tsx b/android/src/screens/ChatScreen.tsx
index d99639a..a119532 100644
--- a/android/src/screens/ChatScreen.tsx
+++ b/android/src/screens/ChatScreen.tsx
@@ -1381,18 +1381,21 @@ const ChatScreen: React.FC = () => {
);
const invertedMessages = useMemo(() => [...chatVisibleMessages].reverse(), [chatVisibleMessages]);
- // Such-Treffer: alle Message-IDs die zur Query passen, in chronologischer
- // Reihenfolge (aelteste zuerst). Bei Query-Change resetten wir den Index.
+ // Such-Treffer: alle Message-IDs die zur Query passen. NEUESTE ZUERST —
+ // analog zu WhatsApp/Telegram: User ist visuell unten im Chat, der erste
+ // Treffer ist meist schon im Viewport (kein weiter Pre-Scroll, kein
+ // Cold-Start-Sprung-Fail). „Naechster" geht in die Vergangenheit.
// WICHTIG: nur in chatVisibleMessages suchen — Spezial-Bubbles (Memory/
// Skill/Trigger) sind im Chat-Stream nicht sichtbar und Treffer auf die
// wuerden zu „ID nicht im FlatList → findIndex=-1 → kein Scroll"-Fail
- // fuehren (Cessna in einer Memory-Bubble → springt zur falschen Stelle).
+ // fuehren.
const searchMatchIds = useMemo(() => {
const q = searchQuery.trim().toLowerCase();
if (!q) return [] as string[];
return chatVisibleMessages
.filter(m => (m.text || '').toLowerCase().includes(q))
- .map(m => m.id);
+ .map(m => m.id)
+ .reverse();
}, [chatVisibleMessages, searchQuery]);
useEffect(() => {
@@ -1470,7 +1473,9 @@ const ChatScreen: React.FC = () => {
animated: false,
});
} catch {}
- // Nach kurzer Render-Pause praezise nachsetzen
+ // Nach kurzer Render-Pause praezise nachsetzen. 200 ms statt 80 ms —
+ // bei Cold-Start braucht FlatList laenger fuer das Item-Layout, das
+ // war Stefans „erst beim zweiten Versuch klappt's"-Bug.
requestAnimationFrame(() => {
setTimeout(() => {
try {
@@ -1478,7 +1483,7 @@ const ChatScreen: React.FC = () => {
} catch {
// onScrollToIndexFailed-Handler uebernimmt den Fallback
}
- }, 80);
+ }, 200);
});
}, [searchIndex, searchMatchIds]);
diff --git a/android/src/screens/SettingsScreen.tsx b/android/src/screens/SettingsScreen.tsx
index 8e08796..e2d5f19 100644
--- a/android/src/screens/SettingsScreen.tsx
+++ b/android/src/screens/SettingsScreen.tsx
@@ -1798,7 +1798,7 @@ const SettingsScreen: React.FC = () => {
ARIA Cockpit
Version {require('../../package.json').version}
- ARIA \u2014 Autonomous Reasoning & Intelligence Assistant.{'\n'}
+ ARIA {'\u2014'} Autonomous Reasoning & Intelligence Assistant.{'\n'}
Stefans Kommandozentrale.{'\n'}
Gebaut mit React Native + TypeScript.
diff --git a/android/src/services/gpsTracking.ts b/android/src/services/gpsTracking.ts
index 240aa08..ef98299 100644
--- a/android/src/services/gpsTracking.ts
+++ b/android/src/services/gpsTracking.ts
@@ -26,6 +26,13 @@ class GpsTrackingService {
private listeners: Set = new Set();
// Defensive: nicht zu schnell oeffentlich togglen
private lastChangeAt = 0;
+ // Letzte bekannte Position — wird vom Heartbeat-Timer alle 60s erneut
+ // an die Bridge gesendet, sonst veraltet near() im Brain (NEAR_MAX_AGE_SEC
+ // = 5 min) wenn der User stationaer ist und distanceFilter keine Updates
+ // mehr triggert.
+ private lastLat: number | null = null;
+ private lastLon: number | null = null;
+ private heartbeatTimer: ReturnType | null = null;
isActive(): boolean {
return this.active;
@@ -84,6 +91,8 @@ class GpsTrackingService {
(pos) => {
const lat = pos.coords.latitude;
const lon = pos.coords.longitude;
+ this.lastLat = lat;
+ this.lastLon = lon;
rvs.send('location_update' as any, { lat, lon });
},
(err) => {
@@ -96,6 +105,17 @@ class GpsTrackingService {
fastestInterval: 10000, // (Android) max Frequenz
} as any,
);
+ // Heartbeat: alle 60s die letzte bekannte Position erneut senden.
+ // Sonst bleibt der Brain-State stale wenn der User stationaer ist
+ // (distanceFilter blockt watchPosition-Updates) → near()-Watcher
+ // verwerfen die Position als veraltet (NEAR_MAX_AGE_SEC = 300s).
+ // Kein neuer GPS-Wakeup, nur Re-Send der letzten Werte → akkufreundlich.
+ if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
+ this.heartbeatTimer = setInterval(() => {
+ if (this.lastLat != null && this.lastLon != null) {
+ rvs.send('location_update' as any, { lat: this.lastLat, lon: this.lastLon });
+ }
+ }, 60_000);
this.active = true;
this.lastChangeAt = Date.now();
this.notify();
@@ -118,6 +138,10 @@ class GpsTrackingService {
try { Geolocation.clearWatch(this.watchId); } catch {}
this.watchId = null;
}
+ if (this.heartbeatTimer) {
+ clearInterval(this.heartbeatTimer);
+ this.heartbeatTimer = null;
+ }
this.active = false;
this.lastChangeAt = Date.now();
this.notify();