Merge remote-tracking branch 'origin/master'

pull/32/head
gedoor 6 years ago
commit 800f0609d6
  1. 3
      app/src/main/java/io/legado/app/base/BaseActivity.kt
  2. 71
      app/src/main/java/io/legado/app/data/dao/ExploreSearchUrlDao.kt
  3. 1
      app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt
  4. 32
      app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt
  5. 29
      app/src/main/java/io/legado/app/data/entities/ExploreSearchUrl.kt
  6. 17
      app/src/main/java/io/legado/app/data/entities/SearchKeyword.kt
  7. 27
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt
  8. 16
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt
  9. 6
      app/src/main/java/io/legado/app/utils/MiscExtensions.kt
  10. 59
      app/src/main/res/layout/item_relace_rule.xml
  11. 1
      app/src/main/res/values/strings.xml

@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModel
import com.google.android.material.bottomnavigation.BottomNavigationView
abstract class BaseActivity<BD : ViewDataBinding, VM : ViewModel> : AppCompatActivity() {
@ -33,7 +34,7 @@ abstract class BaseActivity<BD : ViewDataBinding, VM : ViewModel> : AppCompatAct
return true
}
}
return if (item == null) false else onCompatOptionsItemSelected(item)
return item != null && onCompatOptionsItemSelected(item)
}
open fun onCompatOptionsItemSelected(item: MenuItem): Boolean {

@ -0,0 +1,71 @@
package io.legado.app.data.dao
import androidx.paging.DataSource
import androidx.room.*
import io.legado.app.data.entities.ExploreSearchUrl
@Dao
interface ExploreSearchUrlDao {
companion object {
private const val ORDER_DEFAULT = "ORDER BY sourceId ASC, defOrder ASC"
private const val ORDER_USAGE = "ORDER BY usage DESC, lastUseTime DESC"
private const val ORDER_TIME = "ORDER BY lastUseTime DESC"
private const val QUERY_NAME = "name LIKE '%' || :name || '%'"
private const val QUERY_ENABLED_EXPLORE = "WHERE type = 0 AND isEnabled = 1"
}
// 用于发现列表,默认排序
@Query("SELECT * FROM explore_search_urls $QUERY_ENABLED_EXPLORE $ORDER_DEFAULT")
fun observeExploreUrls(): DataSource.Factory<Int, ExploreSearchUrl>
// 用于发现列表,按使用次数排序
@Query("SELECT * FROM explore_search_urls $QUERY_ENABLED_EXPLORE $ORDER_USAGE")
fun observeExploreUrlsByUsage(): DataSource.Factory<Int, ExploreSearchUrl>
// 用于发现列表,按使用时间排序
@Query("SELECT * FROM explore_search_urls $QUERY_ENABLED_EXPLORE $ORDER_TIME")
fun observeExploreUrlsByTime(): DataSource.Factory<Int, ExploreSearchUrl>
// 用于搜索时的发现列表,默认排序
@Query("SELECT * FROM explore_search_urls $QUERY_ENABLED_EXPLORE AND $QUERY_NAME $ORDER_DEFAULT")
fun observeFilteredExploreUrls(name: String): DataSource.Factory<Int, ExploreSearchUrl>
// 用于搜索时的发现列表,按使用次数排序
@Query("SELECT * FROM explore_search_urls $QUERY_ENABLED_EXPLORE AND $QUERY_NAME $ORDER_USAGE")
fun observeFilteredExploreUrlsByUsage(): DataSource.Factory<Int, ExploreSearchUrl>
// 用于搜索时的发现列表,按使用时间排序
@Query("SELECT * FROM explore_search_urls $QUERY_ENABLED_EXPLORE AND $QUERY_NAME $ORDER_TIME")
fun observeFilteredExploreUrlsByTime(): DataSource.Factory<Int, ExploreSearchUrl>
// 获取特定书源的发现
@Query("SELECT * FROM explore_search_urls $QUERY_ENABLED_EXPLORE AND sourceId = :sourceId")
fun findExploreUrlsBySourceId(sourceId: Int): List<ExploreSearchUrl>
// 获取特定书源的搜索链接
@Query("SELECT * FROM explore_search_urls WHERE type = 1 AND sourceId = :sourceId")
fun findSearchUrlsBySourceId(sourceId: Int): List<ExploreSearchUrl>
// 所有的搜索链接
@get:Query("SELECT * FROM explore_search_urls WHERE type = 1")
val allSearchUrls: List<ExploreSearchUrl>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg keywords: ExploreSearchUrl)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(keyword: ExploreSearchUrl): Long
@Update
fun update(vararg keywords: ExploreSearchUrl)
@Delete
fun delete(vararg keywords: ExploreSearchUrl)
// 批量删除特定书源的发现和搜索链接,一般用于更新书源时
@Query("DELETE FROM explore_search_urls WHERE sourceId = :sourceId")
fun deleteBySourceId(sourceId: Int)
}

@ -44,6 +44,7 @@ interface ReplaceRuleDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(replaceRule: ReplaceRule): Long
@Update
fun update(vararg replaceRules: ReplaceRule)

@ -0,0 +1,32 @@
package io.legado.app.data.dao
import androidx.paging.DataSource
import androidx.room.*
import io.legado.app.data.entities.SearchKeyword
@Dao
interface SearchKeywordDao {
@Query("SELECT * FROM search_keywords ORDER BY usage DESC")
fun observeByUsage(): DataSource.Factory<Int, SearchKeyword>
@Query("SELECT * FROM search_keywords ORDER BY lastUseTime DESC")
fun observeByTime(): DataSource.Factory<Int, SearchKeyword>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg keywords: SearchKeyword)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(keyword: SearchKeyword): Long
@Update
fun update(vararg keywords: SearchKeyword)
@Delete
fun delete(vararg keywords: SearchKeyword)
@Query("DELETE FROM search_keywords")
fun deleteAll()
}

@ -0,0 +1,29 @@
package io.legado.app.data.entities
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(tableName = "explore_search_urls",
indices = [(Index(value = ["sourceId", "url"], unique = true))],
foreignKeys = [(ForeignKey(entity = Source::class,
parentColumns = ["sourceId"],
childColumns = ["sourceId"],
onDelete = ForeignKey.CASCADE))]) // 删除书源时自动删除章节
data class ExploreSearchUrl (
@PrimaryKey(autoGenerate = true)
var esId: Int = 0, // 编号
var sourceId: Int = 0, // 书源Id
var name: String = "", // 发现名称,搜索可以没有
var url: String = "", // 地址
var type: Int = 0, // 类型,0 为发现,1 为搜索
var isEnabled: Boolean = true, // 是否启用
var defOrder: Int = 0, // 默认排序,是在编辑书源的时候的顺序
var usage: Int = 0, // 使用次数,用于按使用次数排序
var lastUseTime: Long = 0L // 最后一次使用的时间
) : Parcelable

@ -0,0 +1,17 @@
package io.legado.app.data.entities
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(tableName = "search_keywords", indices = [(Index(value = ["word"], unique = true))])
data class SearchKeyword (
@PrimaryKey
var word: String = "", // 搜索关键词
var usage: Int = 1, // 使用次数
var lastUseTime: Long = 0 // 最后一次使用时间
): Parcelable

@ -13,6 +13,8 @@ import io.legado.app.data.entities.ReplaceRule
import kotlinx.android.synthetic.main.activity_replace_rule.*
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.toast
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.ItemTouchHelper
class ReplaceRuleActivity : AppCompatActivity() {
@ -26,6 +28,7 @@ class ReplaceRuleActivity : AppCompatActivity() {
rv_replace_rule.layoutManager = LinearLayoutManager(this)
initRecyclerView()
initDataObservers()
initSwipeToDelete()
}
private fun initRecyclerView() {
@ -69,4 +72,28 @@ class ReplaceRuleActivity : AppCompatActivity() {
}
}
}
private fun initSwipeToDelete() {
ItemTouchHelper(object : ItemTouchHelper.Callback() {
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
return ItemTouchHelper.Callback.makeMovementFlags(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
toast("You swiped the item!")
TODO()
// remove((viewHolder as TodoViewHolder).todo)
}
}).attachToRecyclerView(rv_replace_rule)
}
}

@ -50,13 +50,15 @@ class ReplaceRuleAdapter(context: Context) :
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(rule: ReplaceRule, listener: OnClickListener?, hideDivider: Boolean) = with(itemView) {
cb_enable.text = rule.name
cb_enable.isChecked = rule.isEnabled
divider.isGone = hideDivider
iv_delete.onClick { listener?.delete(rule) }
iv_edit.onClick { listener?.edit(rule) }
cb_enable.onClick {
rule.isEnabled = cb_enable.isChecked
tv_name.text = rule.name
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 {
rule.isEnabled = swt_enabled.isChecked
listener?.update(rule)
}
}

@ -2,8 +2,8 @@ package io.legado.app.utils
import com.jayway.jsonpath.ReadContext
fun ReadContext.readString(path: String) = this.read(path, String::class.java)
fun ReadContext.readString(path: String): String? = this.read(path, String::class.java)
fun ReadContext.readBool(path: String) = this.read(path, Boolean::class.java)
fun ReadContext.readBool(path: String): Boolean? = this.read(path, Boolean::class.java)
fun ReadContext.readInt(path: String) = this.read(path, Int::class.java)
fun ReadContext.readInt(path: String): Int? = this.read(path, Int::class.java)

@ -2,25 +2,12 @@
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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">
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/cb_enable"
android:text="Rule Name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:textSize="16sp"
android:textColor="@color/text_default"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/iv_delete"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_edit"
android:layout_width="wrap_content"
@ -29,6 +16,7 @@
android:background="@drawable/bg_ib_pre_round"
android:contentDescription="@string/edit"
android:src="@drawable/ic_edit"
android:visibility="gone"
app:tint="@color/text_default"
app:layout_constraintEnd_toStartOf="@id/iv_delete"
app:layout_constraintBottom_toBottomOf="parent"
@ -42,11 +30,54 @@
android:background="@drawable/bg_ib_pre_round"
android:contentDescription="@string/delete"
android:src="@drawable/ic_clear_all"
android:visibility="gone"
app:tint="@color/text_default"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/cb_selected"
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_name"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="16dp"
android:textSize="16sp"
android:text="Item Name"
android:textColor="@color/text_default"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/cb_selected"
app:layout_constraintEnd_toStartOf="@id/swt_enabled"/>
<Switch
android:id="@+id/swt_enabled"
android:name="@string/enable"
android:text=""
android:paddingStart="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_name"
app:layout_constraintHorizontal_bias="1"/>
<View
android:id="@+id/divider"
android:layout_width="match_parent"

@ -30,4 +30,5 @@
<string name="delete">删除</string>
<string name="replace">净化替换</string>
<string name="not_available">暂无</string>
<string name="enable">启用</string>
</resources>

Loading…
Cancel
Save