From 4b65d6fc7140f4d0c72c7cd32f6022fc26c2ceaf Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Sat, 27 Jun 2026 02:16:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=BF=9E=E8=BD=BD?= =?UTF-8?q?=E5=B7=B2=E8=AF=BB/=E5=AE=8C=E6=9C=AC=E5=B7=B2=E8=AF=BB?= =?UTF-8?q?=E5=88=86=E7=BB=84=EF=BC=8C=E5=9F=BA=E4=BA=8EcanUpdate=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E8=87=AA=E5=8A=A8=E5=88=86=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/data/AppDatabase.kt | 27 +++- .../java/io/legado/app/data/dao/BookDao.kt | 119 ++++++++++++++++++ .../io/legado/app/data/dao/BookGroupDao.kt | 14 +++ .../io/legado/app/data/entities/BookGroup.kt | 4 + app/src/main/res/values-zh-rCN/strings.xml | 37 ++++++ app/src/main/res/values/strings.xml | 37 ++++++ 6 files changed, 235 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index f271331dd..2c9e54727 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -16,6 +16,8 @@ import io.legado.app.data.dao.CacheDao import io.legado.app.data.dao.CookieDao import io.legado.app.data.dao.DictRuleDao import io.legado.app.data.dao.HighlightRuleDao +import io.legado.app.data.dao.HighlightTagRuleDao +import io.legado.app.data.dao.TagGroupRuleDao import io.legado.app.data.dao.HomepageCustomSetDao import io.legado.app.data.dao.HomepageModuleDao import io.legado.app.data.dao.HttpTTSDao @@ -42,6 +44,8 @@ import io.legado.app.data.entities.Cache import io.legado.app.data.entities.Cookie import io.legado.app.data.entities.DictRule import io.legado.app.data.entities.HighlightRule +import io.legado.app.data.entities.HighlightTagRule +import io.legado.app.data.entities.TagGroupRule import io.legado.app.data.entities.HomepageCustomSet import io.legado.app.data.entities.HomepageModule import io.legado.app.data.entities.HttpTTS @@ -75,7 +79,7 @@ val appDb by lazy { } @Database( - version = 91, + version = 92, exportSchema = true, entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class, @@ -84,7 +88,7 @@ val appDb by lazy { RssStar::class, TxtTocRule::class, ReadRecord::class, HttpTTS::class, Cache::class, RuleSub::class, DictRule::class, KeyboardAssist::class, Server::class, SearchContentHistory::class, HomepageModule::class, HomepageCustomSet::class, - HighlightRule::class], + HighlightRule::class, HighlightTagRule::class, TagGroupRule::class], views = [BookSourcePart::class], autoMigrations = [ AutoMigration(from = 43, to = 44), @@ -134,7 +138,8 @@ val appDb by lazy { AutoMigration(from = 87, to = 88), AutoMigration(from = 88, to = 89), AutoMigration(from = 89, to = 90), - AutoMigration(from = 90, to = 91) + AutoMigration(from = 90, to = 91), + AutoMigration(from = 91, to = 92) ] ) abstract class AppDatabase : RoomDatabase() { @@ -164,6 +169,8 @@ abstract class AppDatabase : RoomDatabase() { abstract val homepageModuleDao: HomepageModuleDao abstract val homepageCustomSetDao: HomepageCustomSetDao abstract val highlightRuleDao: HighlightRuleDao + abstract val highlightTagRuleDao: HighlightTagRuleDao + abstract val tagGroupRuleDao: TagGroupRuleDao companion object { @@ -237,6 +244,20 @@ abstract class AppDatabase : RoomDatabase() { """.trimIndent() db.execSQL(insertGroupReadFinished) @Language("sql") + val insertGroupReadFinishedUpdate = """ + insert into book_groups(groupId, groupName, 'order', show) + select ${BookGroup.IdReadFinishedUpdate}, '连载已读', -27, 1 + where not exists (select * from book_groups where groupId = ${BookGroup.IdReadFinishedUpdate}) + """.trimIndent() + db.execSQL(insertGroupReadFinishedUpdate) + @Language("sql") + val insertGroupReadFinishedComplete = """ + insert into book_groups(groupId, groupName, 'order', show) + select ${BookGroup.IdReadFinishedComplete}, '完本已读', -26, 1 + where not exists (select * from book_groups where groupId = ${BookGroup.IdReadFinishedComplete}) + """.trimIndent() + db.execSQL(insertGroupReadFinishedComplete) + @Language("sql") val insertBookGroupNetNoneGroupSql = """ insert into book_groups(groupId, groupName, 'order', show) select ${BookGroup.IdNetNone}, '网络未分组', -7, 1 diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 7af033094..d4faef07d 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -48,6 +48,8 @@ interface BookDao { BookGroup.IdUnread -> flowUnread() BookGroup.IdReading -> flowReading() BookGroup.IdReadFinished -> flowReadFinished() + BookGroup.IdReadFinishedUpdate -> flowReadFinishedUpdate() + BookGroup.IdReadFinishedComplete -> flowReadFinishedComplete() else -> flowByUserGroup(groupId) }.map { list -> list.filterNot { it.isNotShelf } @@ -68,6 +70,8 @@ interface BookDao { BookGroup.IdUnread -> flowBookShelfUnread() BookGroup.IdReading -> flowBookShelfReading() BookGroup.IdReadFinished -> flowBookShelfReadFinished() + BookGroup.IdReadFinishedUpdate -> flowBookShelfReadFinishedUpdate() + BookGroup.IdReadFinishedComplete -> flowBookShelfReadFinishedComplete() else -> flowBookShelfByUserGroup(groupId) }.map { list -> list.filterNot { it.isNotShelf } @@ -123,6 +127,9 @@ interface BookDao { @Query("SELECT * FROM books order by durChapterTime desc") fun flowAll(): Flow> + @Query("SELECT * FROM books") + suspend fun getAll(): List + @Query( """ SELECT @@ -485,6 +492,80 @@ interface BookDao { ) fun flowBookShelfReadFinished(): Flow> + @Query( + """SELECT * FROM books WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND canUpdate = 1""" + ) + fun flowReadFinishedUpdate(): Flow> + + @Query( + """ + SELECT + bookUrl, + name, + author, + origin, + originName, + coverUrl, + customCoverUrl, + durChapterTitle, + durChapterTime, + durChapterPos, + latestChapterTitle, + latestChapterTime, + lastCheckCount, + totalChapterNum, + durChapterIndex, + type, + `group`, + `order`, + canUpdate, + ifnull(customIntro, intro) as intro, + kind, + wordCount + FROM books + WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND canUpdate = 1 + AND $PUBLIC_BOOK_FILTER + """ + ) + fun flowBookShelfReadFinishedUpdate(): Flow> + + @Query( + """SELECT * FROM books WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND canUpdate = 0""" + ) + fun flowReadFinishedComplete(): Flow> + + @Query( + """ + SELECT + bookUrl, + name, + author, + origin, + originName, + coverUrl, + customCoverUrl, + durChapterTitle, + durChapterTime, + durChapterPos, + latestChapterTitle, + latestChapterTime, + lastCheckCount, + totalChapterNum, + durChapterIndex, + type, + `group`, + `order`, + canUpdate, + ifnull(customIntro, intro) as intro, + kind, + wordCount + FROM books + WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND canUpdate = 0 + AND $PUBLIC_BOOK_FILTER + """ + ) + fun flowBookShelfReadFinishedComplete(): Flow> + @Query("""SELECT * FROM books WHERE totalChapterNum > 0 AND durChapterIndex > 0 AND durChapterIndex < totalChapterNum - 1""") fun flowReading(): Flow> @@ -728,6 +809,8 @@ interface BookDao { 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 + UNION ALL SELECT ${BookGroup.IdReadFinishedUpdate}, COUNT(*) FROM books WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND canUpdate = 1 AND $PUBLIC_BOOK_FILTER + UNION ALL SELECT ${BookGroup.IdReadFinishedComplete}, COUNT(*) FROM books WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND canUpdate = 0 AND $PUBLIC_BOOK_FILTER """ ) fun flowSystemGroupCounts(): Flow> @@ -755,6 +838,8 @@ interface BookDao { BookGroup.IdUnread -> flowBookShelfUnreadPreview() BookGroup.IdReading -> flowBookShelfReadingPreview() BookGroup.IdReadFinished -> flowBookShelfReadFinishedPreview() + BookGroup.IdReadFinishedUpdate -> flowBookShelfReadFinishedUpdatePreview() + BookGroup.IdReadFinishedComplete -> flowBookShelfReadFinishedCompletePreview() else -> flowBookShelfPreviewByUserGroup(groupId) }.map { list -> list.filterNot { it.isNotShelf } @@ -968,6 +1053,40 @@ interface BookDao { ) fun flowBookShelfReadFinishedPreview(): Flow> + @Query( + """ + SELECT bookUrl, name, author, origin, originName, + coverUrl, customCoverUrl, durChapterTitle, durChapterTime, + durChapterPos, latestChapterTitle, latestChapterTime, + lastCheckCount, totalChapterNum, durChapterIndex, + type, `group`, `order`, canUpdate, + ifnull(customIntro, intro) as intro, kind, wordCount + FROM books + WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND canUpdate = 1 + AND $PUBLIC_BOOK_FILTER + ORDER BY durChapterTime DESC + LIMIT 10 + """ + ) + fun flowBookShelfReadFinishedUpdatePreview(): Flow> + + @Query( + """ + SELECT bookUrl, name, author, origin, originName, + coverUrl, customCoverUrl, durChapterTitle, durChapterTime, + durChapterPos, latestChapterTitle, latestChapterTime, + lastCheckCount, totalChapterNum, durChapterIndex, + type, `group`, `order`, canUpdate, + ifnull(customIntro, intro) as intro, kind, wordCount + FROM books + WHERE totalChapterNum > 0 AND durChapterIndex >= totalChapterNum - 1 AND canUpdate = 0 + AND $PUBLIC_BOOK_FILTER + ORDER BY durChapterTime DESC + LIMIT 10 + """ + ) + fun flowBookShelfReadFinishedCompletePreview(): Flow> + @Query( """ SELECT bookUrl, name, author, origin, originName, diff --git a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt index ba96cc9ea..d27ea74c0 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt @@ -80,6 +80,20 @@ interface BookGroupDao { AND durChapterPos != 0 AND (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0) )) + or (groupId = ${BookGroup.IdReadFinishedUpdate} and exists ( + SELECT 1 FROM books + WHERE totalChapterNum > 0 + AND durChapterIndex >= totalChapterNum - 1 + AND canUpdate = 1 + AND (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0) + )) + or (groupId = ${BookGroup.IdReadFinishedComplete} and exists ( + SELECT 1 FROM books + WHERE totalChapterNum > 0 + AND durChapterIndex >= totalChapterNum - 1 + AND canUpdate = 0 + AND (`group` = 0 or (const.sumPrivateGroupId & `group`) = 0) + )) or (groupId = ${BookGroup.IdError} and exists ( select 1 from books diff --git a/app/src/main/java/io/legado/app/data/entities/BookGroup.kt b/app/src/main/java/io/legado/app/data/entities/BookGroup.kt index 8809dd3b5..6081c56f6 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookGroup.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookGroup.kt @@ -41,6 +41,8 @@ data class BookGroup( const val IdReading = -20L const val IdUnread = -21L const val IdReadFinished = -22L + const val IdReadFinishedUpdate = -23L + const val IdReadFinishedComplete = -24L } data class GroupNameInfo( @@ -61,6 +63,8 @@ data class BookGroup( IdReading -> GroupNameInfo(groupName, context.getString(R.string.is_reading)) IdUnread -> GroupNameInfo(groupName, context.getString(R.string.is_unread)) IdReadFinished -> GroupNameInfo(groupName, context.getString(R.string.is_read_finished)) + IdReadFinishedUpdate -> GroupNameInfo(groupName, context.getString(R.string.is_read_finished_update)) + IdReadFinishedComplete -> GroupNameInfo(groupName, context.getString(R.string.is_read_finished_complete)) else -> GroupNameInfo(groupName) } } diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index f6607f776..cdde3657e 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -660,6 +660,7 @@ 页脚字号 选择图片 分组管理 + 新建分组 分组选择 编辑分组 移入分组 @@ -1670,6 +1671,8 @@ 在读 未读 已读 + 连载已读 + 完本已读 漫画 小说 显示字体阴影 @@ -1947,4 +1950,38 @@ 仅在配置的时间段内生效 开始时间 结束时间 + + + 标签规则 + 导入标签规则 + 标题 + 匹配规则 + 暂无醒目标签规则。添加规则可在书籍信息页面突出显示特定标签。 + 添加规则 + 编辑规则 + 标题(可选) + 正则表达式(如 (\\d+)字) + 显示模式 + 水平 + 竖向 + 测试 + 输入测试文本 + 测试匹配 + 匹配:%1$s + 匹配:%1$s | %2$s + 未匹配 + 错误:%1$s + + + 醒目标签 + 标签分组 + 新建标签分组 + 编辑分组规则 + 分组名称 + 匹配规则(匹配书籍标签) + 暂无标签分组规则。添加规则可根据书籍标签自动分组。 + 同步标签分组 + 标签分组规则 + 分组同步完成 + 导入分组规则 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b076dd43a..70ef2dcb9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -686,6 +686,7 @@ Footer Font Size Select a picture Group Management + New Group Group selection Group editing Move to group @@ -1707,6 +1708,8 @@ Reading Unread Finished + Finished (Serial) + Finished (Completed) Manga Novel Show Font Shadow @@ -1956,4 +1959,38 @@ Only apply during the configured time range Start Time End Time + + + Tag Rules + Import Tag Rules + Title + Pattern + No highlight tag rules configured. Add rules to highlight specific tags on the book info screen. + Add Rule + Edit Rule + Title (optional) + Regex pattern (e.g. (\\d+)字) + Display Mode + Horizontal + Vertical + Test + Enter test text + Test Match + Matched: %1$s + Matched: %1$s | %2$s + No match + Error: %1$s + + + Highlight + Group + New Tag Group + Edit Group Rule + Group Name + Pattern (matches kind tags) + No tag group rules configured. Add rules to auto-group books by their kind tags. + Sync Tag Groups + Tag Group Rules + Group sync complete + Import Tag Group Rules