feat: paginate, sync, and display branched sessions (#563)

* mobile: 以 Desktop Sessions 作为聊天历史源

* mobile: 修复快速连接崩溃与无标题会话隐藏

* mobile: 对齐 Desktop 标题并恢复完整历史

* mobile: 分离 Desktop 存储 ID 与运行 Session ID

* mobile: 将新对话持久化为 Desktop Session

* mobile: 渲染 Desktop 本地媒体

* feat: 分页加载并同步当前会话

* fix: 显示分支会话名称与层级

* fix: align PR with upstream app contract

* fix: preserve upstream session RPC lifecycle
This commit is contained in:
Genesi599 authored and GitHub committed 2026-07-12 12:53:23 +03:00
1 parent 306861a222
commit 3052db7d65
8 files changed
+405 -79

No files matched your search

@@ -19,6 +19,8 @@ data class SessionInfo(
val preview: String? = null,
val started_at: Double? = null,
val source: String? = null,
val parent_session_id: String? = null,
val display_name: String? = null,
)
@Serializable
@@ -0,0 +1,51 @@
package com.m57.hermescontrol.data.model
data class SessionTreeItem(
val session: SessionInfo,
val depth: Int,
val branchStem: String?,
val displayTitle: String,
)
fun flattenSessionTree(sessions: List<SessionInfo>): List<SessionTreeItem> {
val ids = sessions.mapTo(mutableSetOf()) { it.id }
val children = sessions.groupBy { it.parent_session_id?.takeIf(ids::contains) }
val result = mutableListOf<SessionTreeItem>()
val visited = mutableSetOf<String>()
fun append(
session: SessionInfo,
depth: Int,
branchStem: String?,
siblingIndex: Int,
) {
if (!visited.add(session.id)) return
val isBranch = session.parent_session_id?.takeIf(ids::contains) != null
val title =
session.title?.takeIf(String::isNotBlank)
?: session.display_name?.takeIf(String::isNotBlank)
?: if (isBranch) {
"branch ${siblingIndex + 1}"
} else {
session.preview?.takeIf(String::isNotBlank)?.take(80) ?: "Untitled"
}
result += SessionTreeItem(session, depth, branchStem, title)
val descendants = children[session.id].orEmpty()
descendants.forEachIndexed { index, child ->
append(
session = child,
depth = depth + 1,
branchStem = if (index == descendants.lastIndex) "└─" else "├─",
siblingIndex = index,
)
}
}
children[null].orEmpty().forEachIndexed { index, root ->
append(root, depth = 0, branchStem = null, siblingIndex = index)
}
sessions.filterNot { it.id in visited }.forEachIndexed { index, orphan ->
append(orphan, depth = 0, branchStem = null, siblingIndex = index)
}
return result
}