@@ -1026,7 +1026,15 @@ const ChatScreen: React.FC = () => {
} , [ messages ] ) ;
} , [ messages ] ) ;
// Inverted FlatList: neueste Nachrichten unten, kein manuelles Scrollen noetig
// Inverted FlatList: neueste Nachrichten unten, kein manuelles Scrollen noetig
const invertedMessages = useMemo ( ( ) = > [ . . . messages ] . reverse ( ) , [ messages ] ) ;
// Spezial-Bubbles (memorySaved/triggerCreated/skillCreated) sollen im Chat
// NICHT mehr erscheinen — sie werden in der Notizen-Inbox angezeigt.
// Das verhindert dass sie chronologisch unten im Chat haengen und der
// eigentliche Chat-Verlauf darunter verschwindet.
const chatVisibleMessages = useMemo (
( ) = > messages . filter ( m = > ! m . memorySaved && ! m . triggerCreated && ! m . skillCreated ) ,
[ messages ] ,
) ;
const invertedMessages = useMemo ( ( ) = > [ . . . chatVisibleMessages ] . reverse ( ) , [ chatVisibleMessages ] ) ;
// Such-Treffer: alle Message-IDs die zur Query passen, in chronologischer
// Such-Treffer: alle Message-IDs die zur Query passen, in chronologischer
// Reihenfolge (aelteste zuerst). Bei Query-Change resetten wir den Index.
// Reihenfolge (aelteste zuerst). Bei Query-Change resetten wir den Index.
@@ -1597,7 +1605,7 @@ const ChatScreen: React.FC = () => {
connectionState === 'connecting' ? 'Verbinde...' : 'Getrennt' }
connectionState === 'connecting' ? 'Verbinde...' : 'Getrennt' }
< / Text >
< / Text >
< TouchableOpacity onPress = { ( ) = > setInboxVisible ( true ) } style = { { marginLeft : 'auto' , paddingHorizontal : 6 } } hitSlop = { { top :8 , bottom :8 , left :6 , right :6 } } >
< TouchableOpacity onPress = { ( ) = > setInboxVisible ( true ) } style = { { marginLeft : 'auto' , paddingHorizontal : 6 } } hitSlop = { { top :8 , bottom :8 , left :6 , right :6 } } >
< Text style = { { fontSize : 18 } } > \ uD83D \ uDDC2 \ uFE0F < / Text >
< Text style = { { fontSize : 18 } } > { '\uD83D\uDDC2\uFE0F' } < / Text >
< / TouchableOpacity >
< / TouchableOpacity >
< TouchableOpacity onPress = { ( ) = > setSearchVisible ( ! searchVisible ) } style = { { paddingHorizontal : 6 } } hitSlop = { { top :8 , bottom :8 , left :6 , right :6 } } >
< TouchableOpacity onPress = { ( ) = > setSearchVisible ( ! searchVisible ) } style = { { paddingHorizontal : 6 } } hitSlop = { { top :8 , bottom :8 , left :6 , right :6 } } >
< Text style = { { fontSize : 16 } } > { '\uD83D\uDD0D' } < / Text >
< Text style = { { fontSize : 16 } } > { '\uD83D\uDD0D' } < / Text >
@@ -1844,11 +1852,87 @@ const ChatScreen: React.FC = () => {
< Modal visible = { inboxVisible } animationType = "slide" onRequestClose = { ( ) = > setInboxVisible ( false ) } >
< Modal visible = { inboxVisible } animationType = "slide" onRequestClose = { ( ) = > setInboxVisible ( false ) } >
< View style = { { flex :1 , backgroundColor : '#0D0D1A' } } >
< View style = { { flex :1 , backgroundColor : '#0D0D1A' } } >
< View style = { { flexDirection : 'row' , alignItems : 'center' , padding :14 , borderBottomWidth :1 , borderBottomColor : '#1E1E2E' } } >
< View style = { { flexDirection : 'row' , alignItems : 'center' , padding :14 , borderBottomWidth :1 , borderBottomColor : '#1E1E2E' } } >
< Text style = { { color : '#FFD60A' , fontWeight : 'bold' , fontSize :16 , flex :1 } } > 🗂 ️ Notizen - Inbox < / Text >
< Text style = { { color : '#FFD60A' , fontWeight : 'bold' , fontSize :16 , flex :1 } } > { '🗂️' } Notizen - Inbox < / Text >
< TouchableOpacity onPress = { ( ) = > setInboxVisible ( false ) } hitSlop = { { top :8 , bottom :8 , left :8 , right :8 } } >
< TouchableOpacity onPress = { ( ) = > setInboxVisible ( false ) } hitSlop = { { top :8 , bottom :8 , left :8 , right :8 } } >
< Text style = { { color : '#8888AA' , fontSize :24 } } > × < / Text >
< Text style = { { color : '#8888AA' , fontSize :24 } } > × < / Text >
< / TouchableOpacity >
< / TouchableOpacity >
< / View >
< / View >
{ /* Aus aktuellem Chat: Spezial-Bubbles (memory/trigger/skill) kompakt
auflisten — neueste oben. Klick auf Memory oeffnet Detail-Modal. */ }
{ ( ( ) = > {
const specials = messages
. filter ( m = > m . memorySaved || m . triggerCreated || m . skillCreated )
. slice ( ) . reverse ( ) ;
if ( specials . length === 0 ) {
return (
< View style = { { padding :14 , borderBottomWidth :1 , borderBottomColor : '#1E1E2E' } } >
< Text style = { { color : '#555570' , fontSize :11 , fontStyle : 'italic' } } >
( keine Notizen - Bubbles im aktuellen Chat )
< / Text >
< / View >
) ;
}
return (
< View style = { { maxHeight :260 , borderBottomWidth :1 , borderBottomColor : '#1E1E2E' } } >
< Text style = { { color : '#8888AA' , fontSize :11 , paddingHorizontal :14 , paddingTop :8 , paddingBottom :4 , textTransform : 'uppercase' , letterSpacing :0.5 } } >
Aus diesem Chat
< / Text >
< ScrollView style = { { paddingHorizontal :8 } } >
{ specials . map ( m = > {
if ( m . memorySaved ) {
const ms = m . memorySaved ;
const action = ms . action || 'created' ;
const verb = action === 'updated' ? 'geändert' : action === 'deleted' ? 'gelöscht' : 'angelegt' ;
const dotColor = action === 'deleted' ? '#FF6B6B' : '#FFD60A' ;
return (
< TouchableOpacity
key = { m . id }
style = { styles . inboxRow }
onPress = { ( ) = > { if ( ms . id && action !== 'deleted' ) { setInboxVisible ( false ) ; setMemoryDetailId ( ms . id ) ; } } }
disabled = { ! ms . id || action === 'deleted' }
>
< Text style = { { fontSize :16 } } > { '🧠' } < / Text >
< View style = { { flex :1 } } >
< Text style = { styles . inboxRowTitle } numberOfLines = { 1 } > { ms . title } < / Text >
< Text style = { [ styles . inboxRowMeta , { color : dotColor } ] } > Memory · { verb } · { ms . type } < / Text >
< / View >
{ ms . id && action !== 'deleted' ? < Text style = { { color : '#0096FF' , fontSize :14 } } > › < / Text > : null }
< / TouchableOpacity >
) ;
}
if ( m . triggerCreated ) {
const t = m . triggerCreated ;
return (
< View key = { m . id } style = { styles . inboxRow } >
< Text style = { { fontSize :16 } } > { '⏰' } < / Text >
< View style = { { flex :1 } } >
< Text style = { styles . inboxRowTitle } numberOfLines = { 1 } > { t . name } < / Text >
< Text style = { styles . inboxRowMeta } > Trigger · { t . type } { t . fires_at ? ` · ${ t . fires_at . slice ( 0 , 16 ) . replace ( 'T' , ' ' ) } ` : '' } < / Text >
< / View >
< / View >
) ;
}
if ( m . skillCreated ) {
const sk = m . skillCreated ;
return (
< View key = { m . id } style = { styles . inboxRow } >
< Text style = { { fontSize :16 } } > { '🛠' } < / Text >
< View style = { { flex :1 } } >
< Text style = { styles . inboxRowTitle } numberOfLines = { 1 } > { sk . name } < / Text >
< Text style = { styles . inboxRowMeta } > Skill · { sk . execution } < / Text >
< / View >
< / View >
) ;
}
return null ;
} ) }
< / ScrollView >
< / View >
) ;
} ) ( ) }
< Text style = { { color : '#8888AA' , fontSize :11 , paddingHorizontal :14 , paddingTop :10 , paddingBottom :4 , textTransform : 'uppercase' , letterSpacing :0.5 } } >
Alle Memories aus der DB
< / Text >
< MemoryBrowser / >
< MemoryBrowser / >
< / View >
< / View >
< / Modal >
< / Modal >
@@ -2181,6 +2265,25 @@ const styles = StyleSheet.create({
playButtonText : {
playButtonText : {
fontSize : 16 ,
fontSize : 16 ,
} ,
} ,
inboxRow : {
flexDirection : 'row' ,
alignItems : 'center' ,
gap : 10 ,
backgroundColor : '#1E1E2E' ,
padding : 10 ,
borderRadius : 6 ,
marginBottom : 4 ,
} ,
inboxRowTitle : {
color : '#E0E0F0' ,
fontSize : 13 ,
fontWeight : '600' ,
} ,
inboxRowMeta : {
color : '#8888AA' ,
fontSize : 11 ,
marginTop : 1 ,
} ,
memoryAttachmentRow : {
memoryAttachmentRow : {
flexDirection : 'row' ,
flexDirection : 'row' ,
alignItems : 'center' ,
alignItems : 'center' ,