| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- package io.legato.kazusa.ui.association
- import android.annotation.SuppressLint
- import android.app.Application
- import android.content.DialogInterface
- import android.os.Bundle
- import android.view.View
- import android.view.ViewGroup
- import androidx.core.view.isVisible
- import androidx.fragment.app.viewModels
- import androidx.lifecycle.MutableLiveData
- import io.legato.kazusa.R
- import io.legato.kazusa.base.BaseDialogFragment
- import io.legato.kazusa.base.BaseViewModel
- import io.legato.kazusa.constant.AppLog
- import io.legato.kazusa.data.appDb
- import io.legato.kazusa.data.entities.Book
- import io.legato.kazusa.data.entities.BookSource
- import io.legato.kazusa.databinding.DialogAddToBookshelfBinding
- import io.legato.kazusa.exception.NoStackTraceException
- import io.legato.kazusa.model.analyzeRule.AnalyzeUrl
- import io.legato.kazusa.model.webBook.WebBook
- import io.legato.kazusa.ui.book.info.BookInfoActivity
- import io.legato.kazusa.utils.GSON
- import io.legato.kazusa.utils.NetworkUtils
- import io.legato.kazusa.utils.fromJsonObject
- import io.legato.kazusa.utils.setLayout
- import io.legato.kazusa.utils.startActivity
- import io.legato.kazusa.utils.toastOnUi
- import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
- /**
- * 添加书籍链接到书架,需要对应网站书源
- * ${origin}/${path}, {origin: bookSourceUrl}
- * 按以下顺序尝试匹配书源并添加网址
- * - UrlOption中的指定的书源网址bookSourceUrl
- * - 在所有启用的书源中匹配orgin
- * - 在所有启用的书源中使用详情页正则匹配${origin}/${path}, {origin: bookSourceUrl}
- */
- class AddToBookshelfDialog() : BaseDialogFragment(R.layout.dialog_add_to_bookshelf) {
- constructor(bookUrl: String, finishOnDismiss: Boolean = false) : this() {
- arguments = Bundle().apply {
- putString("bookUrl", bookUrl)
- putBoolean("finishOnDismiss", finishOnDismiss)
- }
- }
- val binding by viewBinding(DialogAddToBookshelfBinding::bind)
- val viewModel by viewModels<ViewModel>()
- override fun onStart() {
- super.onStart()
- setLayout(0.9f, ViewGroup.LayoutParams.WRAP_CONTENT)
- }
- override fun onDismiss(dialog: DialogInterface) {
- super.onDismiss(dialog)
- if (arguments?.getBoolean("finishOnDismiss") == true) {
- activity?.finish()
- }
- }
- @SuppressLint("SetTextI18n")
- override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
- val bookUrl = arguments?.getString("bookUrl")
- if (bookUrl.isNullOrBlank()) {
- toastOnUi("url不能为空")
- dismiss()
- return
- }
- viewModel.loadStateLiveData.observe(this) {
- if (it) {
- binding.rotateLoading.isVisible = true
- } else {
- binding.rotateLoading.isVisible = true
- }
- }
- viewModel.loadErrorLiveData.observe(this) {
- toastOnUi(it)
- dismiss()
- }
- viewModel.load(bookUrl) {
- viewModel.saveSearchBook(it) {
- startActivity<BookInfoActivity> {
- putExtra("name", it.name)
- putExtra("author", it.author)
- putExtra("bookUrl", it.bookUrl)
- }
- dismiss()
- }
- }
- binding.tvCancel.setOnClickListener {
- dismiss()
- }
- }
- class ViewModel(application: Application) : BaseViewModel(application) {
- val loadStateLiveData = MutableLiveData<Boolean>()
- val loadErrorLiveData = MutableLiveData<String>()
- var book: Book? = null
- fun load(bookUrl: String, success: (book: Book) -> Unit) {
- execute {
- appDb.bookDao.getBook(bookUrl)?.let {
- throw NoStackTraceException("${it.name} 已在书架")
- }
- val baseUrl = NetworkUtils.getBaseUrl(bookUrl)
- ?: throw NoStackTraceException("书籍地址格式不对")
- val urlMatcher = AnalyzeUrl.paramPattern.matcher(bookUrl)
- if (urlMatcher.find()) {
- val origin = GSON.fromJsonObject<AnalyzeUrl.UrlOption>(
- bookUrl.substring(urlMatcher.end())
- ).getOrNull()?.getOrigin()
- origin?.let {
- val source = appDb.bookSourceDao.getBookSource(it)
- source?.let {
- getBookInfo(bookUrl, source)?.let { book ->
- return@execute book
- }
- }
- }
- }
- appDb.bookSourceDao.getBookSourceAddBook(baseUrl)?.let { source ->
- getBookInfo(bookUrl, source)?.let { book ->
- return@execute book
- }
- }
- appDb.bookSourceDao.hasBookUrlPattern.forEach { source ->
- try {
- val bs = source.getBookSource()!!
- if (bookUrl.matches(bs.bookUrlPattern!!.toRegex())) {
- getBookInfo(bookUrl, bs)?.let { book ->
- return@execute book
- }
- }
- } catch (_: Exception) {
- }
- }
- throw NoStackTraceException("未找到匹配书源")
- }.onError {
- AppLog.put("添加书籍 $bookUrl 出错", it)
- loadErrorLiveData.postValue(it.localizedMessage)
- }.onSuccess {
- book = it
- success.invoke(it)
- }.onStart {
- loadStateLiveData.postValue(true)
- }.onFinally {
- loadStateLiveData.postValue(false)
- }
- }
- private suspend fun getBookInfo(bookUrl: String, source: BookSource): Book? {
- return kotlin.runCatching {
- val book = Book(
- bookUrl = bookUrl,
- origin = source.bookSourceUrl,
- originName = source.bookSourceName
- )
- WebBook.getBookInfoAwait(source, book)
- }.getOrNull()
- }
- fun saveSearchBook(book: Book, success: () -> Unit) {
- execute {
- val searchBook = book.toSearchBook()
- appDb.searchBookDao.insert(searchBook)
- searchBook
- }.onSuccess {
- success.invoke()
- }
- }
- }
- }
|