From 5f2991373b0ef21cabd3d15a53c11700d93b9b86 Mon Sep 17 00:00:00 2001 From: atbest Date: Sun, 26 May 2019 00:06:45 -0400 Subject: [PATCH] Added importing book shelf from YueDu --- .../jsonpath/spi/json/GsonJsonProvider.java | 4 +- .../java/io/legado/app/data/dao/BookDao.kt | 11 +++ .../java/io/legado/app/data/entities/Book.kt | 4 +- .../io/legado/app/ui/main/MainActivity.kt | 92 +++++++++++++++---- .../app/ui/replacerule/ReplaceRuleActivity.kt | 14 ++- .../app/ui/replacerule/ReplaceRuleAdapter.kt | 14 +-- .../io/legado/app/utils/MiscExtensions.kt | 5 +- app/src/main/res/drawable/ic_divider.xml | 6 ++ .../main/res/layout/activity_replace_rule.xml | 4 +- app/src/main/res/layout/item_relace_rule.xml | 12 +-- 10 files changed, 128 insertions(+), 38 deletions(-) create mode 100644 app/src/main/res/drawable/ic_divider.xml diff --git a/app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java b/app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java index 0828b2951..ab0ffc9ae 100644 --- a/app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java +++ b/app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java @@ -247,8 +247,8 @@ public class GsonJsonProvider extends AbstractJsonProvider { } } - throw new JsonPathException("length operation can not applied to " + obj != null ? obj.getClass().getName() - : "null"); + throw new JsonPathException("length operation can not applied to " + (obj != null ? obj.getClass().getName() + : "null")); } @Override 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 aae85f47f..0ea2baac1 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 @@ -3,6 +3,8 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData import androidx.paging.DataSource import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import io.legado.app.data.entities.Book @@ -19,4 +21,13 @@ interface BookDao { @Query("SELECT * FROM books WHERE `name` in (:names)") fun findByName(vararg names: String): List + @get:Query("SELECT descUrl FROM books") + val allBookUrls: List + + @get:Query("SELECT COUNT(*) FROM books") + val allBookCount: Int + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(vararg books: Book) + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 1efd170c3..c883ff956 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -30,11 +30,13 @@ data class Book(@PrimaryKey var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间 var lastCheckCount: Int = 0, // 最近一次发现新章节的数量 var totalChapterNum: Int = 0, // 书籍目录总数 - var durChapterTitle: String? = null, // 当前章节名称 + var durChapterTitle: String? = null, // 当前章节名称 var durChapterIndex: Int = 0, // 当前章节索引 var durChapterPos: Int = 0, // 当前阅读的进度(首行字符的索引位置) var durChapterTime: Long = 0, // 最近一次阅读书籍的时间(打开正文的时间) var canUpdate: Boolean = true, // 刷新书架时更新书籍信息 + var order: Int = 0, // 手动排序 + var useReplaceRule: Boolean = true, // 正文使用净化替换规则 var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息) ) : Parcelable { diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index f6fb83294..46cb0096b 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -16,6 +16,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.constant.AppConst.APP_TAG +import io.legado.app.data.entities.Book import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat @@ -107,30 +108,85 @@ class MainActivity : BaseActivity(), NavigationV .build() ) - // Replace rules - val rFile = File(yuedu, "myBookReplaceRule.json") - val replaceRules = mutableListOf() - if (rFile.exists()) try { - val items: List> = jsonPath.parse(rFile.readText()).read("$.*") - for (item in items) { - val jsonItem = jsonPath.parse(item) - val rRule = ReplaceRule() - rRule.name = jsonItem.readString("$.replaceSummary") - rRule.pattern = jsonItem.readString("$.regex") - rRule.replacement = jsonItem.readString("$.replacement") - rRule.isRegex = jsonItem.readBool("$.isRegex") - rRule.scope = jsonItem.readString("$.useTo") - rRule.isEnabled = jsonItem.readBool("$.enable") - rRule.order = jsonItem.readInt("$.serialNumber") - replaceRules.add(rRule) + // 导入书架 + val shelfFile = File(yuedu, "myBookShelf.json") + val books = mutableListOf() + if (shelfFile.exists()) try { + doAsync { + val items: List> = jsonPath.parse(shelfFile.readText()).read("$") + val existingBooks = App.db.bookDao().allBookUrls.toSet() + for (item in items) { + val jsonItem = jsonPath.parse(item) + val book = Book() + book.descUrl = jsonItem.readString("$.noteUrl") ?: "" + if (book.descUrl.isBlank()) continue + book.name = jsonItem.readString("$.bookInfoBean.name") + if (book.descUrl in existingBooks) { + Log.d(APP_TAG, "Found existing book: ${book.name}") + continue + } + book.author = jsonItem.readString("$.bookInfoBean.author") + book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 + book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.descUrl + book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl") + book.customCoverUrl = jsonItem.readString("$.customCoverPath") + book.lastCheckTime = jsonItem.readLong("$.bookInfoBean.finalRefreshData") ?: 0 + book.canUpdate = jsonItem.readBool("$.allowUpdate") == true + book.totalChapterNum = jsonItem.readInt("$.chapterListSize") ?: 0 + book.durChapterIndex = jsonItem.readInt("$.durChapter") ?: 0 + book.durChapterTitle = jsonItem.readString("$.durChapterName") + book.durChapterPos = jsonItem.readInt("$.durChapterPage") ?: 0 + book.durChapterTime = jsonItem.readLong("$.finalDate") ?: 0 + book.group = jsonItem.readInt("$.group") ?: 0 + // book. = jsonItem.readString("$.hasUpdate") + // book. = jsonItem.readString("$.isLoading") + book.latestChapterTitle = jsonItem.readString("$.lastChapterName") + book.lastCheckCount = jsonItem.readInt("$.newChapters") ?: 0 + book.order = jsonItem.readInt("$.serialNumber") ?: 0 + book.useReplaceRule = jsonItem.readBool("$.useReplaceRule") == true + book.variable = jsonItem.readString("$.variable") + books.add(book) + Log.d(APP_TAG, "Added ${book.name}") + } + App.db.bookDao().insert(*books.toTypedArray()) + val count = books.size + + uiThread { + toast(if (count > 0) "成功地导入 $count 本新书和音频" else "没有发现新书或音频") + } + } + } catch (e: Exception) { + Log.e(APP_TAG, "Failed to import book shelf.", e) + toast("Unable to import books:\n${e.localizedMessage}") + } + + // Replace rules + val ruleFile = File(yuedu, "myBookReplaceRule.json") + val replaceRules = mutableListOf() + if (ruleFile.exists()) try { doAsync { + val items: List> = jsonPath.parse(ruleFile.readText()).read("$") + val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() + for (item in items) { + val jsonItem = jsonPath.parse(item) + val rRule = ReplaceRule() + rRule.pattern = jsonItem.readString("$.regex") + if (rRule.pattern.isNullOrEmpty() || rRule.pattern in existingRules) continue + rRule.name = jsonItem.readString("$.replaceSummary") + rRule.replacement = jsonItem.readString("$.replacement") + rRule.isRegex = jsonItem.readBool("$.isRegex") == true + rRule.scope = jsonItem.readString("$.useTo") + rRule.isEnabled = jsonItem.readBool("$.enable") == true + rRule.order = jsonItem.readInt("$.serialNumber") ?: 0 + replaceRules.add(rRule) + } App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) - val count = items.size + val count = replaceRules.size val maxId = App.db.replaceRuleDao().maxOrder uiThread { - toast("成功地导入 $count 条净化替换规则") + toast(if (count > 0) "成功地导入 $count 条净化替换规则" else "没有发现新的净化替换规则") } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 8f6077c96..5d0ebadc6 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -1,11 +1,14 @@ package io.legado.app.ui.replacerule import android.os.Bundle +import android.util.Log import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R @@ -15,6 +18,8 @@ import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.ItemTouchHelper +import io.legado.app.constant.AppConst.APP_TAG +import kotlinx.android.synthetic.main.item_relace_rule.* class ReplaceRuleActivity : AppCompatActivity() { @@ -25,7 +30,6 @@ class ReplaceRuleActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_replace_rule) - rv_replace_rule.layoutManager = LinearLayoutManager(this) initRecyclerView() initDataObservers() initSwipeToDelete() @@ -57,6 +61,12 @@ class ReplaceRuleActivity : AppCompatActivity() { } } rv_replace_rule.adapter = adapter + rv_replace_rule.addItemDecoration( + DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { + ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let { + Log.e(APP_TAG, it.toString()) + this.setDrawable(it) } + }) } private fun initDataObservers() { @@ -90,7 +100,7 @@ class ReplaceRuleActivity : AppCompatActivity() { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { toast("You swiped the item!") - TODO() + // TODO() // remove((viewHolder as TodoViewHolder).todo) } }).attachToRecyclerView(rv_replace_rule) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index a767cee52..d9befdd97 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.replacerule import android.content.Context +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,6 +10,7 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R +import io.legado.app.constant.AppConst.APP_TAG import io.legado.app.data.entities.ReplaceRule import kotlinx.android.synthetic.main.item_relace_rule.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -45,16 +47,16 @@ class ReplaceRuleAdapter(context: Context) : } override fun onBindViewHolder(holder: MyViewHolder, pos: Int) { - getItem(pos)?.let { holder.bind(it, onClickListener, pos == itemCount - 1) } + getItem(pos)?.let { holder.bind(it, onClickListener) } } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(rule: ReplaceRule, listener: OnClickListener?, hideDivider: Boolean) = with(itemView) { + fun bind(rule: ReplaceRule, listener: OnClickListener?) = with(itemView) { tv_name.text = rule.name - swt_enabled.isChecked = rule.isEnabled - divider.isGone = hideDivider - iv_delete.isGone = true - iv_edit.isGone = true + swt_enabled.isChecked = rule.isEnabled + // divider.isGone = hideDivider + iv_delete.isGone = true + iv_edit.isGone = true // iv_delete.onClick { listener?.delete(rule) } // iv_edit.onClick { listener?.edit(rule) } swt_enabled.onClick { diff --git a/app/src/main/java/io/legado/app/utils/MiscExtensions.kt b/app/src/main/java/io/legado/app/utils/MiscExtensions.kt index 1f47d2af9..84665cd8c 100644 --- a/app/src/main/java/io/legado/app/utils/MiscExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/MiscExtensions.kt @@ -6,4 +6,7 @@ fun ReadContext.readString(path: String): String? = this.read(path, String::clas fun ReadContext.readBool(path: String): Boolean? = this.read(path, Boolean::class.java) -fun ReadContext.readInt(path: String): Int? = this.read(path, Int::class.java) \ No newline at end of file +fun ReadContext.readInt(path: String): Int? = this.read(path, Int::class.java) + +fun ReadContext.readLong(path: String): Long? = this.read(path, Long::class.java) + diff --git a/app/src/main/res/drawable/ic_divider.xml b/app/src/main/res/drawable/ic_divider.xml new file mode 100644 index 000000000..7515c3960 --- /dev/null +++ b/app/src/main/res/drawable/ic_divider.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/layout/activity_replace_rule.xml b/app/src/main/res/layout/activity_replace_rule.xml index d2d3d92e8..c16af5b11 100644 --- a/app/src/main/res/layout/activity_replace_rule.xml +++ b/app/src/main/res/layout/activity_replace_rule.xml @@ -18,8 +18,8 @@ android:id="@+id/rv_replace_rule" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingStart="8dp" - android:paddingEnd="8dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" android:layout_marginBottom="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/item_relace_rule.xml b/app/src/main/res/layout/item_relace_rule.xml index c739121b9..34e28b5c9 100644 --- a/app/src/main/res/layout/item_relace_rule.xml +++ b/app/src/main/res/layout/item_relace_rule.xml @@ -4,9 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingStart="8dp" - android:paddingEnd="8dp"> + android:layout_height="wrap_content"> - +