reformat code

pull/32/head
gedoor 6 years ago
parent 0b019531f9
commit 3039f993f3
  1. 2
      app/src/main/java/io/legado/app/App.kt
  2. 4
      app/src/main/java/io/legado/app/base/BaseFragment.kt
  3. 2
      app/src/main/java/io/legado/app/base/adapter/InfiniteScrollListener.kt
  4. 7
      app/src/main/java/io/legado/app/base/adapter/ItemAnimation.kt
  5. 2
      app/src/main/java/io/legado/app/base/adapter/ItemViewDelegate.kt
  6. 2
      app/src/main/java/io/legado/app/base/adapter/animations/AlphaInAnimation.kt
  7. 3
      app/src/main/java/io/legado/app/base/adapter/animations/SlideInBottomAnimation.kt
  8. 3
      app/src/main/java/io/legado/app/base/adapter/animations/SlideInLeftAnimation.kt
  9. 3
      app/src/main/java/io/legado/app/base/adapter/animations/SlideInRightAnimation.kt
  10. 10
      app/src/main/java/io/legado/app/constant/AppUtils.kt
  11. 10
      app/src/main/java/io/legado/app/data/AppDatabase.kt
  12. 4
      app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
  13. 65
      app/src/main/java/io/legado/app/data/entities/Book.kt
  14. 6
      app/src/main/java/io/legado/app/data/entities/BookSource.kt
  15. 27
      app/src/main/java/io/legado/app/data/entities/Chapter.kt
  16. 14
      app/src/main/java/io/legado/app/data/entities/ExploreSearchUrl.kt
  17. 26
      app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt
  18. 4
      app/src/main/java/io/legado/app/data/entities/SearchKeyword.kt
  19. 2
      app/src/main/java/io/legado/app/data/entities/rule/BookInfoRule.kt
  20. 2
      app/src/main/java/io/legado/app/data/entities/rule/ChapterRule.kt
  21. 2
      app/src/main/java/io/legado/app/data/entities/rule/ContentRule.kt
  22. 2
      app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt
  23. 2
      app/src/main/java/io/legado/app/data/entities/rule/PutRule.kt
  24. 4
      app/src/main/java/io/legado/app/data/entities/rule/Rule.kt
  25. 2
      app/src/main/java/io/legado/app/data/entities/rule/SearchRule.kt
  26. 1
      app/src/main/java/io/legado/app/help/permission/RequestSource.kt
  27. 1
      app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt
  28. 33
      app/src/main/java/io/legado/app/lib/webdav/WebDav.kt
  29. 3
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  30. 1
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  31. 1
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt
  32. 30
      app/src/main/java/io/legado/app/ui/main/booksource/BookSourceAdapter.kt
  33. 10
      app/src/main/java/io/legado/app/ui/main/booksource/BookSourceFragment.kt
  34. 1
      app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt
  35. 7
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt
  36. 10
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt
  37. 1
      app/src/main/java/io/legado/app/ui/search/SearchActivity.kt
  38. 6
      app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt
  39. 4
      app/src/main/java/io/legado/app/ui/sourceedit/SourceEditAdapter.kt
  40. 3
      app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt
  41. 7
      app/src/main/java/io/legado/app/ui/widget/RotateLoading.kt
  42. 12
      app/src/main/java/io/legado/app/ui/widget/dynamiclayout/ViewSwitcher.kt
  43. 2
      app/src/main/java/io/legado/app/utils/AnkoExtensions.kt
  44. 4
      app/src/main/java/io/legado/app/utils/MenuExtensions.kt
  45. 3
      app/src/main/java/io/legado/app/utils/StringExtensions.kt
  46. 3
      app/src/main/java/io/legado/app/utils/ViewModelKt.kt
  47. 288
      app/src/main/res/layout/item_bookshelf_list.xml
  48. 3
      app/src/main/res/layout/item_relace_rule.xml
  49. 12
      app/src/main/res/layout/item_source_edit.xml
  50. 24
      app/src/main/res/layout/view_dynamic.xml
  51. 34
      app/src/main/res/layout/view_error.xml

@ -79,7 +79,7 @@ class App : Application() {
} }
} }
fun applyDayNight(){ fun applyDayNight() {
upThemeStore() upThemeStore()
initNightTheme() initNightTheme()
} }

@ -6,11 +6,9 @@ import android.view.MenuItem
import androidx.appcompat.view.SupportMenuInflater import androidx.appcompat.view.SupportMenuInflater
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import io.legado.app.utils.setIconColor import io.legado.app.utils.setIconColor
abstract class BaseFragment(contentLayoutId: Int = 0) : Fragment(contentLayoutId){ abstract class BaseFragment(contentLayoutId: Int = 0) : Fragment(contentLayoutId) {
var supportToolbar: Toolbar? = null var supportToolbar: Toolbar? = null
private set private set

@ -14,7 +14,7 @@ abstract class InfiniteScrollListener() : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
// if (dy < 0 || dataLoading.isDataLoading()) return // if (dy < 0 || dataLoading.isDataLoading()) return
val layoutManager:LinearLayoutManager = recyclerView.layoutManager as LinearLayoutManager val layoutManager: LinearLayoutManager = recyclerView.layoutManager as LinearLayoutManager
val visibleItemCount = recyclerView.childCount val visibleItemCount = recyclerView.childCount
val totalItemCount = layoutManager.itemCount val totalItemCount = layoutManager.itemCount
val firstVisibleItem = layoutManager.findFirstVisibleItemPosition() val firstVisibleItem = layoutManager.findFirstVisibleItemPosition()

@ -2,12 +2,7 @@ package io.legado.app.base.adapter
import android.view.animation.Interpolator import android.view.animation.Interpolator
import android.view.animation.LinearInterpolator import android.view.animation.LinearInterpolator
import io.legado.app.base.adapter.animations.AlphaInAnimation import io.legado.app.base.adapter.animations.*
import io.legado.app.base.adapter.animations.BaseAnimation
import io.legado.app.base.adapter.animations.ScaleInAnimation
import io.legado.app.base.adapter.animations.SlideInBottomAnimation
import io.legado.app.base.adapter.animations.SlideInLeftAnimation
import io.legado.app.base.adapter.animations.SlideInRightAnimation
/** /**
* Created by Invincible on 2017/12/15. * Created by Invincible on 2017/12/15.

@ -7,7 +7,7 @@ import android.content.Context
* *
* item代理 * item代理
*/ */
abstract class ItemViewDelegate<in ITEM>(protected val context: Context, val layoutId: Int) { abstract class ItemViewDelegate<in ITEM>(protected val context: Context, val layoutId: Int) {
abstract fun convert(holder: ItemViewHolder, item: ITEM, payloads: MutableList<Any>) abstract fun convert(holder: ItemViewHolder, item: ITEM, payloads: MutableList<Any>)

@ -8,7 +8,7 @@ import android.view.View
class AlphaInAnimation @JvmOverloads constructor(private val mFrom: Float = DEFAULT_ALPHA_FROM) : BaseAnimation { class AlphaInAnimation @JvmOverloads constructor(private val mFrom: Float = DEFAULT_ALPHA_FROM) : BaseAnimation {
override fun getAnimators(view: View): Array<Animator> = override fun getAnimators(view: View): Array<Animator> =
arrayOf(ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f)) arrayOf(ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f))
companion object { companion object {

@ -3,11 +3,10 @@ package io.legado.app.base.adapter.animations
import android.animation.Animator import android.animation.Animator
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.view.View import android.view.View
import io.legado.app.base.adapter.animations.BaseAnimation
class SlideInBottomAnimation : BaseAnimation { class SlideInBottomAnimation : BaseAnimation {
override fun getAnimators(view: View): Array<Animator> = override fun getAnimators(view: View): Array<Animator> =
arrayOf(ObjectAnimator.ofFloat(view, "translationY", view.measuredHeight.toFloat(), 0f)) arrayOf(ObjectAnimator.ofFloat(view, "translationY", view.measuredHeight.toFloat(), 0f))
} }

@ -3,12 +3,11 @@ package io.legado.app.base.adapter.animations
import android.animation.Animator import android.animation.Animator
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.view.View import android.view.View
import io.legado.app.base.adapter.animations.BaseAnimation
class SlideInLeftAnimation : BaseAnimation { class SlideInLeftAnimation : BaseAnimation {
override fun getAnimators(view: View): Array<Animator> = override fun getAnimators(view: View): Array<Animator> =
arrayOf(ObjectAnimator.ofFloat(view, "translationX", -view.rootView.width.toFloat(), 0f)) arrayOf(ObjectAnimator.ofFloat(view, "translationX", -view.rootView.width.toFloat(), 0f))
} }

@ -3,12 +3,11 @@ package io.legado.app.base.adapter.animations
import android.animation.Animator import android.animation.Animator
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.view.View import android.view.View
import io.legado.app.base.adapter.animations.BaseAnimation
class SlideInRightAnimation : BaseAnimation { class SlideInRightAnimation : BaseAnimation {
override fun getAnimators(view: View): Array<Animator> = override fun getAnimators(view: View): Array<Animator> =
arrayOf(ObjectAnimator.ofFloat(view, "translationX", view.rootView.width.toFloat(), 0f)) arrayOf(ObjectAnimator.ofFloat(view, "translationX", view.rootView.width.toFloat(), 0f))
} }

@ -4,9 +4,9 @@ import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
object AppUtils { object AppUtils {
val GSON_CONVERTER: Gson = GsonBuilder() val GSON_CONVERTER: Gson = GsonBuilder()
.disableHtmlEscaping() .disableHtmlEscaping()
.setPrettyPrinting() .setPrettyPrinting()
.setDateFormat("yyyy-MM-dd HH:mm:ssZ") .setDateFormat("yyyy-MM-dd HH:mm:ssZ")
.create() .create()
} }

@ -7,15 +7,19 @@ import androidx.room.RoomDatabase
import androidx.room.migration.Migration import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import io.legado.app.data.dao.BookDao import io.legado.app.data.dao.BookDao
import io.legado.app.data.dao.ReplaceRuleDao
import io.legado.app.data.dao.BookSourceDao import io.legado.app.data.dao.BookSourceDao
import io.legado.app.data.dao.ReplaceRuleDao
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.Chapter import io.legado.app.data.entities.Chapter
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
@Database(entities = [Book::class, BookSource::class, Chapter::class, ReplaceRule::class], version = 1, exportSchema = true) @Database(
entities = [Book::class, BookSource::class, Chapter::class, ReplaceRule::class],
version = 1,
exportSchema = true
)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
@ -46,5 +50,5 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun bookDao(): BookDao abstract fun bookDao(): BookDao
abstract fun replaceRuleDao(): ReplaceRuleDao abstract fun replaceRuleDao(): ReplaceRuleDao
abstract fun bookSourceDao() : BookSourceDao abstract fun bookSourceDao(): BookSourceDao
} }

@ -11,10 +11,10 @@ interface BookSourceDao {
fun observeAll(): DataSource.Factory<Int, BookSource> fun observeAll(): DataSource.Factory<Int, BookSource>
@Query("select * from book_sources where name like :searchKey or `group` like :searchKey or origin like :searchKey order by customOrder asc") @Query("select * from book_sources where name like :searchKey or `group` like :searchKey or origin like :searchKey order by customOrder asc")
fun observeSearch(searchKey:String = ""): DataSource.Factory<Int, BookSource> fun observeSearch(searchKey: String = ""): DataSource.Factory<Int, BookSource>
@Query("select * from book_sources where origin = :key") @Query("select * from book_sources where origin = :key")
fun findByKey(key:String): BookSource? fun findByKey(key: String): BookSource?
@Query("select count(*) from book_sources") @Query("select count(*) from book_sources")
fun allCount(): Int fun allCount(): Int

@ -1,42 +1,45 @@
package io.legado.app.data.entities package io.legado.app.data.entities
import android.os.Parcelable import android.os.Parcelable
import androidx.room.* import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import io.legado.app.constant.AppConst.NOT_AVAILABLE import io.legado.app.constant.AppConst.NOT_AVAILABLE
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
@Entity(tableName = "books", indices = [(Index(value = ["descUrl"], unique = true))]) @Entity(tableName = "books", indices = [(Index(value = ["descUrl"], unique = true))])
data class Book(@PrimaryKey data class Book(
var descUrl: String = "", // 详情页Url(本地书源存储完整文件路径) @PrimaryKey
var tocUrl: String = "", // 目录页Url (toc=table of Contents) var descUrl: String = "", // 详情页Url(本地书源存储完整文件路径)
var sourceId: Int = -1, // 书源规则id(默认-1,表示本地书籍) var tocUrl: String = "", // 目录页Url (toc=table of Contents)
var name: String? = null, // 书籍名称(书源获取) var sourceId: Int = -1, // 书源规则id(默认-1,表示本地书籍)
var customName: String? = null, // 书籍名称(用户修改) var name: String? = null, // 书籍名称(书源获取)
var author: String? = null, // 作者名称(书源获取) var customName: String? = null, // 书籍名称(用户修改)
var customAuthor: String? = null, // 作者名称(用户修改) var author: String? = null, // 作者名称(书源获取)
var tag: String? = null, // 分类信息(书源获取) var customAuthor: String? = null, // 作者名称(用户修改)
var customTag: String? = null, // 分类信息(用户修改) var tag: String? = null, // 分类信息(书源获取)
var coverUrl: String? = null, // 封面Url(书源获取) var customTag: String? = null, // 分类信息(用户修改)
var customCoverUrl: String? = null, // 封面Url(用户修改) var coverUrl: String? = null, // 封面Url(书源获取)
var description: String? = null, // 简介内容(书源获取) var customCoverUrl: String? = null, // 封面Url(用户修改)
var customDescription: String? = null, // 简介内容(用户修改) var description: String? = null, // 简介内容(书源获取)
var charset: String? = null, // 自定义字符集名称(仅适用于本地书籍) var customDescription: String? = null, // 简介内容(用户修改)
var type: Int = 0, // 0: 文本读物, 1: 有声读物 var charset: String? = null, // 自定义字符集名称(仅适用于本地书籍)
var group: Int = 0, // 自定义分组索引号 var type: Int = 0, // 0: 文本读物, 1: 有声读物
var latestChapterTitle: String? = null, // 最新章节标题 var group: Int = 0, // 自定义分组索引号
var latestChapterTime: Long = 0, // 最新章节标题更新时间 var latestChapterTitle: String? = null, // 最新章节标题
var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间 var latestChapterTime: Long = 0, // 最新章节标题更新时间
var lastCheckCount: Int = 0, // 最近一次发现新章节的数量 var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间
var totalChapterNum: Int = 0, // 书籍目录总数 var lastCheckCount: Int = 0, // 最近一次发现新章节的数量
var durChapterTitle: String? = null, // 当前章节名称 var totalChapterNum: Int = 0, // 书籍目录总数
var durChapterIndex: Int = 0, // 当前章节索引 var durChapterTitle: String? = null, // 当前章节名称
var durChapterPos: Int = 0, // 当前阅读的进度(首行字符的索引位置) var durChapterIndex: Int = 0, // 当前章节索引
var durChapterTime: Long = 0, // 最近一次阅读书籍的时间(打开正文的时间) var durChapterPos: Int = 0, // 当前阅读的进度(首行字符的索引位置)
var canUpdate: Boolean = true, // 刷新书架时更新书籍信息 var durChapterTime: Long = 0, // 最近一次阅读书籍的时间(打开正文的时间)
var order: Int = 0, // 手动排序 var canUpdate: Boolean = true, // 刷新书架时更新书籍信息
var useReplaceRule: Boolean = true, // 正文使用净化替换规则 var order: Int = 0, // 手动排序
var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息) var useReplaceRule: Boolean = true, // 正文使用净化替换规则
var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息)
) : Parcelable { ) : Parcelable {
fun getUnreadChapterNum() = Math.max(totalChapterNum - durChapterIndex - 1, 0) fun getUnreadChapterNum() = Math.max(totalChapterNum - durChapterIndex - 1, 0)

@ -1,7 +1,9 @@
package io.legado.app.data.entities package io.legado.app.data.entities
import android.os.Parcelable import android.os.Parcelable
import androidx.room.* import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import io.legado.app.constant.AppUtils.GSON_CONVERTER import io.legado.app.constant.AppUtils.GSON_CONVERTER
import io.legado.app.data.entities.rule.* import io.legado.app.data.entities.rule.*
import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.IgnoredOnParcel
@ -12,7 +14,7 @@ import kotlinx.android.parcel.Parcelize
tableName = "book_sources", tableName = "book_sources",
indices = [(Index(value = ["origin"], unique = false))] indices = [(Index(value = ["origin"], unique = false))]
) )
data class BookSource ( data class BookSource(
@PrimaryKey @PrimaryKey
var origin: String = "", // 地址,包括 http/https var origin: String = "", // 地址,包括 http/https
var name: String = "", // 名称 var name: String = "", // 名称

@ -4,26 +4,29 @@ import android.os.Parcelable
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
@Entity(tableName = "chapters", @Entity(
tableName = "chapters",
primaryKeys = ["url", "bookUrl"], primaryKeys = ["url", "bookUrl"],
indices = [(Index(value = ["url"], unique = true)), (Index(value = ["bookUrl", "index"], unique = true))], indices = [(Index(value = ["url"], unique = true)), (Index(value = ["bookUrl", "index"], unique = true))],
foreignKeys = [(ForeignKey(entity = Book::class, foreignKeys = [(ForeignKey(
entity = Book::class,
parentColumns = ["descUrl"], parentColumns = ["descUrl"],
childColumns = ["bookUrl"], childColumns = ["bookUrl"],
onDelete = ForeignKey.CASCADE))]) // 删除书籍时自动删除章节 onDelete = ForeignKey.CASCADE
))]
) // 删除书籍时自动删除章节
data class Chapter( data class Chapter(
var url: String = "", // 章节地址 var url: String = "", // 章节地址
var title: String = "", // 章节标题 var title: String = "", // 章节标题
var bookUrl: String = "", // 书籍地址 var bookUrl: String = "", // 书籍地址
var index: Int = 0, // 章节序号 var index: Int = 0, // 章节序号
var resourceUrl: String? = null, // 音频真实URL var resourceUrl: String? = null, // 音频真实URL
var tag: String? = null, // var tag: String? = null, //
var start: Long? = null, // 章节起始位置 var start: Long? = null, // 章节起始位置
var end: Long? = null // 章节终止位置 var end: Long? = null // 章节终止位置
) : Parcelable ) : Parcelable

@ -8,13 +8,17 @@ import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
@Entity(tableName = "explore_search_urls", @Entity(
tableName = "explore_search_urls",
indices = [(Index(value = ["sourceId", "url"], unique = true))], indices = [(Index(value = ["sourceId", "url"], unique = true))],
foreignKeys = [(ForeignKey(entity = BookSource::class, foreignKeys = [(ForeignKey(
entity = BookSource::class,
parentColumns = ["sourceId"], parentColumns = ["sourceId"],
childColumns = ["sourceId"], childColumns = ["sourceId"],
onDelete = ForeignKey.CASCADE))]) // 删除书源时自动删除章节 onDelete = ForeignKey.CASCADE
data class ExploreSearchUrl ( ))]
) // 删除书源时自动删除章节
data class ExploreSearchUrl(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var esId: Int = 0, // 编号 var esId: Int = 0, // 编号
var sourceId: Int = 0, // 书源Id var sourceId: Int = 0, // 书源Id
@ -25,5 +29,5 @@ data class ExploreSearchUrl (
var defOrder: Int = 0, // 默认排序,是在编辑书源的时候的顺序 var defOrder: Int = 0, // 默认排序,是在编辑书源的时候的顺序
var usage: Int = 0, // 使用次数,用于按使用次数排序 var usage: Int = 0, // 使用次数,用于按使用次数排序
var lastUseTime: Long = 0L // 最后一次使用的时间 var lastUseTime: Long = 0L // 最后一次使用的时间
) : Parcelable ) : Parcelable

@ -8,19 +8,21 @@ import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
@Parcelize @Parcelize
@Entity(tableName = "replace_rules", @Entity(
indices = [(Index(value = ["id"]))]) tableName = "replace_rules",
indices = [(Index(value = ["id"]))]
)
data class ReplaceRule( data class ReplaceRule(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Int = 0, var id: Int = 0,
var name: String? = null, var name: String? = null,
var pattern: String? = null, var pattern: String? = null,
var replacement: String? = null, var replacement: String? = null,
var scope: String? = null, var scope: String? = null,
var isEnabled: Boolean = true, var isEnabled: Boolean = true,
var isRegex: Boolean = true, var isRegex: Boolean = true,
@ColumnInfo(name = "sortOrder") @ColumnInfo(name = "sortOrder")
var order: Int = 0 var order: Int = 0
) : Parcelable ) : Parcelable

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

@ -1,6 +1,6 @@
package io.legado.app.data.entities.rule package io.legado.app.data.entities.rule
data class BookInfoRule ( data class BookInfoRule(
var name: Rule, var name: Rule,
var author: Rule, var author: Rule,
var desc: Rule, var desc: Rule,

@ -1,6 +1,6 @@
package io.legado.app.data.entities.rule package io.legado.app.data.entities.rule
data class ChapterRule ( data class ChapterRule(
var chapterList: Rule, var chapterList: Rule,
var isReversed: Boolean = false, var isReversed: Boolean = false,
var title: Rule, var title: Rule,

@ -1,6 +1,6 @@
package io.legado.app.data.entities.rule package io.legado.app.data.entities.rule
data class ContentRule ( data class ContentRule(
var fulltext: Rule, var fulltext: Rule,
var resourceUrl: Rule, var resourceUrl: Rule,
var nextUrl: Rule var nextUrl: Rule

@ -1,6 +1,6 @@
package io.legado.app.data.entities.rule package io.legado.app.data.entities.rule
data class ExploreRule ( data class ExploreRule(
var bookList: Rule, var bookList: Rule,
var name: Rule, var name: Rule,
var author: Rule, var author: Rule,

@ -1,6 +1,6 @@
package io.legado.app.data.entities.rule package io.legado.app.data.entities.rule
data class PutRule ( data class PutRule(
var selector: Rule, var selector: Rule,
var key: String var key: String
) )

@ -1,9 +1,9 @@
package io.legado.app.data.entities.rule package io.legado.app.data.entities.rule
import io.legado.app.utils.splitNotBlank
import io.legado.app.utils.safeTrim import io.legado.app.utils.safeTrim
import io.legado.app.utils.splitNotBlank
data class Rule ( data class Rule(
var selectors: List<BaseRule>, var selectors: List<BaseRule>,
var regex: String?, var regex: String?,
var replacement: String?, var replacement: String?,

@ -1,6 +1,6 @@
package io.legado.app.data.entities.rule package io.legado.app.data.entities.rule
data class SearchRule ( data class SearchRule(
var bookList: Rule, var bookList: Rule,
var name: Rule, var name: Rule,
var author: Rule, var author: Rule,

@ -2,7 +2,6 @@ package io.legado.app.help.permission
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.fragment.app.FragmentManager
interface RequestSource { interface RequestSource {

@ -3,7 +3,6 @@ package io.legado.app.lib.theme.view
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import android.view.View
import android.widget.Switch
import androidx.appcompat.widget.SwitchCompat import androidx.appcompat.widget.SwitchCompat
import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.ThemeStore

@ -3,29 +3,16 @@ package io.legado.app.lib.webdav
import io.legado.app.lib.webdav.http.Handler import io.legado.app.lib.webdav.http.Handler
import io.legado.app.lib.webdav.http.HttpAuth import io.legado.app.lib.webdav.http.HttpAuth
import io.legado.app.lib.webdav.http.OkHttp import io.legado.app.lib.webdav.http.OkHttp
import okhttp3.*
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import java.io.File import java.io.File
import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.UnsupportedEncodingException import java.io.UnsupportedEncodingException
import java.lang.reflect.Field
import java.net.MalformedURLException import java.net.MalformedURLException
import java.net.URL import java.net.URL
import java.net.URLEncoder import java.net.URLEncoder
import java.util.ArrayList import java.util.*
import okhttp3.Credentials
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
class WebDav @Throws(MalformedURLException::class) class WebDav @Throws(MalformedURLException::class)
constructor(url: String) { constructor(url: String) {
@ -50,9 +37,9 @@ constructor(url: String) {
get() = url.toString() get() = url.toString()
private val inputStream: InputStream? private val inputStream: InputStream?
get() = getUrl()?.let {url -> get() = getUrl()?.let { url ->
val request = Request.Builder().url(url) val request = Request.Builder().url(url)
HttpAuth.auth?.let {request.header("Authorization", Credentials.basic(it.user, it.pass)) } HttpAuth.auth?.let { request.header("Authorization", Credentials.basic(it.user, it.pass)) }
try { try {
return okHttpClient.newCall(request.build()).execute().body()?.byteStream() return okHttpClient.newCall(request.build()).execute().body()?.byteStream()
@ -113,9 +100,9 @@ constructor(url: String) {
@Throws(IOException::class) @Throws(IOException::class)
@JvmOverloads @JvmOverloads
fun listFiles(propsList: ArrayList<String> = ArrayList()): List<WebDav> { fun listFiles(propsList: ArrayList<String> = ArrayList()): List<WebDav> {
propFindResponse(propsList)?.let {response-> propFindResponse(propsList)?.let { response ->
if (response.isSuccessful) { if (response.isSuccessful) {
response.body()?.let {body-> response.body()?.let { body ->
return parseDir(body.string()) return parseDir(body.string())
} }
} }
@ -136,14 +123,14 @@ constructor(url: String) {
} else { } else {
String.format(DIR, requestProps.toString() + "\n") String.format(DIR, requestProps.toString() + "\n")
} }
getUrl()?.let {url-> getUrl()?.let { url ->
val request = Request.Builder() val request = Request.Builder()
.url(url) .url(url)
// 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性 // 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性
// 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。 // 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。
.method("PROPFIND", RequestBody.create(MediaType.parse("text/plain"), requestPropsStr)) .method("PROPFIND", RequestBody.create(MediaType.parse("text/plain"), requestPropsStr))
HttpAuth.auth?.let {request.header("Authorization", Credentials.basic(it.user, it.pass)) } HttpAuth.auth?.let { request.header("Authorization", Credentials.basic(it.user, it.pass)) }
request.header("Depth", if (depth < 0) "infinity" else Integer.toString(depth)) request.header("Depth", if (depth < 0) "infinity" else Integer.toString(depth))
@ -156,7 +143,7 @@ constructor(url: String) {
val list = ArrayList<WebDav>() val list = ArrayList<WebDav>()
val document = Jsoup.parse(s) val document = Jsoup.parse(s)
val elements = document.getElementsByTag("d:response") val elements = document.getElementsByTag("d:response")
getUrl()?.let { url-> getUrl()?.let { url ->
val baseUrl = if (url.endsWith("/")) url else "$url/" val baseUrl = if (url.endsWith("/")) url else "$url/"
for (element in elements) { for (element in elements) {
val href = element.getElementsByTag("d:href")[0].text() val href = element.getElementsByTag("d:href")[0].text()
@ -184,7 +171,7 @@ constructor(url: String) {
*/ */
@Throws(IOException::class) @Throws(IOException::class)
fun makeAsDir(): Boolean { fun makeAsDir(): Boolean {
getUrl()?.let { url-> getUrl()?.let { url ->
val request = Request.Builder() val request = Request.Builder()
.url(url) .url(url)
.method("MKCOL", null) .method("MKCOL", null)

@ -3,7 +3,6 @@ package io.legado.app.ui.config
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.jeremyliao.liveeventbus.LiveEventBus import com.jeremyliao.liveeventbus.LiveEventBus
@ -87,7 +86,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
if (App.INSTANCE.getPrefBoolean("isNightTheme", false) == isNightTheme) { if (App.INSTANCE.getPrefBoolean("isNightTheme", false) == isNightTheme) {
App.INSTANCE.upThemeStore() App.INSTANCE.upThemeStore()
LiveEventBus.get().with(Bus.recreate).post("") LiveEventBus.get().with(Bus.recreate).post("")
Handler().postDelayed({activity?.recreate()}, 100) Handler().postDelayed({ activity?.recreate() }, 100)
} }
} }

@ -1,7 +1,6 @@
package io.legado.app.ui.main package io.legado.app.ui.main
import android.os.Bundle import android.os.Bundle
import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager

@ -6,5 +6,4 @@ import androidx.lifecycle.AndroidViewModel
class MainViewModel(application: Application) : AndroidViewModel(application) { class MainViewModel(application: Application) : AndroidViewModel(application) {
} }

@ -4,20 +4,16 @@ import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.CompoundButton
import android.widget.PopupMenu import android.widget.PopupMenu
import androidx.paging.PagedListAdapter import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R import io.legado.app.R
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.help.ItemTouchCallback
import io.legado.app.help.ItemTouchCallback.OnItemTouchCallbackListener import io.legado.app.help.ItemTouchCallback.OnItemTouchCallbackListener
import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.ThemeStore
import kotlinx.android.synthetic.main.item_book_source.view.* import kotlinx.android.synthetic.main.item_book_source.view.*
import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onClick
import java.util.*
import kotlin.collections.HashSet
class BookSourceAdapter : PagedListAdapter<BookSource, BookSourceAdapter.MyViewHolder>(DIFF_CALLBACK) { class BookSourceAdapter : PagedListAdapter<BookSource, BookSourceAdapter.MyViewHolder>(DIFF_CALLBACK) {
@ -48,8 +44,8 @@ class BookSourceAdapter : PagedListAdapter<BookSource, BookSourceAdapter.MyViewH
currentList?.let { currentList?.let {
val srcSource = it[srcPosition] val srcSource = it[srcPosition]
val targetSource = it[targetPosition] val targetSource = it[targetPosition]
srcSource?.let { a-> srcSource?.let { a ->
targetSource?.let { b-> targetSource?.let { b ->
a.customOrder = targetPosition a.customOrder = targetPosition
b.customOrder = srcPosition b.customOrder = srcPosition
callBack?.update(a, b) callBack?.update(a, b)
@ -86,25 +82,31 @@ class BookSourceAdapter : PagedListAdapter<BookSource, BookSourceAdapter.MyViewH
} }
} }
sw_enabled.isChecked = bookSource.isEnabled sw_enabled.isChecked = bookSource.isEnabled
sw_enabled.setOnClickListener{ sw_enabled.setOnClickListener {
bookSource.isEnabled = sw_enabled.isChecked bookSource.isEnabled = sw_enabled.isChecked
callBack?.update(bookSource) callBack?.update(bookSource)
} }
iv_more.setOnClickListener{ iv_more.setOnClickListener {
val popupMenu = PopupMenu(context, iv_more) val popupMenu = PopupMenu(context, iv_more)
popupMenu.menu.add(Menu.NONE, R.id.menu_edit, Menu.NONE, R.string.edit) popupMenu.menu.add(Menu.NONE, R.id.menu_edit, Menu.NONE, R.string.edit)
popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete)
popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top)
popupMenu.setOnMenuItemClickListener { popupMenu.setOnMenuItemClickListener {
when (it.itemId) { when (it.itemId) {
R.id.menu_edit ->{ R.id.menu_edit -> {
callBack?.edit(bookSource) callBack?.edit(bookSource)
true} true
R.id.menu_del ->{ }
R.id.menu_del -> {
callBack?.del(bookSource) callBack?.del(bookSource)
true} true
R.id.menu_top ->{ true} }
else -> {false} R.id.menu_top -> {
true
}
else -> {
false
}
} }
} }
popupMenu.show() popupMenu.show()

@ -24,7 +24,8 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivity
class BookSourceFragment : BaseFragment(R.layout.fragment_book_source), BookSourceAdapter.CallBack, SearchView.OnQueryTextListener { class BookSourceFragment : BaseFragment(R.layout.fragment_book_source), BookSourceAdapter.CallBack,
SearchView.OnQueryTextListener {
private lateinit var adapter: BookSourceAdapter private lateinit var adapter: BookSourceAdapter
private var bookSourceLiveDate: LiveData<PagedList<BookSource>>? = null private var bookSourceLiveDate: LiveData<PagedList<BookSource>>? = null
@ -68,9 +69,12 @@ class BookSourceFragment : BaseFragment(R.layout.fragment_book_source), BookSour
search_view.setOnQueryTextListener(this) search_view.setOnQueryTextListener(this)
} }
private fun initDataObservers(searchKey:String = "") { private fun initDataObservers(searchKey: String = "") {
bookSourceLiveDate?.removeObservers(viewLifecycleOwner) bookSourceLiveDate?.removeObservers(viewLifecycleOwner)
val dataFactory = if (searchKey.isEmpty()) App.db.bookSourceDao().observeAll() else App.db.bookSourceDao().observeSearch(searchKey) val dataFactory =
if (searchKey.isEmpty()) App.db.bookSourceDao().observeAll() else App.db.bookSourceDao().observeSearch(
searchKey
)
bookSourceLiveDate = LivePagedListBuilder(dataFactory, 30).build() bookSourceLiveDate = LivePagedListBuilder(dataFactory, 30).build()
bookSourceLiveDate?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) bookSourceLiveDate?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) })
} }

@ -2,7 +2,6 @@ package io.legado.app.ui.main.findbook
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem
import android.view.View import android.view.View
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseFragment import io.legado.app.base.BaseFragment

@ -40,19 +40,21 @@ class ReplaceRuleActivity : BaseActivity<ReplaceRuleViewModel>() {
private fun initRecyclerView() { private fun initRecyclerView() {
rv_replace_rule.layoutManager = LinearLayoutManager(this) rv_replace_rule.layoutManager = LinearLayoutManager(this)
adapter = ReplaceRuleAdapter(this) adapter = ReplaceRuleAdapter(this)
adapter.onClickListener = object: ReplaceRuleAdapter.OnClickListener { adapter.onClickListener = object : ReplaceRuleAdapter.OnClickListener {
override fun update(rule: ReplaceRule) { override fun update(rule: ReplaceRule) {
doAsync { doAsync {
App.db.replaceRuleDao().update(rule) App.db.replaceRuleDao().update(rule)
updateEnableAll() updateEnableAll()
} }
} }
override fun delete(rule: ReplaceRule) { override fun delete(rule: ReplaceRule) {
doAsync { doAsync {
App.db.replaceRuleDao().delete(rule) App.db.replaceRuleDao().delete(rule)
updateEnableAll() updateEnableAll()
} }
} }
override fun edit(rule: ReplaceRule) { override fun edit(rule: ReplaceRule) {
doAsync { doAsync {
App.db.replaceRuleDao().enableAll(!allEnabled) App.db.replaceRuleDao().enableAll(!allEnabled)
@ -67,7 +69,8 @@ class ReplaceRuleActivity : BaseActivity<ReplaceRuleViewModel>() {
DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply {
ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let { ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let {
Log.e(APP_TAG, it.toString()) Log.e(APP_TAG, it.toString())
this.setDrawable(it) } this.setDrawable(it)
}
}) })
} }

@ -1,7 +1,6 @@
package io.legado.app.ui.replacerule package io.legado.app.ui.replacerule
import android.content.Context import android.content.Context
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -10,7 +9,6 @@ import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppConst.APP_TAG
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
import kotlinx.android.synthetic.main.item_relace_rule.view.* import kotlinx.android.synthetic.main.item_relace_rule.view.*
import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onClick
@ -52,11 +50,11 @@ class ReplaceRuleAdapter(context: Context) :
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(rule: ReplaceRule, listener: OnClickListener?) = with(itemView) { fun bind(rule: ReplaceRule, listener: OnClickListener?) = with(itemView) {
tv_name.text = rule.name tv_name.text = rule.name
swt_enabled.isChecked = rule.isEnabled swt_enabled.isChecked = rule.isEnabled
// divider.isGone = hideDivider // divider.isGone = hideDivider
iv_delete.isGone = true iv_delete.isGone = true
iv_edit.isGone = true iv_edit.isGone = true
// iv_delete.onClick { listener?.delete(rule) } // iv_delete.onClick { listener?.delete(rule) }
// iv_edit.onClick { listener?.edit(rule) } // iv_edit.onClick { listener?.edit(rule) }
swt_enabled.onClick { swt_enabled.onClick {

@ -4,7 +4,6 @@ import android.os.Bundle
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseActivity import io.legado.app.base.BaseActivity
import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModel
import org.jetbrains.anko.startActivity
class SearchActivity : BaseActivity<SearchViewModel>() { class SearchActivity : BaseActivity<SearchViewModel>() {

@ -5,14 +5,14 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.App
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseActivity import io.legado.app.base.BaseActivity
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_source_edit.* import kotlinx.android.synthetic.main.activity_source_edit.*
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import org.jetbrains.anko.UI import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
class SourceEditActivity : BaseActivity<SourceEditViewModel>() { class SourceEditActivity : BaseActivity<SourceEditViewModel>() {

@ -11,7 +11,7 @@ import kotlinx.android.synthetic.main.item_source_edit.view.*
class SourceEditAdapter : RecyclerView.Adapter<SourceEditAdapter.MyViewHolder>() { class SourceEditAdapter : RecyclerView.Adapter<SourceEditAdapter.MyViewHolder>() {
var sourceEditEntities:ArrayList<SourceEditActivity.SourceEditEntity> = ArrayList() var sourceEditEntities: ArrayList<SourceEditActivity.SourceEditEntity> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_source_edit, parent, false)) return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_source_edit, parent, false))
@ -60,7 +60,7 @@ class SourceEditAdapter : RecyclerView.Adapter<SourceEditAdapter.MyViewHolder>()
} }
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
sourceEditEntity.value=(s?.toString()) sourceEditEntity.value = (s?.toString())
} }
} }
editText.addTextChangedListener(textWatcher) editText.addTextChangedListener(textWatcher)

@ -4,14 +4,13 @@ import android.app.Application
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import io.legado.app.App import io.legado.app.App
import io.legado.app.data.dao.BookSourceDao
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class SourceEditViewModel(application: Application) : AndroidViewModel(application) { class SourceEditViewModel(application: Application) : AndroidViewModel(application) {
val sourceLiveData:MutableLiveData<BookSource> = MutableLiveData() val sourceLiveData: MutableLiveData<BookSource> = MutableLiveData()
fun setBookSource(key: String) { fun setBookSource(key: String) {
GlobalScope.launch { GlobalScope.launch {

@ -89,7 +89,12 @@ class RotateLoading : View {
arc = 10f arc = 10f
loadingRectF = loadingRectF =
RectF((2 * thisWidth).toFloat(), (2 * thisWidth).toFloat(), (w - 2 * thisWidth).toFloat(), (h - 2 * thisWidth).toFloat()) RectF(
(2 * thisWidth).toFloat(),
(2 * thisWidth).toFloat(),
(w - 2 * thisWidth).toFloat(),
(h - 2 * thisWidth).toFloat()
)
shadowRectF = RectF( shadowRectF = RectF(
(2 * thisWidth + shadowPosition).toFloat(), (2 * thisWidth + shadowPosition).toFloat(),
(2 * thisWidth + shadowPosition).toFloat(), (2 * thisWidth + shadowPosition).toFloat(),

@ -5,12 +5,12 @@ import androidx.annotation.StringRes
interface ViewSwitcher { interface ViewSwitcher {
companion object{ companion object {
const val SHOW_CONTENT_VIEW = 0 const val SHOW_CONTENT_VIEW = 0
const val SHOW_ERROR_VIEW = 1 const val SHOW_ERROR_VIEW = 1
const val SHOW_EMPTY_VIEW = 2 const val SHOW_EMPTY_VIEW = 2
const val SHOW_PROGRESS_VIEW = 3 const val SHOW_PROGRESS_VIEW = 3
} }
@Retention(AnnotationRetention.SOURCE) @Retention(AnnotationRetention.SOURCE)
@IntDef(SHOW_CONTENT_VIEW, SHOW_ERROR_VIEW, SHOW_EMPTY_VIEW, SHOW_PROGRESS_VIEW) @IntDef(SHOW_CONTENT_VIEW, SHOW_ERROR_VIEW, SHOW_EMPTY_VIEW, SHOW_PROGRESS_VIEW)

@ -1,10 +1,8 @@
package io.legado.app.utils package io.legado.app.utils
import android.app.Activity
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.View import android.view.View
import android.view.WindowManager
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes

@ -6,7 +6,9 @@ import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.view.menu.MenuItemImpl import androidx.appcompat.view.menu.MenuItemImpl
import androidx.core.view.forEach import androidx.core.view.forEach
import io.legado.app.R import io.legado.app.R
import io.legado.app.lib.theme.* import io.legado.app.lib.theme.DrawableUtils
import io.legado.app.lib.theme.getPrimaryTextColor
import io.legado.app.lib.theme.isDarkTheme
fun Menu.setIconColor(context: Context): Menu = this.let { menu -> fun Menu.setIconColor(context: Context): Menu = this.let { menu ->
if (menu is MenuBuilder) { if (menu is MenuBuilder) {

@ -1,4 +1,5 @@
package io.legado.app.utils package io.legado.app.utils
// import org.apache.commons.text.StringEscapeUtils // import org.apache.commons.text.StringEscapeUtils
fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim() fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim()
@ -7,6 +8,6 @@ fun String.isAbsUrl() = this.startsWith("http://", true)
|| this.startsWith("https://", true) || this.startsWith("https://", true)
fun String.splitNotBlank(delim: String) = if (!this.contains(delim)) sequenceOf(this) else fun String.splitNotBlank(delim: String) = if (!this.contains(delim)) sequenceOf(this) else
this.split(delim).asSequence().map { it.trim() }.filterNot { it.isBlank() } this.split(delim).asSequence().map { it.trim() }.filterNot { it.isBlank() }
// fun String.unescapeJson() = StringEscapeUtils.unescapeJson(this) // fun String.unescapeJson() = StringEscapeUtils.unescapeJson(this)

@ -9,4 +9,5 @@ fun <T : ViewModel> AppCompatActivity.getViewModel(clazz: Class<T>) = ViewModelP
fun <T : ViewModel> Fragment.getViewModel(clazz: Class<T>) = ViewModelProviders.of(this).get(clazz) fun <T : ViewModel> Fragment.getViewModel(clazz: Class<T>) = ViewModelProviders.of(this).get(clazz)
fun <T : ViewModel> Fragment.getViewModelOfActivity(clazz: Class<T>) = ViewModelProviders.of(requireActivity()).get(clazz) fun <T : ViewModel> Fragment.getViewModelOfActivity(clazz: Class<T>) =
ViewModelProviders.of(requireActivity()).get(clazz)

@ -1,175 +1,175 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/cv_content" android:id="@+id/cv_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:foreground="?android:attr/selectableItemBackground" android:foreground="?android:attr/selectableItemBackground"
tools:ignore="UnusedAttribute"> tools:ignore="UnusedAttribute">
<io.legado.app.ui.widget.image.CoverImageView <io.legado.app.ui.widget.image.CoverImageView
android:id="@+id/iv_cover" android:id="@+id/iv_cover"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="80dp" android:layout_height="80dp"
android:layout_margin="8dp" android:layout_margin="8dp"
android:contentDescription="@string/img_cover" android:contentDescription="@string/img_cover"
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:src="@drawable/img_cover_default" android:src="@drawable/img_cover_default"
android:transitionName="img_cover" android:transitionName="img_cover"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="UnusedAttribute" /> tools:ignore="UnusedAttribute"/>
<FrameLayout <FrameLayout
android:id="@+id/fl_has_new" android:id="@+id/fl_has_new"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_name">
<io.legado.app.ui.widget.BadgeView
android:id="@+id/bv_unread"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="right" app:layout_constraintRight_toRightOf="parent"
android:layout_margin="5dp" app:layout_constraintTop_toTopOf="@id/tv_name">
android:includeFontPadding="false"
tools:ignore="RtlHardcoded" /> <io.legado.app.ui.widget.BadgeView
android:id="@+id/bv_unread"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_margin="5dp"
android:includeFontPadding="false"
tools:ignore="RtlHardcoded"/>
<com.victor.loading.rotate.RotateLoading <com.victor.loading.rotate.RotateLoading
android:id="@+id/rl_loading" android:id="@+id/rl_loading"
android:layout_width="26dp" android:layout_width="26dp"
android:layout_height="26dp" android:layout_height="26dp"
android:layout_gravity="right" android:layout_gravity="right"
android:visibility="invisible" android:visibility="invisible"
app:loading_color="@color/colorAccent" app:loading_color="@color/colorAccent"
app:loading_width="2dp" app:loading_width="2dp"
tools:ignore="RtlHardcoded" /> tools:ignore="RtlHardcoded"/>
</FrameLayout> </FrameLayout>
<TextView <TextView
android:id="@+id/tv_name" android:id="@+id/tv_name"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:includeFontPadding="false" android:includeFontPadding="false"
android:paddingLeft="4dp" android:paddingLeft="4dp"
android:singleLine="true" android:singleLine="true"
android:text="@string/book_name" android:text="@string/book_name"
android:textColor="@color/tv_text_default" android:textColor="@color/tv_text_default"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/tv_author" app:layout_constraintBottom_toTopOf="@+id/tv_author"
app:layout_constraintLeft_toRightOf="@+id/iv_cover" app:layout_constraintLeft_toRightOf="@+id/iv_cover"
app:layout_constraintRight_toLeftOf="@id/fl_has_new" app:layout_constraintRight_toLeftOf="@id/fl_has_new"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:ignore="RtlHardcoded,RtlSymmetry" /> tools:ignore="RtlHardcoded,RtlSymmetry"/>
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_author" android:id="@+id/iv_author"
android:layout_width="@dimen/desc_icon_size" android:layout_width="@dimen/desc_icon_size"
android:layout_height="@dimen/desc_icon_size" android:layout_height="@dimen/desc_icon_size"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:contentDescription="@string/author" android:contentDescription="@string/author"
android:paddingStart="2dp" android:paddingStart="2dp"
android:paddingEnd="2dp" android:paddingEnd="2dp"
android:src="@drawable/ic_author" android:src="@drawable/ic_author"
app:layout_constraintBottom_toBottomOf="@+id/tv_author" app:layout_constraintBottom_toBottomOf="@+id/tv_author"
app:layout_constraintLeft_toRightOf="@+id/iv_cover" app:layout_constraintLeft_toRightOf="@+id/iv_cover"
app:layout_constraintTop_toTopOf="@+id/tv_author" app:layout_constraintTop_toTopOf="@+id/tv_author"
app:tint="@color/tv_text_secondary" app:tint="@color/tv_text_secondary"
tools:ignore="RtlHardcoded,RtlSymmetry" /> tools:ignore="RtlHardcoded,RtlSymmetry"/>
<TextView <TextView
android:id="@+id/tv_author" android:id="@+id/tv_author"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:includeFontPadding="false" android:includeFontPadding="false"
android:maxLines="1" android:maxLines="1"
android:paddingEnd="6dp" android:paddingEnd="6dp"
android:text="@string/author" android:text="@string/author"
android:textColor="@color/tv_text_secondary" android:textColor="@color/tv_text_secondary"
android:textSize="13sp" android:textSize="13sp"
app:layout_constraintBottom_toTopOf="@+id/tv_read" app:layout_constraintBottom_toTopOf="@+id/tv_read"
app:layout_constraintLeft_toRightOf="@+id/iv_author" app:layout_constraintLeft_toRightOf="@+id/iv_author"
app:layout_constraintRight_toLeftOf="@id/fl_has_new" app:layout_constraintRight_toLeftOf="@id/fl_has_new"
app:layout_constraintTop_toBottomOf="@+id/tv_name" app:layout_constraintTop_toBottomOf="@+id/tv_name"
tools:ignore="RtlSymmetry" /> tools:ignore="RtlSymmetry"/>
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_read" android:id="@+id/iv_read"
android:layout_width="@dimen/desc_icon_size" android:layout_width="@dimen/desc_icon_size"
android:layout_height="@dimen/desc_icon_size" android:layout_height="@dimen/desc_icon_size"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:contentDescription="@string/read_dur_progress" android:contentDescription="@string/read_dur_progress"
android:paddingStart="2dp" android:paddingStart="2dp"
android:paddingEnd="2dp" android:paddingEnd="2dp"
android:src="@drawable/ic_history" android:src="@drawable/ic_history"
app:layout_constraintBottom_toBottomOf="@+id/tv_read" app:layout_constraintBottom_toBottomOf="@+id/tv_read"
app:layout_constraintLeft_toRightOf="@+id/iv_cover" app:layout_constraintLeft_toRightOf="@+id/iv_cover"
app:layout_constraintTop_toTopOf="@+id/tv_read" app:layout_constraintTop_toTopOf="@+id/tv_read"
app:tint="@color/tv_text_secondary" app:tint="@color/tv_text_secondary"
tools:ignore="RtlHardcoded,RtlSymmetry" /> tools:ignore="RtlHardcoded,RtlSymmetry"/>
<TextView <TextView
android:id="@+id/tv_read" android:id="@+id/tv_read"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:includeFontPadding="false" android:includeFontPadding="false"
android:singleLine="true" android:singleLine="true"
android:text="@string/read_dur_progress" android:text="@string/read_dur_progress"
android:textColor="@color/tv_text_secondary" android:textColor="@color/tv_text_secondary"
android:textSize="13sp" android:textSize="13sp"
app:layout_constraintBottom_toTopOf="@id/tv_last" app:layout_constraintBottom_toTopOf="@id/tv_last"
app:layout_constraintLeft_toRightOf="@+id/iv_read" app:layout_constraintLeft_toRightOf="@+id/iv_read"
app:layout_constraintRight_toLeftOf="@id/fl_has_new" app:layout_constraintRight_toLeftOf="@id/fl_has_new"
app:layout_constraintTop_toBottomOf="@+id/tv_author" /> app:layout_constraintTop_toBottomOf="@+id/tv_author"/>
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_last" android:id="@+id/iv_last"
android:layout_width="@dimen/desc_icon_size" android:layout_width="@dimen/desc_icon_size"
android:layout_height="@dimen/desc_icon_size" android:layout_height="@dimen/desc_icon_size"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:contentDescription="@string/book_search_last" android:contentDescription="@string/book_search_last"
android:paddingStart="2dp" android:paddingStart="2dp"
android:paddingEnd="2dp" android:paddingEnd="2dp"
android:src="@drawable/ic_book_last" android:src="@drawable/ic_book_last"
app:layout_constraintBottom_toBottomOf="@+id/tv_last" app:layout_constraintBottom_toBottomOf="@+id/tv_last"
app:layout_constraintLeft_toRightOf="@+id/iv_cover" app:layout_constraintLeft_toRightOf="@+id/iv_cover"
app:layout_constraintTop_toTopOf="@+id/tv_last" app:layout_constraintTop_toTopOf="@+id/tv_last"
app:tint="@color/tv_text_secondary" app:tint="@color/tv_text_secondary"
tools:ignore="RtlHardcoded,RtlSymmetry" /> tools:ignore="RtlHardcoded,RtlSymmetry"/>
<TextView <TextView
android:id="@+id/tv_last" android:id="@+id/tv_last"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:singleLine="true" android:singleLine="true"
android:text="@string/book_search_last" android:text="@string/book_search_last"
android:textColor="@color/tv_text_secondary" android:textColor="@color/tv_text_secondary"
android:textSize="13sp" android:textSize="13sp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/iv_last" app:layout_constraintLeft_toRightOf="@+id/iv_last"
app:layout_constraintRight_toLeftOf="@id/fl_has_new" app:layout_constraintRight_toLeftOf="@id/fl_has_new"
app:layout_constraintTop_toBottomOf="@+id/tv_read" /> app:layout_constraintTop_toBottomOf="@+id/tv_read"/>
<View <View
android:id="@+id/vw_select" android:id="@+id/vw_select"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent"/>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0.5dp" android:layout_height="0.5dp"
android:background="@color/btn_bg_press" android:background="@color/btn_bg_press"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -2,7 +2,6 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@ -46,7 +45,7 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_name" app:layout_constraintEnd_toStartOf="@+id/tv_name"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent"/>
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_name" android:id="@+id/tv_name"

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<io.legado.app.lib.theme.view.ATETextInputLayout xmlns:android="http://schemas.android.com/apk/res/android" <io.legado.app.lib.theme.view.ATETextInputLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/textInputLayout" android:id="@+id/textInputLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<io.legado.app.lib.theme.view.ATEEditText <io.legado.app.lib.theme.view.ATEEditText
android:id="@+id/editText" android:id="@+id/editText"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"/>
</io.legado.app.lib.theme.view.ATETextInputLayout> </io.legado.app.lib.theme.view.ATETextInputLayout>

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" <merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ViewStub <ViewStub
android:id="@+id/errorViewStub" android:id="@+id/errorViewStub"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout="@layout/view_error" /> android:layout="@layout/view_error"/>
<ViewStub <ViewStub
android:id="@+id/progressViewStub" android:id="@+id/progressViewStub"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout="@layout/view_loading" /> android:layout="@layout/view_loading"/>
</merge> </merge>

@ -1,27 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:orientation="vertical"> android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_error_image" android:id="@+id/iv_error_image"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_error_message" android:id="@+id/tv_error_message"
style="@style/Style.Text.Primary.Normal" style="@style/Style.Text.Primary.Normal"
android:paddingTop="16dp" android:paddingTop="16dp"
android:paddingBottom="16dp" /> android:paddingBottom="16dp"/>
<androidx.appcompat.widget.AppCompatButton <androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_error_retry" android:id="@+id/btn_error_retry"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:backgroundTint="@color/colorAccent" android:backgroundTint="@color/colorAccent"
android:minWidth="96dp" android:minWidth="96dp"
android:text="@string/dynamic_click_retry" /> android:text="@string/dynamic_click_retry"/>
</LinearLayout> </LinearLayout>
Loading…
Cancel
Save