Merge pull request #1207 from journey-ad/feature/private-group

新增隐私分组功能
This commit is contained in:
Kudomaga
2026-05-27 01:10:58 +08:00
committed by GitHub
15 changed files with 2548 additions and 46 deletions
File diff suppressed because it is too large Load Diff
@@ -73,7 +73,7 @@ val appDb by lazy {
}
@Database(
version = 88,
version = 89,
exportSchema = true,
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
@@ -128,7 +128,8 @@ val appDb by lazy {
AutoMigration(from = 84, to = 85),
AutoMigration(from = 85, to = 86),
AutoMigration(from = 86, to = 87),
AutoMigration(from = 87, to = 88)
AutoMigration(from = 87, to = 88),
AutoMigration(from = 88, to = 89)
]
)
abstract class AppDatabase : RoomDatabase() {
@@ -22,6 +22,15 @@ data class GroupBookCount(
val count: Int
)
private const val PRIVATE_GROUP_MASK =
"(SELECT COALESCE(SUM(groupId), 0) FROM book_groups WHERE groupId > 0 AND isPrivate = 1)"
private const val PUBLIC_GROUP_MASK =
"(SELECT COALESCE(SUM(groupId), 0) FROM book_groups WHERE groupId > 0 AND isPrivate = 0)"
private const val PUBLIC_BOOK_FILTER =
"(`group` = 0 OR (`group` & $PRIVATE_GROUP_MASK) = 0)"
@Dao
interface BookDao {
@@ -69,7 +78,8 @@ interface BookDao {
"""
select * from books where type & ${BookType.text} > 0
and type & ${BookType.local} = 0
and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0
and ($PUBLIC_GROUP_MASK & `group`) = 0
and $PUBLIC_BOOK_FILTER
and (select show from book_groups where groupId = ${BookGroup.IdNetNone}) != 1
"""
)
@@ -103,7 +113,8 @@ interface BookDao {
FROM books
where type & ${BookType.text} > 0
and type & ${BookType.local} = 0
and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0
and ($PUBLIC_GROUP_MASK & `group`) = 0
and $PUBLIC_BOOK_FILTER
and (select show from book_groups where groupId = ${BookGroup.IdNetNone}) != 1
"""
)
@@ -138,6 +149,7 @@ interface BookDao {
kind,
wordCount
FROM books
WHERE $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
"""
)
@@ -173,6 +185,7 @@ interface BookDao {
wordCount
FROM books
WHERE type & ${BookType.audio} > 0
AND $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfAudio(): Flow<List<BookShelfItem>>
@@ -207,6 +220,7 @@ interface BookDao {
wordCount
FROM books
WHERE type & ${BookType.local} > 0
AND $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfLocal(): Flow<List<BookShelfItem>>
@@ -246,7 +260,8 @@ interface BookDao {
wordCount
FROM books
where type & ${BookType.audio} = 0 and type & ${BookType.local} = 0
and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0
and ($PUBLIC_GROUP_MASK & `group`) = 0
and $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfNetNoGroup(): Flow<List<BookShelfItem>>
@@ -286,7 +301,8 @@ interface BookDao {
wordCount
FROM books
where type & ${BookType.local} > 0
and ((SELECT sum(groupId) FROM book_groups where groupId > 0) & `group`) = 0
and ($PUBLIC_GROUP_MASK & `group`) = 0
and $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfLocalNoGroup(): Flow<List<BookShelfItem>>
@@ -321,6 +337,7 @@ interface BookDao {
wordCount
FROM books
WHERE (`group` & :group) > 0
AND ((SELECT isPrivate FROM book_groups WHERE groupId = :group) = 1 OR $PUBLIC_BOOK_FILTER)
"""
)
fun flowBookShelfByUserGroup(group: Long): Flow<List<BookShelfItem>>
@@ -356,7 +373,8 @@ interface BookDao {
kind,
wordCount
FROM books
WHERE name like '%'||:key||'%' or author like '%'||:key||'%' or originName like '%'||:key||'%'
WHERE (name like '%'||:key||'%' or author like '%'||:key||'%' or originName like '%'||:key||'%')
AND $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfSearch(key: String): Flow<List<BookShelfItem>>
@@ -391,6 +409,7 @@ interface BookDao {
wordCount
FROM books
where type & ${BookType.updateError} > 0
and $PUBLIC_BOOK_FILTER
order by durChapterTime desc
"""
)
@@ -426,6 +445,7 @@ interface BookDao {
wordCount
FROM books
WHERE durChapterIndex = 0 AND durChapterPos = 0
AND $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfUnread(): Flow<List<BookShelfItem>>
@@ -460,6 +480,7 @@ interface BookDao {
wordCount
FROM books
WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1
AND $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfReadFinished(): Flow<List<BookShelfItem>>
@@ -494,6 +515,7 @@ interface BookDao {
wordCount
FROM books
WHERE totalChapterNum > 0 AND durChapterIndex > 0 AND durChapterIndex < totalChapterNum - 1
AND $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfReading(): Flow<List<BookShelfItem>>
@@ -528,6 +550,7 @@ interface BookDao {
wordCount
FROM books
WHERE type & ${BookType.image} > 0
AND $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfManga(): Flow<List<BookShelfItem>>
@@ -562,6 +585,7 @@ interface BookDao {
wordCount
FROM books
WHERE type & ${BookType.text} > 0
AND $PUBLIC_BOOK_FILTER
"""
)
fun flowBookShelfText(): Flow<List<BookShelfItem>>
@@ -677,35 +701,44 @@ interface BookDao {
// ── Group preview / count queries (DB-level, replaces in-memory buildGroupPreviewState) ──
@Query("SELECT COUNT(*) FROM books")
@Query("SELECT COUNT(*) FROM books WHERE $PUBLIC_BOOK_FILTER")
fun flowAllBookShelfCount(): Flow<Int>
@Query(
"""
SELECT ${BookGroup.IdAll} AS groupId, COUNT(*) AS count FROM books
SELECT ${BookGroup.IdAll} AS groupId, COUNT(*) AS count FROM books WHERE $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdRoot}, COUNT(*) FROM books
WHERE type & ${BookType.text} > 0 AND type & ${BookType.local} = 0
AND ((SELECT COALESCE(SUM(groupId), 0) FROM book_groups WHERE groupId > 0) & `group`) = 0
AND ($PUBLIC_GROUP_MASK & `group`) = 0
AND $PUBLIC_BOOK_FILTER
AND (SELECT show FROM book_groups WHERE groupId = ${BookGroup.IdNetNone}) != 1
UNION ALL SELECT ${BookGroup.IdLocal}, COUNT(*) FROM books WHERE type & ${BookType.local} > 0
UNION ALL SELECT ${BookGroup.IdAudio}, COUNT(*) FROM books WHERE type & ${BookType.audio} > 0
UNION ALL SELECT ${BookGroup.IdLocal}, COUNT(*) FROM books WHERE type & ${BookType.local} > 0 AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdAudio}, COUNT(*) FROM books WHERE type & ${BookType.audio} > 0 AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdNetNone}, COUNT(*) FROM books
WHERE type & ${BookType.audio} = 0 AND type & ${BookType.local} = 0
AND ((SELECT COALESCE(SUM(groupId), 0) FROM book_groups WHERE groupId > 0) & `group`) = 0
AND ($PUBLIC_GROUP_MASK & `group`) = 0
AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdLocalNone}, COUNT(*) FROM books
WHERE type & ${BookType.local} > 0
AND ((SELECT COALESCE(SUM(groupId), 0) FROM book_groups WHERE groupId > 0) & `group`) = 0
UNION ALL SELECT ${BookGroup.IdManga}, COUNT(*) FROM books WHERE type & ${BookType.image} > 0
UNION ALL SELECT ${BookGroup.IdText}, COUNT(*) FROM books WHERE type & ${BookType.text} > 0
UNION ALL SELECT ${BookGroup.IdError}, COUNT(*) FROM books WHERE type & ${BookType.updateError} > 0
UNION ALL SELECT ${BookGroup.IdUnread}, COUNT(*) FROM books WHERE durChapterIndex = 0 AND durChapterPos = 0
UNION ALL SELECT ${BookGroup.IdReading}, COUNT(*) FROM books WHERE totalChapterNum > 0 AND durChapterIndex > 0 AND durChapterIndex < totalChapterNum - 1
UNION ALL SELECT ${BookGroup.IdReadFinished}, COUNT(*) FROM books WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1
AND ($PUBLIC_GROUP_MASK & `group`) = 0
AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdManga}, COUNT(*) FROM books WHERE type & ${BookType.image} > 0 AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdText}, COUNT(*) FROM books WHERE type & ${BookType.text} > 0 AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdError}, COUNT(*) FROM books WHERE type & ${BookType.updateError} > 0 AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdUnread}, COUNT(*) FROM books WHERE durChapterIndex = 0 AND durChapterPos = 0 AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdReading}, COUNT(*) FROM books WHERE totalChapterNum > 0 AND durChapterIndex > 0 AND durChapterIndex < totalChapterNum - 1 AND $PUBLIC_BOOK_FILTER
UNION ALL SELECT ${BookGroup.IdReadFinished}, COUNT(*) FROM books WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND $PUBLIC_BOOK_FILTER
"""
)
fun flowSystemGroupCounts(): Flow<List<GroupBookCount>>
@Query("SELECT COUNT(*) FROM books WHERE (`group` & :groupId) > 0")
@Query(
"""
SELECT COUNT(*) FROM books
WHERE (`group` & :groupId) > 0
AND ((SELECT isPrivate FROM book_groups WHERE groupId = :groupId) = 1 OR $PUBLIC_BOOK_FILTER)
"""
)
fun flowUserGroupBookCount(groupId: Long): Flow<Int>
fun flowGroupPreview(groupId: Long): Flow<List<BookShelfItem>> {
@@ -737,6 +770,7 @@ interface BookDao {
type, `group`, `order`, canUpdate,
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -753,7 +787,8 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE type & ${BookType.text} > 0 AND type & ${BookType.local} = 0
AND ((SELECT COALESCE(SUM(groupId), 0) FROM book_groups WHERE groupId > 0) & `group`) = 0
AND ($PUBLIC_GROUP_MASK & `group`) = 0
AND $PUBLIC_BOOK_FILTER
AND (SELECT show FROM book_groups WHERE groupId = ${BookGroup.IdNetNone}) != 1
ORDER BY durChapterTime DESC
LIMIT 10
@@ -771,6 +806,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE type & ${BookType.local} > 0
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -787,6 +823,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE type & ${BookType.audio} > 0
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -803,7 +840,8 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE type & ${BookType.audio} = 0 AND type & ${BookType.local} = 0
AND ((SELECT COALESCE(SUM(groupId), 0) FROM book_groups WHERE groupId > 0) & `group`) = 0
AND ($PUBLIC_GROUP_MASK & `group`) = 0
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -820,7 +858,8 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE type & ${BookType.local} > 0
AND ((SELECT COALESCE(SUM(groupId), 0) FROM book_groups WHERE groupId > 0) & `group`) = 0
AND ($PUBLIC_GROUP_MASK & `group`) = 0
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -837,6 +876,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE type & ${BookType.image} > 0
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -853,6 +893,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE type & ${BookType.text} > 0
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -869,6 +910,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE type & ${BookType.updateError} > 0
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -885,6 +927,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE durChapterIndex = 0 AND durChapterPos = 0
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -901,6 +944,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE totalChapterNum > 0 AND durChapterIndex > 0 AND durChapterIndex < totalChapterNum - 1
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -917,6 +961,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1
AND $PUBLIC_BOOK_FILTER
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -933,6 +978,7 @@ interface BookDao {
ifnull(customIntro, intro) as intro, kind, wordCount
FROM books
WHERE (`group` & :groupId) > 0
AND ((SELECT isPrivate FROM book_groups WHERE groupId = :groupId) = 1 OR $PUBLIC_BOOK_FILTER)
ORDER BY durChapterTime DESC
LIMIT 10
"""
@@ -25,42 +25,75 @@ interface BookGroupDao {
@get:Query(
"""
with const as (SELECT sum(groupId) sumGroupId FROM book_groups where groupId > 0)
with const as (
SELECT
COALESCE(SUM(CASE WHEN groupId > 0 AND isPrivate = 0 THEN groupId ELSE 0 END), 0) sumPublicGroupId,
COALESCE(SUM(CASE WHEN groupId > 0 AND isPrivate = 1 THEN groupId ELSE 0 END), 0) sumPrivateGroupId
FROM book_groups
)
SELECT book_groups.* FROM book_groups join const
where show > 0
and (
(groupId >= 0 and exists (select 1 from books where `group` & book_groups.groupId > 0))
(groupId >= 0 and exists (
select 1 from books
where `group` & book_groups.groupId > 0
and (book_groups.isPrivate = 1 or `group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or groupId = ${BookGroup.IdAll}
or (groupId = ${BookGroup.IdLocal} and exists (select 1 from books where type & ${BookType.local} > 0))
or (groupId = ${BookGroup.IdAudio} and exists (select 1 from books where type & ${BookType.audio} > 0))
or (groupId = ${BookGroup.IdManga} and exists (select 1 FROM books where type & ${BookType.image} > 0))
or (groupId = ${BookGroup.IdText} and exists (select 1 FROM books where type & ${BookType.text} > 0))
or (groupId = ${BookGroup.IdLocal} and exists (
select 1 from books
where type & ${BookType.local} > 0
and (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or (groupId = ${BookGroup.IdAudio} and exists (
select 1 from books
where type & ${BookType.audio} > 0
and (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or (groupId = ${BookGroup.IdManga} and exists (
select 1 FROM books
where type & ${BookType.image} > 0
and (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or (groupId = ${BookGroup.IdText} and exists (
select 1 FROM books
where type & ${BookType.text} > 0
and (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or (groupId = ${BookGroup.IdReading} and exists (
SELECT 1 FROM books
WHERE totalChapterNum > 0
AND durChapterIndex > 0
AND durChapterIndex < totalChapterNum - 1
AND (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or (groupId = ${BookGroup.IdUnread} and exists (
SELECT 1 FROM books
WHERE durChapterIndex = 0
AND durChapterPos = 0
AND (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or (groupId = ${BookGroup.IdReadFinished} and exists (
SELECT 1 FROM books
WHERE totalChapterNum > 0
AND durChapterIndex >= totalChapterNum - 1
AND durChapterPos != 0
AND (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or (groupId = ${BookGroup.IdError} and exists (select 1 from books where type & ${BookType.updateError} > 0))
or (groupId = ${BookGroup.IdError} and exists (
select 1 from books
where type & ${BookType.updateError} > 0
and (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
))
or (groupId = ${BookGroup.IdNetNone}
and exists (
select 1 from books
where type & ${BookType.audio} = 0
and type & ${BookType.local} = 0
and const.sumGroupId & `group` = 0
and (const.sumPublicGroupId & `group`) = 0
and (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
)
)
or (groupId = ${BookGroup.IdLocalNone}
@@ -68,7 +101,8 @@ interface BookGroupDao {
select 1 from books
where type & ${BookType.audio} = 0
and type & ${BookType.local} > 0
and const.sumGroupId & `group` = 0
and (const.sumPublicGroupId & `group`) = 0
and (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0)
)
)
)
@@ -124,4 +158,4 @@ interface BookGroupDao {
}
return id
}
}
}
@@ -23,7 +23,9 @@ data class BookGroup(
@ColumnInfo(defaultValue = "1")
var show: Boolean = true,
@ColumnInfo(defaultValue = "-1")
var bookSort: Int = -1
var bookSort: Int = -1,
@ColumnInfo(defaultValue = "0")
var isPrivate: Boolean = false
) : Parcelable {
companion object {
@@ -83,8 +85,9 @@ data class BookGroup(
&& other.enableRefresh == enableRefresh
&& other.show == show
&& other.order == order
&& other.isPrivate == isPrivate
}
return false
}
}
}
@@ -82,6 +82,11 @@ class GroupEditDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_book_gro
binding.ivCover.load(group.cover)
}
binding.cbEnableRefresh.isChecked = group.enableRefresh
binding.cbPrivate.isChecked = group.isPrivate
if (group.groupId <= 0) {
binding.cbPrivate.gone()
binding.tvPrivateDesc.gone()
}
selectedSortIndex = group.bookSort
val displayIndex = selectedSortIndex + 1
@@ -103,6 +108,17 @@ class GroupEditDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_book_gro
selectedSortIndex = position - 1
}
binding.cbPrivate.setOnCheckedChangeListener { buttonView, isChecked ->
if (!isChecked && bookGroup?.isPrivate == true) {
alert(R.string.disable_private_group, R.string.sure_disable_private_group) {
yesButton()
noButton {
buttonView.isChecked = true
}
}
}
}
binding.run {
ivCover.onClick {
selectImage.launch()
@@ -128,11 +144,13 @@ class GroupEditDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_book_gro
val bookSort = selectedSortIndex
val coverPath = binding.ivCover.bitmapPath
val enableRefresh = binding.cbEnableRefresh.isChecked
val isPrivate = binding.cbPrivate.isChecked
bookGroup?.let {
it.groupName = groupName
it.cover = coverPath
it.bookSort = bookSort
it.enableRefresh = enableRefresh
it.isPrivate = isPrivate
viewModel.upGroup(it) {
dismiss()
}
@@ -141,6 +159,7 @@ class GroupEditDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_book_gro
groupName,
bookSort,
enableRefresh,
isPrivate,
coverPath
) {
dismiss()
@@ -163,7 +182,12 @@ class GroupEditDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_book_gro
private fun deleteGroup(ok: () -> Unit) {
alert(R.string.delete, R.string.sure_del) {
val message = if (bookGroup?.isPrivate == true) {
R.string.sure_del_private_group
} else {
R.string.sure_del
}
alert(R.string.delete, message) {
yesButton {
ok.invoke()
}
@@ -171,4 +195,4 @@ class GroupEditDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_book_gro
}
}
}
}
@@ -103,12 +103,15 @@ fun GroupEditContent(
val context = LocalContext.current
var groupName by remember(group) { mutableStateOf(group?.groupName ?: "") }
var enableRefresh by remember(group) { mutableStateOf(group?.enableRefresh ?: true) }
var isPrivate by remember(group) { mutableStateOf(group?.isPrivate ?: false) }
var showDisablePrivateDialog by remember(group) { mutableStateOf(false) }
var selectedSortIndex by remember(group) { mutableIntStateOf(group?.bookSort ?: -1) }
val sortOptions = stringArrayResource(R.array.book_sort)
val sortEntryValues = remember(sortOptions) {
Array(sortOptions.size) { (it - 1).toString() }
}
val canSetPrivate = group == null || group.groupId > 0
val selectImage = rememberLauncherForActivityResult(SelectImageContract()) { result ->
result.uri?.let { uri ->
@@ -190,6 +193,23 @@ fun GroupEditContent(
onCheckedChange = { enableRefresh = it }
)
if (canSetPrivate) {
Spacer(modifier = Modifier.height(8.dp))
CompactSwitchSettingItem(
title = stringResource(R.string.private_group),
description = stringResource(R.string.private_group_desc),
checked = isPrivate,
onCheckedChange = { checked ->
if (!checked && group?.isPrivate == true) {
showDisablePrivateDialog = true
} else {
isPrivate = checked
}
}
)
}
Spacer(modifier = Modifier.height(16.dp))
ConfirmDismissButtonsRow(
@@ -199,13 +219,14 @@ fun GroupEditContent(
if (groupName.isEmpty()) {
appCtx.toastOnUi("分组名称不能为空")
} else {
if (group != null && group.groupId != 0b1L) {
if (group != null) {
viewModel.upGroup(
group.copy(
groupName = groupName,
cover = coverPath,
bookSort = selectedSortIndex,
enableRefresh = enableRefresh
enableRefresh = enableRefresh,
isPrivate = isPrivate
)
) {
onDismissRequest()
@@ -215,6 +236,7 @@ fun GroupEditContent(
groupName,
selectedSortIndex,
enableRefresh,
isPrivate,
coverPath
) {
onDismissRequest()
@@ -226,6 +248,20 @@ fun GroupEditContent(
confirmText = stringResource(R.string.ok)
)
}
AppAlertDialog(
show = showDisablePrivateDialog,
onDismissRequest = { showDisablePrivateDialog = false },
title = stringResource(R.string.disable_private_group),
text = stringResource(R.string.sure_disable_private_group),
confirmText = stringResource(android.R.string.ok),
onConfirm = {
isPrivate = false
showDisablePrivateDialog = false
},
dismissText = stringResource(android.R.string.cancel),
onDismiss = { showDisablePrivateDialog = false }
)
}
@Composable
@@ -247,7 +283,9 @@ fun GroupDeleteAction(
show = showDeleteDialog,
onDismissRequest = { showDeleteDialog = false },
title = stringResource(R.string.delete),
text = stringResource(R.string.sure_del),
text = stringResource(
if (group.isPrivate) R.string.sure_del_private_group else R.string.sure_del
),
confirmText = stringResource(android.R.string.ok),
onConfirm = {
showDeleteDialog = false
@@ -24,6 +24,7 @@ class GroupViewModel(
groupName: String,
bookSort: Int,
enableRefresh: Boolean,
isPrivate: Boolean,
cover: String?,
finally: () -> Unit
) {
@@ -35,6 +36,7 @@ class GroupViewModel(
cover = cover,
bookSort = bookSort,
enableRefresh = enableRefresh,
isPrivate = isPrivate,
order = bookGroupRepository.getMaxOrder().plus(1)
)
bookGroupRepository.getByID(groupId) ?: removeBookGroupAssignmentUseCase.execute(groupId)
@@ -138,6 +138,7 @@ fun GroupSelectSheet(
) {
var selectedGroupId by remember(currentGroupId, show) { mutableLongStateOf(currentGroupId) }
var editingGroup by remember(show) { mutableStateOf<BookGroup?>(null) }
var showAddGroup by remember(show) { mutableStateOf(false) }
AppModalBottomSheet(
show = show,
@@ -145,7 +146,7 @@ fun GroupSelectSheet(
title = stringResource(R.string.group_select),
startAction = {
MediumPlainButton(
onClick = { editingGroup = BookGroup() },
onClick = { showAddGroup = true },
icon = Icons.Default.Add
)
},
@@ -198,7 +199,14 @@ fun GroupSelectSheet(
Spacer(modifier = Modifier.height(12.dp))
}
}
GroupEditSheet(show = editingGroup != null, group = editingGroup, onDismissRequest = { editingGroup = null })
GroupEditSheet(
show = showAddGroup || editingGroup != null,
group = editingGroup,
onDismissRequest = {
showAddGroup = false
editingGroup = null
}
)
}
@OptIn(ExperimentalFoundationApi::class)
@@ -648,4 +656,3 @@ fun ChangeSourceSheet(
}
)
}
@@ -11,7 +11,8 @@ data class BookGroupUi(
val order: Int,
val enableRefresh: Boolean,
val show: Boolean,
val bookSort: Int
val bookSort: Int,
val isPrivate: Boolean
)
fun BookGroup.toBookGroupUi() = BookGroupUi(
@@ -21,5 +22,6 @@ fun BookGroup.toBookGroupUi() = BookGroupUi(
order = order,
enableRefresh = enableRefresh,
show = show,
bookSort = bookSort
bookSort = bookSort,
isPrivate = isPrivate
)
@@ -103,6 +103,25 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_cover" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/cb_private"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/private_group"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cb_enable_refresh" />
<TextView
android:id="@+id/tv_private_desc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/private_group_desc"
android:textAppearance="?attr/textAppearanceBodySmall"
android:textColor="?attr/colorOnSurfaceVariant"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/cb_private"
app:layout_constraintTop_toBottomOf="@id/cb_private" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -570,6 +570,8 @@
<string name="no"></string>
<string name="sure">确认</string>
<string name="sure_del">是否确认删除?</string>
<string name="sure_del_private_group">删除后,相关书籍可能在公开书架中显示,是否确认删除?</string>
<string name="sure_disable_private_group">关闭后,本组书籍可能在公开书架中显示,是否确认关闭?</string>
<string name="sure_del_any">是否确认删除 %s ?</string>
<string name="sure_del_all_book">是否删除全部书籍?</string>
<string name="sure_del_download_book">是否同时删除已下载的书籍目录?</string>
@@ -1207,6 +1209,9 @@
<string name="file_manage_summary">管理私有文件夹的文件</string>
<string name="create_folder">创建文件夹</string>
<string name="allow_drop_down_refresh">允许下拉刷新</string>
<string name="private_group">设为隐私分组</string>
<string name="disable_private_group">关闭隐私分组</string>
<string name="private_group_desc">开启后,本分组内的书籍将从公开书架隐藏</string>
<string name="text_underline">文字下划线</string>
<string name="select_new_source">选中新增源</string>
<string name="select_update_source">选中更新源</string>
@@ -508,6 +508,8 @@
<string name="no">唔係</string>
<string name="sure">確認</string>
<string name="sure_del">是否確認刪除?</string>
<string name="sure_del_private_group">刪除後,相關書籍可能喺公開書架中顯示,是否確認刪除?</string>
<string name="sure_disable_private_group">關閉後,本組書籍可能喺公開書架中顯示,是否確認關閉?</string>
<string name="sure_del_any">是否確認刪除 %s</string>
<string name="sure_del_all_book">是否刪除全部書籍?</string>
<string name="sure_del_download_book">是否同時刪除已下載的書籍目錄?</string>
@@ -1137,6 +1139,9 @@
<string name="file_manage_summary">管理私有文件夹的文件</string>
<string name="create_folder">创建文件夹</string>
<string name="allow_drop_down_refresh">允许下拉刷新</string>
<string name="private_group">設為私隱分組</string>
<string name="disable_private_group">關閉私隱分組</string>
<string name="private_group_desc">開啟後,本分組內嘅書籍將從公開書架隱藏</string>
<string name="text_underline">文字下划线</string>
<string name="select_new_source">选中新增源</string>
<string name="select_update_source">选中更新源</string>
@@ -517,6 +517,8 @@
<string name="no"></string>
<string name="sure">確認</string>
<string name="sure_del">是否確認刪除?</string>
<string name="sure_del_private_group">刪除後,相關書籍可能在公開書架中顯示,是否確認刪除?</string>
<string name="sure_disable_private_group">關閉後,本組書籍可能在公開書架中顯示,是否確認關閉?</string>
<string name="sure_del_any">是否確認刪除 %s</string>
<string name="sure_del_all_book">是否刪除全部書籍?</string>
<string name="sure_del_download_book">是否同時刪除已下載的書籍目錄?</string>
@@ -1140,6 +1142,9 @@
<string name="file_manage_summary">管理私有文件夹的文件</string>
<string name="create_folder">创建文件夹</string>
<string name="allow_drop_down_refresh">允许下拉刷新</string>
<string name="private_group">設為隱私分組</string>
<string name="disable_private_group">關閉隱私分組</string>
<string name="private_group_desc">開啟後,本分組內的書籍將從公開書架隱藏</string>
<string name="text_underline">文字下划线</string>
<string name="select_new_source">选中新增源</string>
<string name="select_update_source">选中更新源</string>
+5
View File
@@ -591,6 +591,8 @@
<string name="no">No</string>
<string name="sure">OK</string>
<string name="sure_del">Are you sure to delete it?</string>
<string name="sure_del_private_group">Related books may appear in public bookshelf views after deletion. Are you sure to delete?</string>
<string name="sure_disable_private_group">Books in this group may appear in public bookshelf views after disabling. Are you sure to disable?</string>
<string name="sure_del_any">Are you sure to delete %s?</string>
<string name="sure_del_all_book">Are you sure to delete all books</string>
<string name="sure_del_download_book">Do you want to delete the downloaded book chapters at the same time?</string>
@@ -1245,6 +1247,9 @@
<string name="file_manage_summary">Managing files in the application\'s private folder</string>
<string name="create_folder">Create Folder</string>
<string name="allow_drop_down_refresh">Allow drop-down refresh</string>
<string name="private_group">Set as private group</string>
<string name="disable_private_group">Disable private group</string>
<string name="private_group_desc">After enabling, books in this group are hidden from the public bookshelf</string>
<string name="text_underline">Text underline</string>
<string name="select_new_source">Select new source</string>
<string name="select_update_source">Select update source</string>