feat(app): Trigger-CRUD-Section in Settings + nested-Scroll-Fix

Settings hatte zwei Probleme:

1) Gedächtnis-Liste scrollte nur runter, nicht hoch. Klassisches Android
   nested-Scroll-Problem: aeussere ScrollView + innere FlatList mit
   fixer height:600 = nur eine Richtung wird respektiert.

   Fix: outer ScrollView mit scrollEnabled=false wenn die Section eine
   eigene voll-hoch-scrollende Sub-Liste hat (memory/triggers). Plus
   dynamische Hoehe via useWindowDimensions (winHeight - 220 statt
   hardcoded 600) damit MemoryBrowser sauber den verfuegbaren Platz
   nutzt.

2) Trigger waren bisher nur via Diagnostic-Tab editierbar — keine App-
   side CRUD. Stefan wollte das.

   Neu: TriggerBrowser-Komponente (analog MemoryBrowser-Struktur)
   - Liste aller Trigger mit Filter (alle/aktive/inaktive)
   - Toggle aktiv/inaktiv via Switch direkt in der Zeile
   - Tap oeffnet TriggerEditModal (Nachricht/Condition/fires_at/intervals
     editieren, Loeschen-Knopf mit Confirm)
   - "+ Neu"-Knopf oeffnet TriggerNewModal mit Type-Switch (Watcher/Timer),
     Watcher zeigt Hinweis auf verfuegbare Funktionen + Variablen
   - Live Reload-Button, Meta-Info (fire_count, last_fired_at, ...)

   brainApi um Trigger-Endpoints erweitert: listTriggers, getTrigger,
   createTimer, createWatcher, updateTrigger (patch), deleteTrigger,
   getTriggerConditions, getTriggerLogs. Plus Trigger-Type-Definition.

Settings-Liste hat eine neue Section " Trigger" zwischen Gedaechtnis
und Protokoll.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 22:44:24 +02:00
parent b4923bc221
commit 7093ebaf0b
3 changed files with 695 additions and 2 deletions
+26 -2
View File
@@ -19,6 +19,7 @@ import {
ActivityIndicator,
Modal,
PermissionsAndroid,
useWindowDimensions,
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import RNFS from 'react-native-fs';
@@ -53,6 +54,7 @@ import {
import audioService from '../services/audio';
import gpsTrackingService from '../services/gpsTracking';
import MemoryBrowser from '../components/MemoryBrowser';
import TriggerBrowser from '../components/TriggerBrowser';
import { isVerboseLogging, setVerboseLogging } from '../services/logger';
import {
isWakeReadySoundEnabled,
@@ -102,6 +104,7 @@ const SETTINGS_SECTIONS = [
{ id: 'storage', icon: '📁', label: 'Speicher', desc: 'Anhang-Speicherort, Auto-Download' },
{ id: 'files', icon: '📂', label: 'Dateien', desc: 'ARIA- und User-Dateien — anzeigen, löschen' },
{ id: 'memory', icon: '🧠', label: 'Gedächtnis', desc: 'ARIA-Memories durchsuchen, anlegen, bearbeiten, löschen' },
{ id: 'triggers', icon: '⏰', label: 'Trigger', desc: 'Timer + Watcher anlegen, bearbeiten, löschen' },
{ id: 'protocol', icon: '📜', label: 'Protokoll', desc: 'Privatsphaere, Backup' },
{ id: 'about', icon: '️', label: 'Ueber', desc: 'App-Version, Update' },
] as const;
@@ -118,6 +121,7 @@ const SOURCE_COLORS: Record<string, string> = {
// --- Komponente ---
const SettingsScreen: React.FC = () => {
const winDims = useWindowDimensions();
const [connectionState, setConnectionState] = useState<ConnectionState>('disconnected');
const [manualToken, setManualToken] = useState('');
const [manualHost, setManualHost] = useState('');
@@ -868,7 +872,15 @@ const SettingsScreen: React.FC = () => {
})()}
</View>
</Modal>
<ScrollView style={styles.container} contentContainerStyle={styles.content} nestedScrollEnabled={true}>
<ScrollView
style={styles.container}
contentContainerStyle={styles.content}
nestedScrollEnabled={true}
// Wenn eine Section eine eigene voll-hoch-scrollende Sub-Liste hat
// (Memory, Trigger), den outer Scroll deaktivieren — Android-nested-
// scrolling laesst sonst nur in eine Richtung scrollen.
scrollEnabled={currentSection !== 'memory' && currentSection !== 'triggers'}
>
{currentSection === null && (
<>
@@ -1682,11 +1694,23 @@ const SettingsScreen: React.FC = () => {
Alle Memory-Einträge aus ARIAs Vector-DB. Tippen zum Bearbeiten mit Anhängen, pinned-Status,
Tags. Neue Einträge anlegen via "+ Neu".
</Text>
<View style={{height: 600, marginBottom: 8}}>
<View style={{height: winDims.height - 220, marginBottom: 8}}>
<MemoryBrowser />
</View>
</>)}
{/* === Trigger === */}
{currentSection === 'triggers' && (<>
<Text style={styles.sectionTitle}>Trigger</Text>
<Text style={{color: '#8888AA', fontSize: 12, marginBottom: 8, paddingHorizontal: 4}}>
Timer (einmalige Erinnerung) + Watcher (recurring mit Condition, z.B. GPS-near). Toggle aktiv/inaktiv,
Tap zum Bearbeiten, "+ Neu" zum Anlegen.
</Text>
<View style={{height: winDims.height - 220, marginBottom: 8}}>
<TriggerBrowser />
</View>
</>)}
{/* === Logs === */}
{currentSection === 'protocol' && (<>
<Text style={styles.sectionTitle}>Protokoll</Text>