允许书籍共存
This commit is contained in:
@@ -65,7 +65,7 @@ val appDb by lazy {
|
||||
}
|
||||
|
||||
@Database(
|
||||
version = 76,
|
||||
version = 77,
|
||||
exportSchema = true,
|
||||
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
|
||||
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
|
||||
@@ -106,7 +106,8 @@ val appDb by lazy {
|
||||
AutoMigration(from = 72, to = 73),
|
||||
AutoMigration(from = 73, to = 74),
|
||||
AutoMigration(from = 74, to = 75),
|
||||
AutoMigration(from = 75, to = 76)
|
||||
AutoMigration(from = 75, to = 76),
|
||||
AutoMigration(from = 76, to = 77)
|
||||
]
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
@@ -33,7 +33,7 @@ import kotlin.math.max
|
||||
@TypeConverters(Book.Converters::class)
|
||||
@Entity(
|
||||
tableName = "books",
|
||||
indices = [Index(value = ["name", "author"], unique = true)]
|
||||
indices = [Index(value = ["name", "author"], unique = false)]
|
||||
)
|
||||
data class Book(
|
||||
// 详情页Url(本地书源存储完整文件路径)
|
||||
|
||||
@@ -61,6 +61,7 @@ import io.legato.kazusa.utils.showDialogFragment
|
||||
import io.legato.kazusa.utils.startActivity
|
||||
import io.legato.kazusa.utils.startActivityForBook
|
||||
import io.legato.kazusa.utils.startAnimation
|
||||
import io.legato.kazusa.utils.toastOnUi
|
||||
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
|
||||
import io.legato.kazusa.utils.visible
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -688,6 +689,12 @@ class AudioPlayActivity :
|
||||
}
|
||||
}
|
||||
|
||||
override fun addToBookshelf(book: Book, toc: List<BookChapter>) {
|
||||
viewModel.addToBookshelf(book, toc) {
|
||||
toastOnUi("已添加到书架")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun Int.copy(alpha: Float): Int {
|
||||
|
||||
@@ -117,4 +117,21 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
|
||||
}
|
||||
}
|
||||
|
||||
fun addToBookshelf(book: Book, toc: List<BookChapter>, success: (() -> Unit)? = null) {
|
||||
execute {
|
||||
book.removeType(BookType.notShelf)
|
||||
if (book.order == 0) {
|
||||
book.order = appDb.bookDao.minOrder - 1
|
||||
}
|
||||
|
||||
appDb.bookDao.insert(book)
|
||||
appDb.bookChapterDao.insert(*toc.toTypedArray())
|
||||
}.onSuccess {
|
||||
success?.invoke()
|
||||
}.onError {
|
||||
AppLog.put("添加书籍到书架失败", it)
|
||||
context.toastOnUi("添加书籍失败")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.base.BaseBottomSheetDialogFragment
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.constant.BookType
|
||||
import io.legato.kazusa.constant.EventBus
|
||||
import io.legato.kazusa.data.appDb
|
||||
import io.legato.kazusa.data.entities.Book
|
||||
@@ -29,6 +30,7 @@ import io.legato.kazusa.data.entities.SearchBook
|
||||
import io.legato.kazusa.databinding.DialogBookChangeSourceBinding
|
||||
import io.legato.kazusa.help.config.AppConfig
|
||||
import io.legato.kazusa.lib.dialogs.alert
|
||||
import io.legato.kazusa.model.ReadBook
|
||||
import io.legato.kazusa.ui.book.read.ReadBookActivity
|
||||
import io.legato.kazusa.ui.book.source.edit.BookSourceEditActivity
|
||||
import io.legato.kazusa.ui.book.source.manage.BookSourceActivity
|
||||
@@ -40,6 +42,7 @@ import io.legato.kazusa.utils.dpToPx
|
||||
import io.legato.kazusa.utils.getCompatDrawable
|
||||
import io.legato.kazusa.utils.observeEvent
|
||||
import io.legato.kazusa.utils.startActivity
|
||||
import io.legato.kazusa.utils.toastOnUi
|
||||
import io.legato.kazusa.utils.transaction
|
||||
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
|
||||
import io.legato.kazusa.utils.visible
|
||||
@@ -74,6 +77,7 @@ class ChangeBookSourceDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_b
|
||||
val origin = it.data?.getStringExtra("origin") ?: return@registerForActivityResult
|
||||
viewModel.startSearch(origin)
|
||||
}
|
||||
private var currentSelectedSearchBook: SearchBook? = null
|
||||
private val searchFinishCallback: (isEmpty: Boolean) -> Unit = {
|
||||
if (it) {
|
||||
val searchGroup = AppConfig.searchGroup
|
||||
@@ -327,23 +331,65 @@ class ChangeBookSourceDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_b
|
||||
}
|
||||
|
||||
override fun changeTo(searchBook: SearchBook) {
|
||||
currentSelectedSearchBook = searchBook
|
||||
showChangeSourceOptionDialog(searchBook)
|
||||
}
|
||||
|
||||
private fun showChangeSourceOptionDialog(searchBook: SearchBook) {
|
||||
val oldBookType = callBack?.oldBook?.type ?: 0
|
||||
if (searchBook.sameBookTypeLocal(oldBookType)) {
|
||||
changeSource(searchBook) {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!searchBook.sameBookTypeLocal(oldBookType)) {
|
||||
alert(
|
||||
titleResource = R.string.book_type_different,
|
||||
messageResource = R.string.soure_change_source
|
||||
) {
|
||||
okButton {
|
||||
changeSource(searchBook) {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
showChangeSourceActionDialog(searchBook)
|
||||
}
|
||||
cancelButton()
|
||||
}
|
||||
} else {
|
||||
showChangeSourceActionDialog(searchBook)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showChangeSourceActionDialog(searchBook: SearchBook) {
|
||||
context?.alert(getString(R.string.change_source_option_title)) {
|
||||
positiveButton(getString(R.string.replace_current_book)) {
|
||||
performChangeSource(searchBook, true)
|
||||
}
|
||||
negativeButton(getString(R.string.add_as_new_book)) {
|
||||
performChangeSource(searchBook, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun performChangeSource(searchBook: SearchBook, isReplace: Boolean) {
|
||||
val baseBook = viewModel.bookMap[searchBook.primaryStr()] ?: searchBook.toBook()
|
||||
val book = baseBook
|
||||
|
||||
waitDialog.setText(if (isReplace) R.string.load_toc else R.string.load_info)
|
||||
waitDialog.show()
|
||||
|
||||
val coroutine = viewModel.getToc(book, { toc, source ->
|
||||
waitDialog.dismiss()
|
||||
if (isReplace) {
|
||||
|
||||
callBack?.changeTo(source, book, toc)
|
||||
dismissAllowingStateLoss()
|
||||
} else {
|
||||
ReadBook.book?.migrateTo(book, toc)
|
||||
callBack?.addToBookshelf(book, toc)
|
||||
context?.toastOnUi(getString(R.string.book_added_to_shelf))
|
||||
}
|
||||
}, {
|
||||
waitDialog.dismiss()
|
||||
AppLog.put("${if (isReplace) "换源" else "添加书籍"}获取目录出错\n$it", it, true)
|
||||
context?.toastOnUi("${if (isReplace) "换源" else "添加书籍"}失败")
|
||||
})
|
||||
|
||||
waitDialog.setOnCancelListener {
|
||||
coroutine.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,6 +503,7 @@ class ChangeBookSourceDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_b
|
||||
interface CallBack {
|
||||
val oldBook: Book?
|
||||
fun changeTo(source: BookSource, book: Book, toc: List<BookChapter>)
|
||||
fun addToBookshelf(book: Book, toc: List<BookChapter>)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1060,4 +1060,9 @@ class BookInfoActivity :
|
||||
}
|
||||
}
|
||||
|
||||
override fun addToBookshelf(book: Book, toc: List<BookChapter>) {
|
||||
viewModel.addToBookshelf(book, toc) {
|
||||
toastOnUi("已添加到书架")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import io.legato.kazusa.data.appDb
|
||||
import io.legato.kazusa.data.entities.Book
|
||||
import io.legato.kazusa.data.entities.BookChapter
|
||||
import io.legato.kazusa.data.entities.BookSource
|
||||
import io.legato.kazusa.data.entities.SearchBook
|
||||
import io.legato.kazusa.exception.NoBooksDirException
|
||||
import io.legato.kazusa.exception.NoStackTraceException
|
||||
import io.legato.kazusa.help.AppWebDav
|
||||
@@ -56,28 +57,17 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
||||
|
||||
fun initData(intent: Intent) {
|
||||
execute {
|
||||
val name = intent.getStringExtra("name") ?: ""
|
||||
val author = intent.getStringExtra("author") ?: ""
|
||||
val bookUrl = intent.getStringExtra("bookUrl") ?: ""
|
||||
appDb.bookDao.getBook(name, author)?.let {
|
||||
appDb.bookDao.getBook(bookUrl)?.let {
|
||||
inBookshelf = !it.isNotShelf
|
||||
upBook(it)
|
||||
return@execute
|
||||
}
|
||||
if (bookUrl.isNotBlank()) {
|
||||
appDb.searchBookDao.getSearchBook(bookUrl)?.toBook()?.let {
|
||||
upBook(it)
|
||||
return@execute
|
||||
}
|
||||
}
|
||||
appDb.searchBookDao.getFirstByNameAuthor(name, author)?.toBook()?.let {
|
||||
appDb.searchBookDao.getSearchBook(bookUrl)?.toBook()?.let {
|
||||
upBook(it)
|
||||
return@execute
|
||||
}
|
||||
throw NoStackTraceException("未找到书籍")
|
||||
}.onError {
|
||||
AppLog.put(it.localizedMessage, it)
|
||||
context.toastOnUi(it.localizedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,9 +75,12 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
||||
execute {
|
||||
val name = intent.getStringExtra("name") ?: ""
|
||||
val author = intent.getStringExtra("author") ?: ""
|
||||
appDb.bookDao.getBook(name, author)?.let { book ->
|
||||
upBook(book)
|
||||
val bookUrl = intent.getStringExtra("bookUrl") ?: ""
|
||||
val book = when {
|
||||
bookUrl.isNotBlank() -> appDb.bookDao.getBook(bookUrl)
|
||||
else -> appDb.bookDao.getBook(name, author)
|
||||
}
|
||||
book?.let { upBook(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,6 +477,24 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun addToBookshelf(book: Book, toc: List<BookChapter>, success: (() -> Unit)? = null) {
|
||||
execute {
|
||||
book.removeType(BookType.notShelf)
|
||||
if (book.order == 0) {
|
||||
book.order = appDb.bookDao.minOrder - 1
|
||||
}
|
||||
|
||||
appDb.bookDao.insert(book)
|
||||
appDb.bookChapterDao.insert(*toc.toTypedArray())
|
||||
}.onSuccess {
|
||||
success?.invoke()
|
||||
}.onError {
|
||||
AppLog.put("添加书籍到书架失败", it)
|
||||
context.toastOnUi("添加书籍失败")
|
||||
}
|
||||
}
|
||||
|
||||
fun upEditBook() {
|
||||
bookData.value?.let {
|
||||
appDb.bookDao.getBook(it.bookUrl)?.let { book ->
|
||||
|
||||
@@ -685,6 +685,7 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
|
||||
bookInfoActivity.launch {
|
||||
putExtra("name", it.name)
|
||||
putExtra("author", it.author)
|
||||
putExtra("bookUrl", it.bookUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -956,5 +957,10 @@ class ReadMangaActivity : VMBaseActivity<ActivityMangaBinding, ReadMangaViewMode
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
override fun addToBookshelf(book: Book, toc: List<BookChapter>) {
|
||||
viewModel.addToBookshelf(book, toc) {
|
||||
toastOnUi("已添加到书架")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -352,4 +352,21 @@ class ReadMangaViewModel(application: Application) : BaseViewModel(application)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addToBookshelf(book: Book, toc: List<BookChapter>, success: (() -> Unit)? = null) {
|
||||
execute {
|
||||
book.removeType(BookType.notShelf)
|
||||
if (book.order == 0) {
|
||||
book.order = appDb.bookDao.minOrder - 1
|
||||
}
|
||||
|
||||
appDb.bookDao.insert(book)
|
||||
appDb.bookChapterDao.insert(*toc.toTypedArray())
|
||||
}.onSuccess {
|
||||
success?.invoke()
|
||||
}.onError {
|
||||
AppLog.put("添加书籍到书架失败", it)
|
||||
context.toastOnUi("添加书籍失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ import io.legato.kazusa.lib.dialogs.alert
|
||||
import io.legato.kazusa.lib.dialogs.selector
|
||||
import io.legato.kazusa.model.ReadAloud
|
||||
import io.legato.kazusa.model.ReadBook
|
||||
import io.legato.kazusa.model.ReadManga
|
||||
import io.legato.kazusa.model.analyzeRule.AnalyzeRule
|
||||
import io.legato.kazusa.model.analyzeRule.AnalyzeRule.Companion.setChapter
|
||||
import io.legato.kazusa.model.analyzeRule.AnalyzeRule.Companion.setCoroutineContext
|
||||
@@ -202,7 +203,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
registerForActivityResult(StartActivityContract(BookInfoActivity::class.java)) {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
setResult(RESULT_DELETED)
|
||||
super.finish()
|
||||
finish()
|
||||
} else {
|
||||
ReadBook.loadOrUpContent()
|
||||
}
|
||||
@@ -1206,10 +1207,11 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
}
|
||||
|
||||
override fun openBookInfoActivity() {
|
||||
ReadBook.book?.let {
|
||||
ReadManga.book?.let {
|
||||
bookInfoActivity.launch {
|
||||
putExtra("name", it.name)
|
||||
putExtra("author", it.author)
|
||||
putExtra("bookUrl", it.bookUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1685,6 +1687,7 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
ReadBook.book?.save()
|
||||
ReadBook.inBookshelf = true
|
||||
setResult(RESULT_OK)
|
||||
super.finish()
|
||||
}
|
||||
noButton { viewModel.removeFromBookshelf { super.finish() } }
|
||||
}
|
||||
@@ -1803,6 +1806,12 @@ class ReadBookActivity : BaseReadBookActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun addToBookshelf(book: Book, toc: List<BookChapter>) {
|
||||
viewModel.addToBookshelf(book, toc) {
|
||||
toastOnUi("已添加到书架")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val RESULT_DELETED = 100
|
||||
}
|
||||
|
||||
@@ -545,4 +545,21 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
|
||||
}
|
||||
}
|
||||
|
||||
fun addToBookshelf(book: Book, toc: List<BookChapter>, success: (() -> Unit)? = null) {
|
||||
execute {
|
||||
book.removeType(BookType.notShelf)
|
||||
if (book.order == 0) {
|
||||
book.order = appDb.bookDao.minOrder - 1
|
||||
}
|
||||
|
||||
appDb.bookDao.insert(book)
|
||||
appDb.bookChapterDao.insert(*toc.toTypedArray())
|
||||
}.onSuccess {
|
||||
success?.invoke()
|
||||
}.onError {
|
||||
AppLog.put("添加书籍到书架失败", it)
|
||||
context.toastOnUi("添加书籍失败")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ class SearchActivity : VMBaseActivity<ActivityBookSearchBinding, SearchViewModel
|
||||
* 搜索结束
|
||||
*/
|
||||
private fun searchFinally() {
|
||||
binding.refreshProgressBar.gone()
|
||||
binding.refreshProgressBar.invisible()
|
||||
binding.cdProgress.gone()
|
||||
if (!isManualStopSearch && viewModel.hasMore) {
|
||||
binding.fbStartStop.setImageResource(R.drawable.ic_play)
|
||||
|
||||
@@ -300,6 +300,7 @@ class BooksFragment() : BaseFragment(R.layout.fragment_books),
|
||||
val intent = Intent(requireContext(), BookInfoActivity::class.java).apply {
|
||||
putExtra("name", book.name)
|
||||
putExtra("author", book.author)
|
||||
putExtra("bookUrl", book.bookUrl)
|
||||
putExtra("transitionName", "book_${book.bookUrl}") // 给共享元素唯一标识
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user