fix(android): 编辑器改成整页显示,保存后回到刚才那条详情

原来编辑器是叠在工作区上的 Box,而详情抽屉/对话框是独立窗口,永远盖在它上面——用户只能看到编辑器的一条顶栏。改成编辑器替换整页;保存成功后父层记下 itemId,回到工作区由对应页面刷新并重新打开那条详情。取消则什么都不变。
This commit is contained in:
dadao
2026-10-29 04:01:28 +08:00
parent 17be9d1d42
commit d509f0c335
6 changed files with 120 additions and 55 deletions
@@ -73,6 +73,10 @@ private fun AppRoot(joinUri: String?) {
var unread by remember { mutableStateOf(0) }
// 打开富文本编辑器时非空;关掉就恢复原来的界面
var editing by remember { mutableStateOf<EditRequest?>(null) }
// 编辑器保存成功的那条:回到工作区后重新打开它的详情,然后清掉
var reopenItem by remember { mutableStateOf<String?>(null) }
// 上面那条是任务还是知识:决定回哪个页面去重开
var reopenKnowledge by remember { mutableStateOf(false) }
// 有本地令牌就先静默校验一次:令牌过期/被吊销要退回登录页,而不是进了主页再崩。
LaunchedEffect(screen) {
@@ -124,65 +128,72 @@ private fun AppRoot(joinUri: String?) {
)
Screen.Workspace -> {
val ws = current
val request = editing
if (ws == null) {
screen = Screen.Home
} else {
Box {
WorkspaceScaffold(
workspace = ws,
tab = tab,
unread = unread,
onTab = { tab = it },
onBackHome = { screen = Screen.Home },
) {
when (tab) {
WorkspaceTab.Tasks -> TaskListScreen(
api = api,
workspace = ws,
onEdit = { editing = it },
} else if (request != null) {
// 编辑器**替换**整页,而不是叠在上面:抽屉/对话框都是独立窗口,
// 叠一层会被它们盖住,用户只能看到编辑器的一条边。
RichTextEditorScreen(
api = api,
workspaceId = ws.id,
itemId = request.itemId,
initialTitle = request.title,
initialBody = request.body,
titleEnabled = request.titleEnabled,
save = { title, body ->
if (request.knowledge) {
api.updateKnowledge(
workspaceId = ws.id,
itemId = request.itemId,
version = request.version,
title = title,
body = body,
)
WorkspaceTab.Tickets -> TicketsScreen(api = api, workspace = ws)
WorkspaceTab.Knowledge -> KnowledgeScreen(
api = api,
workspace = ws,
onEdit = { editing = it },
} else {
api.updateItem(
workspaceId = ws.id,
itemId = request.itemId,
version = request.version,
title = title,
body = body,
)
WorkspaceTab.Members -> MembersScreen(api = api, workspace = ws)
}
}
val request = editing
if (request != null) {
RichTextEditorScreen(
// 保存成功才标记"回到哪条":取消退出不该改变任何界面状态。
reopenItem = request.itemId
reopenKnowledge = request.knowledge
},
// saved 参数由编辑器给:true 时上面已经设过 reopenItem,
// 这里只负责把编辑器收起来,回到工作区后由对应页面重开详情。
onClose = { _ -> editing = null },
)
} else {
WorkspaceScaffold(
workspace = ws,
tab = tab,
unread = unread,
onTab = { tab = it },
onBackHome = { screen = Screen.Home },
) {
when (tab) {
WorkspaceTab.Tasks -> TaskListScreen(
api = api,
workspaceId = ws.id,
itemId = request.itemId,
initialTitle = request.title,
initialBody = request.body,
titleEnabled = request.titleEnabled,
save = { title, body ->
if (request.knowledge) {
api.updateKnowledge(
workspaceId = ws.id,
itemId = request.itemId,
version = request.version,
title = title,
body = body,
)
} else {
api.updateItem(
workspaceId = ws.id,
itemId = request.itemId,
version = request.version,
title = title,
body = body,
)
}
},
onClose = { editing = null },
workspace = ws,
onEdit = { editing = it },
reopenItem = if (reopenItem != null && !reopenKnowledge) reopenItem else null,
onReopened = { reopenItem = null },
)
WorkspaceTab.Tickets -> TicketsScreen(api = api, workspace = ws)
WorkspaceTab.Knowledge -> KnowledgeScreen(
api = api,
workspace = ws,
onEdit = { editing = it },
reopenItem = if (reopenItem != null && reopenKnowledge) reopenItem else null,
onReopened = { reopenItem = null },
)
WorkspaceTab.Members -> MembersScreen(api = api, workspace = ws)
}
}
}
@@ -55,7 +55,14 @@ private fun docTypeLabel(type: String): String = when (type) {
}
@Composable
fun KnowledgeScreen(api: Api, workspace: Workspace, onEdit: (EditRequest) -> Unit = {}) {
fun KnowledgeScreen(
api: Api,
workspace: Workspace,
onEdit: (EditRequest) -> Unit = {},
/** 编辑器保存后要重新打开的那条。父层持有:编辑器打开时本页会被整体卸载。 */
reopenItem: String? = null,
onReopened: () -> Unit = {},
) {
val scope = rememberCoroutineScope()
var tab by remember { mutableStateOf("draft") }
var docs by remember { mutableStateOf<List<KnowledgeDoc>>(emptyList()) }
@@ -85,6 +92,14 @@ fun KnowledgeScreen(api: Api, workspace: Workspace, onEdit: (EditRequest) -> Uni
LaunchedEffect(tab) { reload() }
// 从编辑器保存回来:本页是新建出来的,刷完列表再把那条详情重新打开。
LaunchedEffect(reopenItem) {
val target = reopenItem ?: return@LaunchedEffect
reload()
open = docs.firstOrNull { it.id == target }
onReopened()
}
fun fail(e: Throwable) {
val code = (e as? ApiException)?.code ?: 0
message = verifyStatusCode(code).ifBlank { e.message ?: "操作没成功" }
@@ -68,6 +68,8 @@ fun TaskDetailSheet(
onChanged: () -> Unit,
/** 进富文本编辑器改正文。标题与状态留在抽屉里,只有正文要更大地方。 */
onEdit: (ItemDetail) -> Unit = {},
/** 编辑器保存回来后变一次,抽屉据此重新拉数据——否则还显示保存前的旧正文。 */
refreshKey: Int = 0,
) {
val sheet = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val scope = rememberCoroutineScope()
@@ -93,7 +95,7 @@ fun TaskDetailSheet(
runCatching { api.me() }.onSuccess { meId = it.user.id }
}
LaunchedEffect(itemId) { reload() }
LaunchedEffect(itemId, refreshKey) { reload() }
fun fail(e: Throwable) {
val code = (e as? ApiException)?.code ?: 0
@@ -51,7 +51,14 @@ private val views = listOf(
)
@Composable
fun TaskListScreen(api: Api, workspace: Workspace, onEdit: (EditRequest) -> Unit = {}) {
fun TaskListScreen(
api: Api,
workspace: Workspace,
onEdit: (EditRequest) -> Unit = {},
/** 编辑器保存后要重新打开的那条。父层持这个状态,因为编辑器打开时本页会被整体卸载。 */
reopenItem: String? = null,
onReopened: () -> Unit = {},
) {
val scope = rememberCoroutineScope()
var view by remember { mutableStateOf("active") }
var mode by remember { mutableStateOf("list") }
@@ -60,6 +67,7 @@ fun TaskListScreen(api: Api, workspace: Workspace, onEdit: (EditRequest) -> Unit
var draft by remember { mutableStateOf("") }
var query by remember { mutableStateOf("") }
var openId by remember { mutableStateOf<String?>(null) }
var detailRefresh by remember { mutableStateOf(0) }
var error by remember { mutableStateOf<String?>(null) }
suspend fun reload() {
@@ -75,6 +83,15 @@ fun TaskListScreen(api: Api, workspace: Workspace, onEdit: (EditRequest) -> Unit
LaunchedEffect(view, query) { reload() }
// 从编辑器保存回来:本页是新建出来的,先刷数据再把那一条详情重新打开。
LaunchedEffect(reopenItem) {
val target = reopenItem ?: return@LaunchedEffect
reload()
detailRefresh += 1
openId = target
onReopened()
}
fun fail(e: Throwable) {
val code = (e as? ApiException)?.code ?: 0
error = verifyStatusCode(code).ifBlank { e.message ?: "操作没成功" }
@@ -193,10 +210,12 @@ fun TaskListScreen(api: Api, workspace: Workspace, onEdit: (EditRequest) -> Unit
itemId = id,
onClose = { openId = null },
onChanged = { scope.launch { reload() } },
// 抽屉是独立窗口,关掉才能让编辑器显示在上层;保存回来后由父层重新打开。
onEdit = {
openId = null
onEdit(EditRequest(it.id, it.title, it.bodyMd, it.version))
},
refreshKey = detailRefresh,
)
}
}