feat: 添加章节管理功能以支持清除回忆
- 在数据库模型中新增 is_active 字段,用于标记章节是否启用。 - 添加数据库迁移脚本以更新现有章节,确保默认值为 TRUE。 - 更新章节相关的 API 以仅返回 active 章节,并实现清除章节的功能。 - 在 Android 客户端中实现清除章节的确认弹窗和相应的 API 调用,提升用户体验。
This commit is contained in:
@@ -165,6 +165,20 @@ class ApiService(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除章节(将章节标记为 disabled)
|
||||
*/
|
||||
suspend fun disableChapter(chapterId: String): Result<Unit> {
|
||||
return try {
|
||||
val response = client.delete("$BASE_URL/api/chapters/$chapterId") {
|
||||
contentType(ContentType.Application.Json)
|
||||
}
|
||||
Result.success(Unit)
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun exportPdf(bookId: String, userId: String = "default_user"): Result<ByteArray> {
|
||||
return try {
|
||||
val response = client.post("$BASE_URL/api/books/export-pdf") {
|
||||
|
||||
@@ -216,6 +216,50 @@ fun MyMemoirScreen(
|
||||
)
|
||||
}
|
||||
|
||||
// 当前章节是否有内容(active)
|
||||
val hasActiveContent = remember(selectedChapter) {
|
||||
selectedChapter?.content?.isNotBlank() == true
|
||||
}
|
||||
|
||||
// 清除回忆确认弹窗状态
|
||||
var showClearDialog by remember { mutableStateOf(false) }
|
||||
|
||||
// 清除回忆确认弹窗
|
||||
if (showClearDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showClearDialog = false },
|
||||
title = {
|
||||
Text(
|
||||
text = "清除回忆",
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Text("清除回忆会完全清除当前章节的内容,确定继续吗?")
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
showClearDialog = false
|
||||
selectedChapter?.let { chapter ->
|
||||
viewModel.disableChapter(chapter.id)
|
||||
}
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(
|
||||
contentColor = MaterialTheme.colorScheme.error
|
||||
)
|
||||
) {
|
||||
Text("确定清除")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { showClearDialog = false }) {
|
||||
Text("取消")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -228,26 +272,53 @@ fun MyMemoirScreen(
|
||||
.windowInsetsPadding(WindowInsets.statusBars)
|
||||
)
|
||||
|
||||
// 返回按钮
|
||||
// 顶部导航栏:返回按钮 + 清除回忆按钮
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(AppDimensions.cardPadding)
|
||||
.clickable { viewModel.clearSelection() },
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
.padding(AppDimensions.cardPadding),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Icon(
|
||||
imageVector = AppIcons.ArrowBack,
|
||||
contentDescription = "返回",
|
||||
tint = SlatePurple,
|
||||
modifier = Modifier.size(AppDimensions.iconSize)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = "返回目录",
|
||||
fontSize = AppTypography.bodyMedium,
|
||||
color = SlatePurple
|
||||
)
|
||||
// 返回按钮
|
||||
Row(
|
||||
modifier = Modifier.clickable { viewModel.clearSelection() },
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = AppIcons.ArrowBack,
|
||||
contentDescription = "返回",
|
||||
tint = SlatePurple,
|
||||
modifier = Modifier.size(AppDimensions.iconSize)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = "返回目录",
|
||||
fontSize = AppTypography.bodyMedium,
|
||||
color = SlatePurple
|
||||
)
|
||||
}
|
||||
|
||||
// 清除回忆按钮
|
||||
TextButton(
|
||||
onClick = { showClearDialog = true },
|
||||
enabled = hasActiveContent,
|
||||
colors = ButtonDefaults.textButtonColors(
|
||||
contentColor = MaterialTheme.colorScheme.error,
|
||||
disabledContentColor = SlatePurple.copy(alpha = 0.3f)
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = AppIcons.Delete,
|
||||
contentDescription = "清除回忆",
|
||||
modifier = Modifier.size(AppDimensions.iconSizeSmall)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text(
|
||||
text = "清除回忆",
|
||||
fontSize = AppTypography.captionLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ChapterReadingView(chapter = chapterContent)
|
||||
|
||||
@@ -171,5 +171,38 @@ class MyMemoirViewModel(
|
||||
fun toggleFullTextReading() {
|
||||
showFullTextReading.value = !showFullTextReading.value
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除章节(将章节标记为 disabled)
|
||||
* 成功后刷新章节列表并清除选中状态
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun disableChapter(chapterId: String, onSuccess: () -> Unit = {}, onError: (String) -> Unit = {}) {
|
||||
viewModelScope.launch {
|
||||
isLoading.value = true
|
||||
try {
|
||||
apiService.disableChapter(chapterId).fold(
|
||||
onSuccess = {
|
||||
// 清除选中状态,回到目录
|
||||
clearSelection()
|
||||
// 刷新章节列表
|
||||
refreshChapters()
|
||||
onSuccess()
|
||||
},
|
||||
onFailure = { e ->
|
||||
val errorMsg = "清除回忆失败: ${e.message}"
|
||||
error.value = errorMsg
|
||||
onError(errorMsg)
|
||||
}
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
val errorMsg = "清除回忆失败: ${e.message}"
|
||||
error.value = errorMsg
|
||||
onError(errorMsg)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user