M7: polish + E2E + docs (layout pass, theming, states, e2e driver, schema, setup.md, security)
This commit is contained in:
1 parent
0cc8b7aafe
commit
bf6bf7e8bd
26 files changed
+2225
-327
No files matched your search
@@ -3,6 +3,8 @@ package iris.state
|
||||
import iris.data.ChatStore
|
||||
import iris.data.ChannelStore
|
||||
import iris.data.MediaItem
|
||||
import iris.data.MessageItem
|
||||
import iris.data.MsgStatus
|
||||
import iris.data.SecureStore
|
||||
import iris.media.MediaCache
|
||||
import iris.media.kindFromMime
|
||||
@@ -16,10 +18,13 @@ import iris.protocol.MediaOfferPayload
|
||||
import iris.protocol.MessagePayload
|
||||
import iris.protocol.MessageStopPayload
|
||||
import iris.protocol.NotificationPayload
|
||||
import iris.protocol.ReadReceiptPayload
|
||||
import iris.protocol.ROLE_ASSISTANT
|
||||
import iris.protocol.SearchHit
|
||||
import iris.protocol.SearchResultsPayload
|
||||
import iris.protocol.StatusPayload
|
||||
import iris.protocol.SyncDonePayload
|
||||
import iris.protocol.TYPE_ERROR
|
||||
import iris.protocol.TYPE_NOTIFICATION
|
||||
import iris.protocol.TYPE_CHANNEL_CREATED
|
||||
import iris.protocol.TYPE_CHANNEL_DELETED
|
||||
@@ -31,7 +36,9 @@ import iris.protocol.TYPE_MESSAGE
|
||||
import iris.protocol.TYPE_MESSAGE_START
|
||||
import iris.protocol.TYPE_MESSAGE_STOP
|
||||
import iris.protocol.TYPE_MESSAGE_UPDATE
|
||||
import iris.protocol.TYPE_READ_RECEIPT
|
||||
import iris.protocol.TYPE_SEARCH_RESULTS
|
||||
import iris.protocol.TYPE_STATUS
|
||||
import iris.protocol.TYPE_SYNC_DONE
|
||||
import iris.protocol.TYPE_TOOL_END
|
||||
import iris.protocol.TYPE_TOOL_PROGRESS
|
||||
@@ -89,6 +96,10 @@ class IrisController(
|
||||
private val _homeChannel = MutableStateFlow("android:default")
|
||||
val homeChannel: StateFlow<String> = _homeChannel.asStateFlow()
|
||||
|
||||
/** Gateway health state (M5: status frame; null = never received). */
|
||||
private val _gatewayStatus = MutableStateFlow<String?>(null)
|
||||
val gatewayStatus: StateFlow<String?> = _gatewayStatus.asStateFlow()
|
||||
|
||||
// ── M3: threads toggle (per-app for now; per-channel lands later) ─────
|
||||
private val _threadsEnabled = MutableStateFlow(false)
|
||||
val threadsEnabled: StateFlow<Boolean> = _threadsEnabled.asStateFlow()
|
||||
@@ -259,6 +270,18 @@ class IrisController(
|
||||
TYPE_TYPING -> {
|
||||
frame.payloadAs<TypingPayload>()?.let { _typing.value = it.on }
|
||||
}
|
||||
TYPE_READ_RECEIPT -> {
|
||||
frame.payloadAs<ReadReceiptPayload>()?.let { chat.markRead(it.messageId) }
|
||||
}
|
||||
TYPE_STATUS -> {
|
||||
frame.payloadAs<StatusPayload>()?.let { _gatewayStatus.value = it.state }
|
||||
}
|
||||
TYPE_ERROR -> {
|
||||
// M7: error frames are global, not per-message — fail
|
||||
// any optimistic sends still in flight so they don't
|
||||
// sit at "sending…" forever.
|
||||
chat.failPending()
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
@@ -375,6 +398,16 @@ class IrisController(
|
||||
_attachments.value = emptyList()
|
||||
}
|
||||
|
||||
/** M7: resend a failed user message (tap on the failed bubble). */
|
||||
fun retrySend(messageId: String) {
|
||||
val lane = chat.currentLane.value
|
||||
val (chatId, threadId) = chat.parseLane(lane)
|
||||
val item = chat.lanes.value[lane]?.firstOrNull { it.id == messageId } as? MessageItem ?: return
|
||||
if (item.status != MsgStatus.Failed) return
|
||||
chat.rearmForRetry(lane, messageId)
|
||||
client.sendMessage(chatId, item.text, threadId, item.media.map { it.mediaId })
|
||||
}
|
||||
|
||||
// ── M4: attachments (pick -> upload -> send) ──────────────────────────
|
||||
|
||||
/** Stage a picked file: upload it, then keep it as a pending attachment. */
|
||||
|
||||
Reference in new issue
Block a user