Merge remote-tracking branch 'origin/master'

# Conflicts:
#	app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt
#	app/src/main/java/io/legado/app/utils/MenuExtensions.kt
#	app/src/main/res/layout/activity_source_edit.xml
#	app/src/main/res/layout/view_titlebar.xml
pull/32/head
Invinciblelee 6 years ago
commit 3f3593c616
  1. 4
      app/build.gradle
  2. 77
      app/src/main/java/io/legado/app/App.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. 21
      app/src/main/java/io/legado/app/data/AppDatabase.kt
  12. 4
      app/src/main/java/io/legado/app/data/dao/BookDao.kt
  13. 15
      app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt
  14. 39
      app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
  15. 10
      app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt
  16. 65
      app/src/main/java/io/legado/app/data/entities/Book.kt
  17. 15
      app/src/main/java/io/legado/app/data/entities/BookGroup.kt
  18. 17
      app/src/main/java/io/legado/app/data/entities/BookSource.kt
  19. 30
      app/src/main/java/io/legado/app/data/entities/Chapter.kt
  20. 14
      app/src/main/java/io/legado/app/data/entities/ExploreSearchUrl.kt
  21. 26
      app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt
  22. 4
      app/src/main/java/io/legado/app/data/entities/SearchKeyword.kt
  23. 2
      app/src/main/java/io/legado/app/data/entities/rule/BookInfoRule.kt
  24. 2
      app/src/main/java/io/legado/app/data/entities/rule/ChapterRule.kt
  25. 2
      app/src/main/java/io/legado/app/data/entities/rule/ContentRule.kt
  26. 2
      app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt
  27. 2
      app/src/main/java/io/legado/app/data/entities/rule/PutRule.kt
  28. 4
      app/src/main/java/io/legado/app/data/entities/rule/Rule.kt
  29. 2
      app/src/main/java/io/legado/app/data/entities/rule/SearchRule.kt
  30. 127
      app/src/main/java/io/legado/app/help/ItemTouchCallback.kt
  31. 1
      app/src/main/java/io/legado/app/help/permission/RequestSource.kt
  32. 35
      app/src/main/java/io/legado/app/lib/theme/view/ATEStockSwitch.kt
  33. 1
      app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt
  34. 33
      app/src/main/java/io/legado/app/lib/webdav/WebDav.kt
  35. 2
      app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt
  36. 46
      app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt
  37. 125
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  38. 32
      app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt
  39. 3
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  40. 1
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt
  41. 38
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt
  42. 80
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt
  43. 40
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt
  44. 121
      app/src/main/java/io/legado/app/ui/main/booksource/BookSourceAdapter.kt
  45. 84
      app/src/main/java/io/legado/app/ui/main/booksource/BookSourceFragment.kt
  46. 3
      app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt
  47. 2
      app/src/main/java/io/legado/app/ui/main/myconfig/MyConfigFragment.kt
  48. 7
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt
  49. 10
      app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt
  50. 1
      app/src/main/java/io/legado/app/ui/search/SearchActivity.kt
  51. 2
      app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt
  52. 92
      app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt
  53. 72
      app/src/main/java/io/legado/app/ui/sourceedit/SourceEditAdapter.kt
  54. 23
      app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt
  55. 233
      app/src/main/java/io/legado/app/ui/widget/BadgeView.kt
  56. 212
      app/src/main/java/io/legado/app/ui/widget/RotateLoading.kt
  57. 2
      app/src/main/java/io/legado/app/ui/widget/TitleBar.kt
  58. 12
      app/src/main/java/io/legado/app/ui/widget/dynamiclayout/ViewSwitcher.kt
  59. 56
      app/src/main/java/io/legado/app/ui/widget/image/CoverImageView.kt
  60. 92
      app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt
  61. 2
      app/src/main/java/io/legado/app/utils/AnkoExtensions.kt
  62. 3
      app/src/main/java/io/legado/app/utils/StringExtensions.kt
  63. 3
      app/src/main/java/io/legado/app/utils/ViewModelKt.kt
  64. 6
      app/src/main/res/drawable-v21/bg_ib_pre.xml
  65. 2
      app/src/main/res/drawable-v21/bg_ib_pre_round.xml
  66. 46
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  67. 10
      app/src/main/res/drawable/bg_chapter_item_divider.xml
  68. 7
      app/src/main/res/drawable/bg_edit.xml
  69. 4
      app/src/main/res/drawable/bg_ib_pre.xml
  70. 2
      app/src/main/res/drawable/bg_ib_pre_round.xml
  71. 13
      app/src/main/res/drawable/bg_textfield_search.xml
  72. 28
      app/src/main/res/drawable/fastscroll_bubble.xml
  73. 18
      app/src/main/res/drawable/fastscroll_handle.xml
  74. 14
      app/src/main/res/drawable/fastscroll_track.xml
  75. 12
      app/src/main/res/drawable/ic_about.xml
  76. 12
      app/src/main/res/drawable/ic_add.xml
  77. 12
      app/src/main/res/drawable/ic_add_online.xml
  78. 20
      app/src/main/res/drawable/ic_arrange.xml
  79. 12
      app/src/main/res/drawable/ic_arrow_back.xml
  80. 12
      app/src/main/res/drawable/ic_arrow_drop_down.xml
  81. 12
      app/src/main/res/drawable/ic_arrow_drop_up.xml
  82. 16
      app/src/main/res/drawable/ic_author.xml
  83. 16
      app/src/main/res/drawable/ic_auto_page.xml
  84. 20
      app/src/main/res/drawable/ic_auto_page_stop.xml
  85. 12
      app/src/main/res/drawable/ic_back_last.xml
  86. 36
      app/src/main/res/drawable/ic_backup.xml
  87. 16
      app/src/main/res/drawable/ic_book_has.xml
  88. 20
      app/src/main/res/drawable/ic_book_last.xml
  89. 24
      app/src/main/res/drawable/ic_book_source_manage.xml
  90. 12
      app/src/main/res/drawable/ic_bookmark.xml
  91. 12
      app/src/main/res/drawable/ic_brightness.xml
  92. 16
      app/src/main/res/drawable/ic_cancel.xml
  93. 24
      app/src/main/res/drawable/ic_chapter_list.xml
  94. 12
      app/src/main/res/drawable/ic_check.xml
  95. 16
      app/src/main/res/drawable/ic_check_source.xml
  96. 20
      app/src/main/res/drawable/ic_copy.xml
  97. 44
      app/src/main/res/drawable/ic_daytime.xml
  98. 20
      app/src/main/res/drawable/ic_disclaimer.xml
  99. 12
      app/src/main/res/drawable/ic_donate.xml
  100. 12
      app/src/main/res/drawable/ic_download.xml
  101. Some files were not shown because too many files have changed in this diff Show More

@ -80,7 +80,7 @@ dependencies {
//androidX
implementation 'androidx.core:core-ktx:1.2.0-alpha01'
implementation 'androidx.appcompat:appcompat:1.1.0-alpha05'
implementation 'androidx.appcompat:appcompat:1.1.0-beta01'
implementation 'androidx.preference:preference:1.1.0-alpha05'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
implementation 'com.google.android.material:material:1.1.0-alpha07'
@ -121,7 +121,7 @@ dependencies {
//Retrofit
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
//Glide
implementation 'com.github.bumptech.glide:glide:4.9.0'

@ -22,6 +22,7 @@ import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.getPrefInt
import java.util.*
@Suppress("DEPRECATION")
class App : Application() {
companion object {
@ -86,7 +87,7 @@ class App : Application() {
}
}
fun applyDayNight(){
fun applyDayNight() {
upThemeStore()
initNightTheme()
}
@ -96,41 +97,43 @@ class App : Application() {
*/
@RequiresApi(Build.VERSION_CODES.O)
private fun createChannelId() {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//用唯一的ID创建渠道对象
val downloadChannel = NotificationChannel(
channelIdDownload,
getString(R.string.download_offline),
NotificationManager.IMPORTANCE_LOW
)
//初始化channel
downloadChannel.enableLights(false)
downloadChannel.enableVibration(false)
downloadChannel.setSound(null, null)
//用唯一的ID创建渠道对象
val readAloudChannel = NotificationChannel(
channelIdReadAloud,
getString(R.string.read_aloud),
NotificationManager.IMPORTANCE_LOW
)
//初始化channel
readAloudChannel.enableLights(false)
readAloudChannel.enableVibration(false)
readAloudChannel.setSound(null, null)
//用唯一的ID创建渠道对象
val webChannel = NotificationChannel(
channelIdWeb,
getString(R.string.web_service),
NotificationManager.IMPORTANCE_LOW
)
//初始化channel
webChannel.enableLights(false)
webChannel.enableVibration(false)
webChannel.setSound(null, null)
//向notification manager 提交channel
notificationManager.createNotificationChannels(Arrays.asList(downloadChannel, readAloudChannel, webChannel))
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
notificationManager?.let {
//用唯一的ID创建渠道对象
val downloadChannel = NotificationChannel(
channelIdDownload,
getString(R.string.download_offline),
NotificationManager.IMPORTANCE_LOW
)
//初始化channel
downloadChannel.enableLights(false)
downloadChannel.enableVibration(false)
downloadChannel.setSound(null, null)
//用唯一的ID创建渠道对象
val readAloudChannel = NotificationChannel(
channelIdReadAloud,
getString(R.string.read_aloud),
NotificationManager.IMPORTANCE_LOW
)
//初始化channel
readAloudChannel.enableLights(false)
readAloudChannel.enableVibration(false)
readAloudChannel.setSound(null, null)
//用唯一的ID创建渠道对象
val webChannel = NotificationChannel(
channelIdWeb,
getString(R.string.web_service),
NotificationManager.IMPORTANCE_LOW
)
//初始化channel
webChannel.enableLights(false)
webChannel.enableVibration(false)
webChannel.setSound(null, null)
//向notification manager 提交channel
it.createNotificationChannels(Arrays.asList(downloadChannel, readAloudChannel, webChannel))
}
}
}

@ -14,7 +14,7 @@ abstract class InfiniteScrollListener() : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
// 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 totalItemCount = layoutManager.itemCount
val firstVisibleItem = layoutManager.findFirstVisibleItemPosition()

@ -2,12 +2,7 @@ package io.legado.app.base.adapter
import android.view.animation.Interpolator
import android.view.animation.LinearInterpolator
import io.legado.app.base.adapter.animations.AlphaInAnimation
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
import io.legado.app.base.adapter.animations.*
/**
* Created by Invincible on 2017/12/15.

@ -7,7 +7,7 @@ import android.content.Context
*
* 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>)

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

@ -3,11 +3,10 @@ package io.legado.app.base.adapter.animations
import android.animation.Animator
import android.animation.ObjectAnimator
import android.view.View
import io.legado.app.base.adapter.animations.BaseAnimation
class SlideInBottomAnimation : BaseAnimation {
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.ObjectAnimator
import android.view.View
import io.legado.app.base.adapter.animations.BaseAnimation
class SlideInLeftAnimation : BaseAnimation {
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.ObjectAnimator
import android.view.View
import io.legado.app.base.adapter.animations.BaseAnimation
class SlideInRightAnimation : BaseAnimation {
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
object AppUtils {
val GSON_CONVERTER: Gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.setDateFormat("yyyy-MM-dd HH:mm:ssZ")
.create()
val GSON_CONVERTER: Gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.setDateFormat("yyyy-MM-dd HH:mm:ssZ")
.create()
}

@ -7,15 +7,17 @@ import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import io.legado.app.data.dao.BookDao
import io.legado.app.data.dao.BookGroupDao
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.Chapter
import io.legado.app.data.entities.ReplaceRule
import javax.xml.transform.Source
import io.legado.app.data.entities.*
@Database(entities = [Book::class, Chapter::class, ReplaceRule::class], version = 1, exportSchema = true)
// @TypeConverters(Converters::class)
@Database(
entities = [Book::class, BookGroup::class, BookSource::class, Chapter::class, ReplaceRule::class],
version = 1,
exportSchema = true
)
abstract class AppDatabase : RoomDatabase() {
companion object {
@ -39,17 +41,14 @@ abstract class AppDatabase : RoomDatabase() {
// .addMigrations(MIGRATION_3_4)
// .addMigrations(MIGRATION_4_5)
// .addMigrations(MIGRATION_5_6)
.addCallback(object : Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
}
})
.build()
}
}
abstract fun bookDao(): BookDao
abstract fun bookGroupDao(): BookGroupDao
abstract fun bookSourceDao(): BookSourceDao
abstract fun replaceRuleDao(): ReplaceRuleDao
}

@ -8,7 +8,6 @@ import androidx.room.OnConflictStrategy
import androidx.room.Query
import io.legado.app.data.entities.Book
@Dao
interface BookDao {
@ -27,6 +26,9 @@ interface BookDao {
@get:Query("SELECT COUNT(*) FROM books")
val allBookCount: Int
@Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,10")
fun recentRead(): DataSource.Factory<Int, Book>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg books: Book)

@ -0,0 +1,15 @@
package io.legado.app.data.dao
import androidx.paging.DataSource
import androidx.room.Dao
import androidx.room.Query
import io.legado.app.data.entities.BookGroup
@Dao
interface BookGroupDao {
@Query("SELECT * FROM book_groups ORDER BY `order`")
fun observeAll(): DataSource.Factory<Int, BookGroup>
}

@ -0,0 +1,39 @@
package io.legado.app.data.dao
import androidx.paging.DataSource
import androidx.room.*
import io.legado.app.data.entities.BookSource
@Dao
interface BookSourceDao {
@Query("select * from book_sources order by customOrder asc")
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")
fun observeSearch(searchKey: String = ""): DataSource.Factory<Int, BookSource>
@Query("select * from book_sources where origin = :key")
fun findByKey(key: String): BookSource?
@Query("select count(*) from book_sources")
fun allCount(): Int
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(bookSource: BookSource): Long
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg bookSource: BookSource)
@Update
fun update(bookSource: BookSource)
@Update
fun update(vararg bookSource: BookSource)
@Delete
fun delete(bookSource: BookSource)
@Delete
fun delete(vararg bookSource: BookSource)
}

@ -40,16 +40,20 @@ interface ReplaceRuleDao {
fun enableAll(enable: Boolean)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg replaceRules: ReplaceRule)
fun insert(vararg replaceRules: ReplaceRule): List<Long>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(replaceRule: ReplaceRule): Long
@Update
fun update(replaceRules: ReplaceRule)
@Update
fun update(vararg replaceRules: ReplaceRule)
@Delete
fun delete(vararg replaceRules: ReplaceRule)
fun delete(replaceRules: ReplaceRule)
@Delete
fun delete(vararg replaceRules: ReplaceRule)
}

@ -1,42 +1,45 @@
package io.legado.app.data.entities
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 kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(tableName = "books", indices = [(Index(value = ["descUrl"], unique = true))])
data class Book(@PrimaryKey
var descUrl: String = "", // 详情页Url(本地书源存储完整文件路径)
var tocUrl: String = "", // 目录页Url (toc=table of Contents)
var sourceId: Int = -1, // 书源规则id(默认-1,表示本地书籍)
var name: String? = null, // 书籍名称(书源获取)
var customName: String? = null, // 书籍名称(用户修改)
var author: String? = null, // 作者名称(书源获取)
var customAuthor: String? = null, // 作者名称(用户修改)
var tag: String? = null, // 分类信息(书源获取)
var customTag: String? = null, // 分类信息(用户修改)
var coverUrl: String? = null, // 封面Url(书源获取)
var customCoverUrl: String? = null, // 封面Url(用户修改)
var description: String? = null, // 简介内容(书源获取)
var customDescription: String? = null, // 简介内容(用户修改)
var charset: String? = null, // 自定义字符集名称(仅适用于本地书籍)
var type: Int = 0, // 0: 文本读物, 1: 有声读物
var group: Int = 0, // 自定义分组索引号
var latestChapterTitle: String? = null, // 最新章节标题
var latestChapterTime: Long = 0, // 最新章节标题更新时间
var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间
var lastCheckCount: Int = 0, // 最近一次发现新章节的数量
var totalChapterNum: Int = 0, // 书籍目录总数
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 // 自定义书籍变量信息(用于书源规则检索书籍信息)
data class Book(
@PrimaryKey
var descUrl: String = "", // 详情页Url(本地书源存储完整文件路径)
var tocUrl: String = "", // 目录页Url (toc=table of Contents)
var sourceId: Int = -1, // 书源规则id(默认-1,表示本地书籍)
var name: String? = null, // 书籍名称(书源获取)
var customName: String? = null, // 书籍名称(用户修改)
var author: String? = null, // 作者名称(书源获取)
var customAuthor: String? = null, // 作者名称(用户修改)
var tag: String? = null, // 分类信息(书源获取)
var customTag: String? = null, // 分类信息(用户修改)
var coverUrl: String? = null, // 封面Url(书源获取)
var customCoverUrl: String? = null, // 封面Url(用户修改)
var description: String? = null, // 简介内容(书源获取)
var customDescription: String? = null, // 简介内容(用户修改)
var charset: String? = null, // 自定义字符集名称(仅适用于本地书籍)
var type: Int = 0, // 0: 文本读物, 1: 有声读物
var group: Int = 0, // 自定义分组索引号
var latestChapterTitle: String? = null, // 最新章节标题
var latestChapterTime: Long = 0, // 最新章节标题更新时间
var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间
var lastCheckCount: Int = 0, // 最近一次发现新章节的数量
var totalChapterNum: Int = 0, // 书籍目录总数
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 {
fun getUnreadChapterNum() = Math.max(totalChapterNum - durChapterIndex - 1, 0)

@ -0,0 +1,15 @@
package io.legado.app.data.entities
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(tableName = "book_groups")
data class BookGroup(
@PrimaryKey
var groupId: Int = 0,
var groupName: String,
var order: Int = 0
) : Parcelable

@ -1,7 +1,9 @@
package io.legado.app.data.entities
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.data.entities.rule.*
import kotlinx.android.parcel.IgnoredOnParcel
@ -9,15 +11,13 @@ import kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(
tableName = "sources",
indices = [(Index(value = ["sourceId"])), (Index(value = ["origin"], unique = false))]
tableName = "book_sources",
indices = [(Index(value = ["origin"], unique = false))]
)
data class Source (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "sourceId")
var id: Int = 0, // 编号
var name: String = "", // 名称
data class BookSource(
@PrimaryKey
var origin: String = "", // 地址,包括 http/https
var name: String = "", // 名称
var type: Int = 0, // 类型,0 文本,1 音频
var group: String? = null, // 分组
var header: String? = null, // header
@ -26,6 +26,7 @@ data class Source (
var lastUpdateTime: Long = 0, // 最后更新时间,用于排序
var customOrder: Int = 0, // 手动排序编号
var weight: Int = 0, // 智能排序的权重
var exploreIsEnabled: Boolean = true, //启用发现
var exploreRule: String? = null, // 发现规则
var searchRule: String? = null, // 搜索规则
var bookInfoRule: String? = null, // 书籍信息页规则

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

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

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

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

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

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

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

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

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

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

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

@ -0,0 +1,127 @@
package io.legado.app.help
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.viewpager.widget.ViewPager
/**
* Created by GKF on 2018/3/16.
*/
class ItemTouchCallback : ItemTouchHelper.Callback() {
private var swipeRefreshLayout: SwipeRefreshLayout? = null
private var viewPager: ViewPager? = null
/**
* Item操作的回调
*/
var onItemTouchCallbackListener: OnItemTouchCallbackListener? = null
/**
* 是否可以拖拽
*/
var isCanDrag = false
/**
* 是否可以被滑动
*/
var isCanSwipe = false
/**
* 当Item被长按的时候是否可以被拖拽
*/
override fun isLongPressDragEnabled(): Boolean {
return isCanDrag
}
/**
* Item是否可以被滑动(H左右滑动V上下滑动)
*/
override fun isItemViewSwipeEnabled(): Boolean {
return isCanSwipe
}
/**
* 当用户拖拽或者滑动Item的时候需要我们告诉系统滑动或者拖拽的方向
*/
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
val layoutManager = recyclerView.layoutManager
if (layoutManager is GridLayoutManager) {// GridLayoutManager
// flag如果值是0,相当于这个功能被关闭
val dragFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN
val swipeFlag = 0
// create make
return makeMovementFlags(dragFlag, swipeFlag)
} else if (layoutManager is LinearLayoutManager) {// linearLayoutManager
val linearLayoutManager = layoutManager as LinearLayoutManager?
val orientation = linearLayoutManager!!.orientation
var dragFlag = 0
var swipeFlag = 0
// 为了方便理解,相当于分为横着的ListView和竖着的ListView
if (orientation == LinearLayoutManager.HORIZONTAL) {// 如果是横向的布局
swipeFlag = ItemTouchHelper.UP or ItemTouchHelper.DOWN
dragFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
} else if (orientation == LinearLayoutManager.VERTICAL) {// 如果是竖向的布局,相当于ListView
dragFlag = ItemTouchHelper.UP or ItemTouchHelper.DOWN
swipeFlag = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
}
return makeMovementFlags(dragFlag, swipeFlag)
}
return 0
}
/**
* 当Item被拖拽的时候被回调
*
* @param recyclerView recyclerView
* @param srcViewHolder 拖拽的ViewHolder
* @param targetViewHolder 目的地的viewHolder
*/
override fun onMove(
recyclerView: RecyclerView,
srcViewHolder: RecyclerView.ViewHolder,
targetViewHolder: RecyclerView.ViewHolder
): Boolean {
onItemTouchCallbackListener?.let {
return it.onMove(srcViewHolder.adapterPosition, targetViewHolder.adapterPosition)
}
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
onItemTouchCallbackListener?.let {
return it.onSwiped(viewHolder.adapterPosition)
}
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
super.onSelectedChanged(viewHolder, actionState)
val swiping = actionState == ItemTouchHelper.ACTION_STATE_DRAG
swipeRefreshLayout?.isEnabled = !swiping
viewPager?.requestDisallowInterceptTouchEvent(swiping)
}
interface OnItemTouchCallbackListener {
/**
* 当某个Item被滑动删除的时候
*
* @param adapterPosition item的position
*/
fun onSwiped(adapterPosition: Int)
/**
* 当两个Item位置互换的时候被回调
*
* @param srcPosition 拖拽的item的position
* @param targetPosition 目的地的Item的position
* @return 开发者处理了操作应该返回true开发者没有处理就返回false
*/
fun onMove(srcPosition: Int, targetPosition: Int): Boolean
}
}

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

@ -1,35 +0,0 @@
package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.Switch
import androidx.appcompat.widget.SwitchCompat
import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.ThemeStore
/**
* @author Aidan Follestad (afollestad)
*/
class ATEStockSwitch : SwitchCompat {
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
ATH.setTint(this, ThemeStore.accentColor(context))
}
override fun isShown(): Boolean {
return parent != null && visibility == View.VISIBLE
}
}

@ -3,7 +3,6 @@ package io.legado.app.lib.theme.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.Switch
import androidx.appcompat.widget.SwitchCompat
import io.legado.app.lib.theme.ATH
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.HttpAuth
import io.legado.app.lib.webdav.http.OkHttp
import okhttp3.*
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.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.UnsupportedEncodingException
import java.lang.reflect.Field
import java.net.MalformedURLException
import java.net.URL
import java.net.URLEncoder
import java.util.ArrayList
import okhttp3.Credentials
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import java.util.*
class WebDav @Throws(MalformedURLException::class)
constructor(url: String) {
@ -50,9 +37,9 @@ constructor(url: String) {
get() = url.toString()
private val inputStream: InputStream?
get() = getUrl()?.let {url ->
get() = getUrl()?.let { 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 {
return okHttpClient.newCall(request.build()).execute().body()?.byteStream()
@ -113,9 +100,9 @@ constructor(url: String) {
@Throws(IOException::class)
@JvmOverloads
fun listFiles(propsList: ArrayList<String> = ArrayList()): List<WebDav> {
propFindResponse(propsList)?.let {response->
propFindResponse(propsList)?.let { response ->
if (response.isSuccessful) {
response.body()?.let {body->
response.body()?.let { body ->
return parseDir(body.string())
}
}
@ -136,14 +123,14 @@ constructor(url: String) {
} else {
String.format(DIR, requestProps.toString() + "\n")
}
getUrl()?.let {url->
getUrl()?.let { url ->
val request = Request.Builder()
.url(url)
// 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性
// 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。
.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))
@ -156,7 +143,7 @@ constructor(url: String) {
val list = ArrayList<WebDav>()
val document = Jsoup.parse(s)
val elements = document.getElementsByTag("d:response")
getUrl()?.let { url->
getUrl()?.let { url ->
val baseUrl = if (url.endsWith("/")) url else "$url/"
for (element in elements) {
val href = element.getElementsByTag("d:href")[0].text()
@ -184,7 +171,7 @@ constructor(url: String) {
*/
@Throws(IOException::class)
fun makeAsDir(): Boolean {
getUrl()?.let { url->
getUrl()?.let { url ->
val request = Request.Builder()
.url(url)
.method("MKCOL", null)

@ -5,7 +5,7 @@ import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_config.*
import kotlinx.android.synthetic.main.view_titlebar.*
import kotlinx.android.synthetic.main.view_title_bar.*
class ConfigActivity : BaseActivity<ConfigViewModel>() {
override val viewModel: ConfigViewModel

@ -1,15 +1,59 @@
package io.legado.app.ui.config
import android.content.SharedPreferences
import android.os.Bundle
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import io.legado.app.R
import io.legado.app.utils.getPrefString
class ConfigFragment : PreferenceFragmentCompat() {
class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener,
SharedPreferences.OnSharedPreferenceChangeListener {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_config)
}
override fun onResume() {
super.onResume()
preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}
override fun onPause() {
preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
super.onPause()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
}
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
val stringValue = newValue.toString()
if (preference is ListPreference) {
val index = preference.findIndexOfValue(stringValue)
// Set the summary to reflect the new value.
preference.setSummary(if (index >= 0) preference.entries[index] else null)
} else {
// For all other preferences, set the summary to the value's
preference?.summary = stringValue
}
return true
}
private fun bindPreferenceSummaryToValue(preference: Preference?) {
preference?.let {
preference.onPreferenceChangeListener = this
onPreferenceChange(
preference,
preference.context.getPrefString(preference.key, "")
)
}
}
}

@ -3,8 +3,8 @@ package io.legado.app.ui.config
import android.content.SharedPreferences
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.jeremyliao.liveeventbus.LiveEventBus
import io.legado.app.App
@ -36,58 +36,105 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
sharedPreferences ?: return
when (key) {
"colorPrimary", "colorAccent", "colorBackground" ->
if (!ColorUtils.isColorLight(
sharedPreferences.getInt(
"colorBackground",
App.INSTANCE.getCompatColor(R.color.md_grey_100)
)
)
) {
AlertDialog.Builder(App.INSTANCE)
.setTitle("白天背景太暗")
.setMessage("将会恢复默认背景?")
.setPositiveButton(R.string.ok) { _, _ ->
App.INSTANCE.putPrefInt("colorBackground", App.INSTANCE.getCompatColor(R.color.md_grey_100))
upTheme(false)
}
.setNegativeButton(R.string.cancel) { _, _ -> upTheme(false) }
.show().upTint
"transparentStatusBar" -> {
LiveEventBus.get().with(Bus.recreate).post("")
Handler().postDelayed({ activity?.recreate() }, 100)
}
"colorPrimary", "colorAccent", "colorBackground" -> {
if (backgroundIsDark(sharedPreferences)) {
activity?.let {
AlertDialog.Builder(it)
.setTitle("白天背景太暗")
.setMessage("将会恢复默认背景?")
.setPositiveButton(R.string.ok) { _, _ ->
App.INSTANCE.putPrefInt(
"colorBackground",
App.INSTANCE.getCompatColor(R.color.md_grey_100)
)
upTheme(false)
}
.setNegativeButton(R.string.cancel) { _, _ -> upTheme(false) }
.show().upTint
}
} else {
upTheme(false)
}
"colorPrimaryNight", "colorAccentNight", "colorBackgroundNight" ->
if (ColorUtils.isColorLight(
sharedPreferences.getInt(
"colorBackgroundNight",
App.INSTANCE.getCompatColor(R.color.md_grey_800)
)
)
) {
AlertDialog.Builder(App.INSTANCE)
.setTitle("夜间背景太亮")
.setMessage("将会恢复默认背景?")
.setPositiveButton(R.string.ok) { _, _ ->
App.INSTANCE.putPrefInt(
"colorBackgroundNight",
App.INSTANCE.getCompatColor(R.color.md_grey_800)
)
upTheme(true)
}
.setNegativeButton(R.string.cancel) { _, _ -> upTheme(true) }
.show()
}
"colorPrimaryNight", "colorAccentNight", "colorBackgroundNight" -> {
if (backgroundIsLight(sharedPreferences)) {
activity?.let {
AlertDialog.Builder(it)
.setTitle("夜间背景太亮")
.setMessage("将会恢复默认背景?")
.setPositiveButton(R.string.ok) { _, _ ->
App.INSTANCE.putPrefInt(
"colorBackgroundNight",
App.INSTANCE.getCompatColor(R.color.md_grey_800)
)
upTheme(true)
}
.setNegativeButton(R.string.cancel) { _, _ -> upTheme(true) }
.show().upTint
}
} else {
upTheme(true)
}
}
}
}
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
when (preference?.key) {
"defaultTheme" -> {
activity?.let {
AlertDialog.Builder(it)
.setTitle("恢复默认主题")
.setMessage("是否确认恢复?")
.setPositiveButton(R.string.ok) { _, _ ->
preferenceManager.sharedPreferences.edit()
.putInt("colorPrimary", App.INSTANCE.getCompatColor(R.color.md_grey_100))
.putInt("colorAccent", App.INSTANCE.getCompatColor(R.color.md_pink_600))
.putInt("colorBackground", App.INSTANCE.getCompatColor(R.color.md_grey_100))
.putInt("colorPrimaryNight", App.INSTANCE.getCompatColor(R.color.md_grey_800))
.putInt("colorAccentNight", App.INSTANCE.getCompatColor(R.color.md_pink_800))
.putInt("colorBackgroundNight", App.INSTANCE.getCompatColor(R.color.md_grey_800))
.apply()
App.INSTANCE.upThemeStore()
LiveEventBus.get().with(Bus.recreate).post("")
Handler().postDelayed({ activity?.recreate() }, 100)
}
.setNegativeButton(R.string.cancel, null)
.show().upTint
}
}
}
return super.onPreferenceTreeClick(preference)
}
private fun backgroundIsDark(sharedPreferences: SharedPreferences): Boolean {
return !ColorUtils.isColorLight(
sharedPreferences.getInt(
"colorBackground",
App.INSTANCE.getCompatColor(R.color.md_grey_100)
)
)
}
private fun backgroundIsLight(sharedPreferences: SharedPreferences): Boolean {
return ColorUtils.isColorLight(
sharedPreferences.getInt(
"colorBackgroundNight",
App.INSTANCE.getCompatColor(R.color.md_grey_800)
)
)
}
private fun upTheme(isNightTheme: Boolean) {
if (App.INSTANCE.getPrefBoolean("isNightTheme", false) == isNightTheme) {
App.INSTANCE.upThemeStore()
LiveEventBus.get().with(Bus.recreate).post("")
Handler().postDelayed({activity?.recreate()}, 100)
Handler().postDelayed({ activity?.recreate() }, 100)
}
}

@ -1,13 +1,43 @@
package io.legado.app.ui.config
import android.os.Bundle
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import io.legado.app.R
import io.legado.app.utils.getPrefString
class WebDavConfigFragment : PreferenceFragmentCompat() {
class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_config_web_dav)
bindPreferenceSummaryToValue(findPreference("web_dav_url"))
bindPreferenceSummaryToValue(findPreference("web_dav_account"))
}
override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
val stringValue = newValue.toString()
if (preference is ListPreference) {
val index = preference.findIndexOfValue(stringValue)
// Set the summary to reflect the new value.
preference.setSummary(if (index >= 0) preference.entries[index] else null)
} else {
// For all other preferences, set the summary to the value's
preference?.summary = stringValue
}
return true
}
private fun bindPreferenceSummaryToValue(preference: Preference?) {
preference?.let {
preference.onPreferenceChangeListener = this
onPreferenceChange(
preference,
preference.context.getPrefString(preference.key, "")
)
}
}
}

@ -1,7 +1,6 @@
package io.legado.app.ui.main
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
@ -16,6 +15,7 @@ import io.legado.app.constant.Bus
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.help.storage.Restore
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.ui.main.bookshelf.BookshelfFragment
import io.legado.app.ui.main.booksource.BookSourceFragment
import io.legado.app.ui.main.findbook.FindBookFragment
@ -33,6 +33,7 @@ class MainActivity : BaseActivity<MainViewModel>(), BottomNavigationView.OnNavig
get() = R.layout.activity_main
override fun onViewModelCreated(viewModel: MainViewModel, savedInstanceState: Bundle?) {
bottom_navigation_view.setBackgroundColor(ThemeStore.backgroundColor(this))
view_pager_main.offscreenPageLimit = 3
view_pager_main.adapter = TabFragmentPageAdapter(supportFragmentManager)
view_pager_main.addOnPageChangeListener(this)

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

@ -0,0 +1,38 @@
package io.legado.app.ui.main.bookshelf
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import io.legado.app.data.entities.BookGroup
class BookGroupAdapter : PagedListAdapter<BookGroup, BookGroupAdapter.MyViewHolder>(DIFF_CALLBACK) {
companion object {
@JvmField
val DIFF_CALLBACK = object : DiffUtil.ItemCallback<BookGroup>() {
override fun areItemsTheSame(oldItem: BookGroup, newItem: BookGroup): Boolean =
oldItem.groupId == newItem.groupId
override fun areContentsTheSame(oldItem: BookGroup, newItem: BookGroup): Boolean =
oldItem.groupId == newItem.groupId
&& oldItem.groupName == newItem.groupName
&& oldItem.order == newItem.order
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_book_group, parent, false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
}
}

@ -0,0 +1,80 @@
package io.legado.app.ui.main.bookshelf
import android.text.TextUtils.isEmpty
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import io.legado.app.R
import io.legado.app.data.entities.Book
import io.legado.app.lib.theme.ThemeStore
import kotlinx.android.synthetic.main.item_bookshelf_list.view.*
import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name
import java.io.File
class BookshelfAdapter : PagedListAdapter<Book, BookshelfAdapter.MyViewHolder>(DIFF_CALLBACK) {
companion object {
@JvmField
val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Book>() {
override fun areItemsTheSame(oldItem: Book, newItem: Book): Boolean =
oldItem.descUrl == newItem.descUrl
override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean =
oldItem.descUrl == newItem.descUrl
&& oldItem.durChapterTitle == newItem.durChapterTitle
&& oldItem.latestChapterTitle == newItem.latestChapterTitle
}
}
var callBack: CallBack? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_bookshelf_list, parent, false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
currentList?.get(position)?.let {
holder.bind(it, callBack)
}
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init {
itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context))
}
fun bind(book: Book, callBack: CallBack?) = with(itemView) {
tv_name.text = book.name
tv_author.text = book.author
tv_read.text = book.durChapterTitle
tv_last.text = book.latestChapterTitle
val cover = if (isEmpty(book.customCoverUrl)) book.coverUrl else book.customCoverUrl
cover?.let {
if (it.startsWith("http")) {
Glide.with(itemView).load(it)
.placeholder(R.drawable.img_cover_default)
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(iv_cover)
} else {
Glide.with(itemView).load(File(it))
.placeholder(R.drawable.img_cover_default)
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(iv_cover)
}
}
itemView.setOnClickListener { callBack?.open(book) }
}
}
interface CallBack {
fun open(book: Book)
}
}

@ -3,20 +3,56 @@ package io.legado.app.ui.main.bookshelf
import android.os.Bundle
import android.view.Menu
import android.view.View
import androidx.core.view.forEach
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.App
import io.legado.app.R
import io.legado.app.base.BaseFragment
import kotlinx.android.synthetic.main.view_titlebar.*
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookGroup
import kotlinx.android.synthetic.main.fragment_bookshelf.*
import kotlinx.android.synthetic.main.view_title_bar.*
class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf) {
private lateinit var bookshelfAdapter: BookshelfAdapter
private lateinit var bookGroupAdapter: BookGroupAdapter
private var bookGroupLiveData: LiveData<PagedList<BookGroup>>? = null
private var bookshelfLiveData: LiveData<PagedList<Book>>? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setSupportToolbar(toolbar)
initRecyclerView()
initBookGroupData()
initBookshelfData()
}
override fun onCompatCreateOptionsMenu(menu: Menu) {
menuInflater.inflate(R.menu.bookshelf, menu)
}
private fun initRecyclerView() {
rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
bookGroupAdapter = BookGroupAdapter()
rv_book_group.adapter = bookGroupAdapter
rv_bookshelf.layoutManager = LinearLayoutManager(context)
bookshelfAdapter = BookshelfAdapter()
rv_bookshelf.adapter = bookshelfAdapter
}
private fun initBookGroupData() {
bookGroupLiveData?.removeObservers(viewLifecycleOwner)
bookGroupLiveData = LivePagedListBuilder(App.db.bookGroupDao().observeAll(), 10).build()
bookGroupLiveData?.observe(viewLifecycleOwner, Observer { bookGroupAdapter.submitList(it) })
}
private fun initBookshelfData() {
bookshelfLiveData?.removeObservers(viewLifecycleOwner)
bookshelfLiveData = LivePagedListBuilder(App.db.bookDao().recentRead(), 20).build()
bookshelfLiveData?.observe(viewLifecycleOwner, Observer { bookshelfAdapter.submitList(it) })
}
}

@ -1,2 +1,123 @@
package io.legado.app.ui.main.booksource
import android.view.LayoutInflater
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import io.legado.app.data.entities.BookSource
import io.legado.app.help.ItemTouchCallback.OnItemTouchCallbackListener
import io.legado.app.lib.theme.ThemeStore
import kotlinx.android.synthetic.main.item_book_source.view.*
import org.jetbrains.anko.sdk27.listeners.onClick
class BookSourceAdapter : PagedListAdapter<BookSource, BookSourceAdapter.MyViewHolder>(DIFF_CALLBACK) {
companion object {
@JvmField
val DIFF_CALLBACK = object : DiffUtil.ItemCallback<BookSource>() {
override fun areItemsTheSame(oldItem: BookSource, newItem: BookSource): Boolean =
oldItem.origin == newItem.origin
override fun areContentsTheSame(oldItem: BookSource, newItem: BookSource): Boolean =
oldItem.origin == newItem.origin
&& oldItem.name == newItem.name
&& oldItem.group == newItem.group
&& oldItem.isEnabled == newItem.isEnabled
}
}
var callBack: CallBack? = null
val checkedList = HashSet<String>()
val itemTouchCallbackListener = object : OnItemTouchCallbackListener {
override fun onSwiped(adapterPosition: Int) {
}
override fun onMove(srcPosition: Int, targetPosition: Int): Boolean {
currentList?.let {
val srcSource = it[srcPosition]
val targetSource = it[targetPosition]
srcSource?.let { a ->
targetSource?.let { b ->
a.customOrder = targetPosition
b.customOrder = srcPosition
callBack?.update(a, b)
}
}
}
return true
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_book_source, parent, false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
getItem(position)?.let { holder.bind(it, checkedList, callBack) }
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init {
itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context))
}
fun bind(bookSource: BookSource, checkedList: HashSet<String>, callBack: CallBack?) = with(itemView) {
cb_book_source.text = String.format("%s (%s)", bookSource.name, bookSource.group)
cb_book_source.onClick {
if (cb_book_source.isChecked) {
checkedList.add(bookSource.origin)
} else {
checkedList.remove(bookSource.origin)
}
}
sw_enabled.isChecked = bookSource.isEnabled
sw_enabled.setOnClickListener {
bookSource.isEnabled = sw_enabled.isChecked
callBack?.update(bookSource)
}
iv_more.setOnClickListener {
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_del, Menu.NONE, R.string.delete)
popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top)
popupMenu.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_edit -> {
callBack?.edit(bookSource)
true
}
R.id.menu_del -> {
callBack?.del(bookSource)
true
}
R.id.menu_top -> {
true
}
else -> {
false
}
}
}
popupMenu.show()
}
}
}
interface CallBack {
fun del(bookSource: BookSource)
fun edit(bookSource: BookSource)
fun update(bookSource: BookSource)
fun update(vararg bookSource: BookSource)
}
}

@ -4,14 +4,37 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.appcompat.widget.SearchView
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.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.App
import io.legado.app.R
import io.legado.app.base.BaseFragment
import kotlinx.android.synthetic.main.view_titlebar.*
import io.legado.app.data.entities.BookSource
import io.legado.app.help.ItemTouchCallback
import io.legado.app.ui.sourceedit.SourceEditActivity
import kotlinx.android.synthetic.main.fragment_book_source.*
import kotlinx.android.synthetic.main.view_title_bar.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jetbrains.anko.startActivity
class BookSourceFragment : BaseFragment(R.layout.fragment_book_source) {
class BookSourceFragment : BaseFragment(R.layout.fragment_book_source), BookSourceAdapter.CallBack,
SearchView.OnQueryTextListener {
private lateinit var adapter: BookSourceAdapter
private var bookSourceLiveDate: LiveData<PagedList<BookSource>>? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setSupportToolbar(toolbar)
initRecyclerView()
initDataObserve()
initSearchView()
}
override fun onCompatCreateOptionsMenu(menu: Menu) {
@ -19,8 +42,65 @@ class BookSourceFragment : BaseFragment(R.layout.fragment_book_source) {
}
override fun onCompatOptionsItemSelected(item: MenuItem) {
when (item.itemId) {
R.id.action_add_book_source -> {
context?.startActivity<SourceEditActivity>()
}
}
}
private fun initRecyclerView() {
recycler_view.layoutManager = LinearLayoutManager(context)
recycler_view.addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
adapter = BookSourceAdapter()
adapter.callBack = this
recycler_view.adapter = adapter
val itemTouchCallback = ItemTouchCallback()
itemTouchCallback.onItemTouchCallbackListener = adapter.itemTouchCallbackListener
itemTouchCallback.isCanDrag = true
ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view)
}
private fun initSearchView() {
search_view.visibility = View.VISIBLE
search_view.onActionViewExpanded()
search_view.queryHint = getString(R.string.search_book_source)
search_view.clearFocus()
search_view.setOnQueryTextListener(this)
}
private fun initDataObserve(searchKey: String = "") {
bookSourceLiveDate?.removeObservers(viewLifecycleOwner)
val dataFactory =
if (searchKey.isEmpty()) App.db.bookSourceDao().observeAll() else App.db.bookSourceDao().observeSearch(
searchKey
)
bookSourceLiveDate = LivePagedListBuilder(dataFactory, 30).build()
bookSourceLiveDate?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) })
}
override fun onQueryTextChange(newText: String?): Boolean {
newText?.let { initDataObserve("%$it%") }
return false
}
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun del(bookSource: BookSource) {
GlobalScope.launch { App.db.bookSourceDao().delete(bookSource) }
}
override fun update(bookSource: BookSource) {
GlobalScope.launch { App.db.bookSourceDao().update(bookSource) }
}
override fun update(vararg bookSource: BookSource) {
GlobalScope.launch { App.db.bookSourceDao().update(*bookSource) }
}
override fun edit(bookSource: BookSource) {
context?.let { it.startActivity<SourceEditActivity>(Pair("data", bookSource.origin)) }
}
}

@ -2,11 +2,10 @@ package io.legado.app.ui.main.findbook
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import io.legado.app.R
import io.legado.app.base.BaseFragment
import kotlinx.android.synthetic.main.view_titlebar.*
import kotlinx.android.synthetic.main.view_title_bar.*
class FindBookFragment : BaseFragment(R.layout.fragment_find_book) {

@ -7,7 +7,7 @@ import android.view.View
import io.legado.app.R
import io.legado.app.base.BaseFragment
import io.legado.app.ui.search.SearchActivity
import kotlinx.android.synthetic.main.view_titlebar.*
import kotlinx.android.synthetic.main.view_title_bar.*
import org.jetbrains.anko.startActivity
class MyConfigFragment : BaseFragment(R.layout.fragment_my_config) {

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

@ -1,7 +1,6 @@
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
@ -10,7 +9,6 @@ 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
@ -52,11 +50,11 @@ class ReplaceRuleAdapter(context: Context) :
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(rule: ReplaceRule, listener: OnClickListener?) = with(itemView) {
tv_name.text = rule.name
swt_enabled.isChecked = rule.isEnabled
tv_name.text = rule.name
swt_enabled.isChecked = rule.isEnabled
// divider.isGone = hideDivider
iv_delete.isGone = true
iv_edit.isGone = true
iv_delete.isGone = true
iv_edit.isGone = true
// iv_delete.onClick { listener?.delete(rule) }
// iv_edit.onClick { listener?.edit(rule) }
swt_enabled.onClick {

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

@ -1,9 +1,19 @@
package io.legado.app.ui.sourceedit
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.data.entities.BookSource
import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_source_edit.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jetbrains.anko.toast
class SourceEditActivity : BaseActivity<SourceEditViewModel>() {
override val viewModel: SourceEditViewModel
@ -11,9 +21,91 @@ class SourceEditActivity : BaseActivity<SourceEditViewModel>() {
override val layoutID: Int
get() = R.layout.activity_source_edit
private val adapter = SourceEditAdapter()
private val sourceEditEntities: ArrayList<SourceEditEntity> = ArrayList()
override fun onViewModelCreated(viewModel: SourceEditViewModel, savedInstanceState: Bundle?) {
initRecyclerView()
viewModel.sourceLiveData.observe(this, Observer {
upRecyclerView(it)
})
if (viewModel.sourceLiveData.value == null) {
val sourceID = intent.getStringExtra("data")
if (sourceID == null) {
upRecyclerView(null)
} else {
sourceID.let { viewModel.setBookSource(sourceID) }
}
} else {
upRecyclerView(viewModel.sourceLiveData.value)
}
}
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.source_edit, menu)
return super.onCompatCreateOptionsMenu(menu)
}
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_save -> {
val bookSource = getSource()
if (bookSource == null) {
toast("书源名称和URL不能为空")
} else {
GlobalScope.launch {
viewModel.save(bookSource)
GlobalScope.launch(Dispatchers.Main) { finish() }
}
}
}
}
return super.onCompatOptionsItemSelected(item)
}
private fun initRecyclerView() {
recycler_view.layoutManager = LinearLayoutManager(this)
recycler_view.adapter = adapter
}
private fun upRecyclerView(bookSource: BookSource?) {
bookSource?.let {
cb_is_enable.isChecked = it.isEnabled
cb_is_enable_find.isChecked = it.exploreIsEnabled
}
sourceEditEntities.clear()
sourceEditEntities.add(SourceEditEntity("origin", bookSource?.origin, R.string.book_source_url))
sourceEditEntities.add(SourceEditEntity("name", bookSource?.name, R.string.book_source_name))
sourceEditEntities.add(SourceEditEntity("group", bookSource?.group, R.string.book_source_group))
adapter.sourceEditEntities = sourceEditEntities
adapter.notifyDataSetChanged()
}
private fun getSource(): BookSource? {
val bookSource = BookSource()
bookSource.isEnabled = cb_is_enable.isChecked
bookSource.exploreIsEnabled = cb_is_enable_find.isChecked
for (entity in adapter.sourceEditEntities) {
when (entity.key) {
"origin" -> {
if (entity.value == null) {
return null
} else {
bookSource.origin = entity.value!!
}
}
"name" -> {
if (entity.value == null) {
return null
} else {
bookSource.name = entity.value!!
}
}
"group" -> bookSource.group = entity.value
}
}
return bookSource
}
class SourceEditEntity(var key: String, var value: String?, var hint: Int)
}

@ -0,0 +1,72 @@
package io.legado.app.ui.sourceedit
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import kotlinx.android.synthetic.main.item_source_edit.view.*
class SourceEditAdapter : RecyclerView.Adapter<SourceEditAdapter.MyViewHolder>() {
var sourceEditEntities: ArrayList<SourceEditActivity.SourceEditEntity> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_source_edit, parent, false))
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(sourceEditEntities[position])
}
override fun getItemCount(): Int {
return sourceEditEntities.size
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(sourceEditEntity: SourceEditActivity.SourceEditEntity) = with(itemView) {
if (editText.getTag(R.id.tag1) == null) {
val listener = object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
editText.isCursorVisible = false
editText.isCursorVisible = true
editText.isFocusable = true
editText.isFocusableInTouchMode = true
}
override fun onViewDetachedFromWindow(v: View) {
}
}
editText.addOnAttachStateChangeListener(listener)
editText.setTag(R.id.tag1, listener)
}
editText.getTag(R.id.tag2)?.let {
if (it is TextWatcher) {
editText.removeTextChangedListener(it)
}
}
editText.setText(sourceEditEntity.value)
textInputLayout.hint = context.getString(sourceEditEntity.hint)
val textWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
sourceEditEntity.value = (s?.toString())
}
}
editText.addTextChangedListener(textWatcher)
editText.setTag(R.id.tag2, textWatcher)
}
}
}

@ -2,7 +2,30 @@ package io.legado.app.ui.sourceedit
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import io.legado.app.App
import io.legado.app.data.entities.BookSource
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
class SourceEditViewModel(application: Application) : AndroidViewModel(application) {
val sourceLiveData: MutableLiveData<BookSource> = MutableLiveData()
fun setBookSource(key: String) {
GlobalScope.launch {
val source = App.db.bookSourceDao().findByKey(key)
sourceLiveData.postValue(source)
}
}
fun save(bookSource: BookSource) {
val source = App.db.bookSourceDao().findByKey(bookSource.origin)
if (source == null) {
bookSource.customOrder = App.db.bookSourceDao().allCount()
}
App.db.bookSourceDao().insert(bookSource)
}
}

@ -0,0 +1,233 @@
package io.legado.app.ui.widget
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.text.TextUtils
import android.util.AttributeSet
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams
import android.widget.TabWidget
import androidx.appcompat.widget.AppCompatTextView
import io.legado.app.R
/**
* Created by milad heydari on 5/6/2016.
*/
class BadgeView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = android.R.attr.textViewStyle
) : AppCompatTextView(context, attrs, defStyle) {
/**
* @return Returns true if view is hidden on badge value 0 or null;
*/
/**
* @param hideOnNull the hideOnNull to set
*/
var isHideOnNull = true
set(hideOnNull) {
field = hideOnNull
text = text
}
private var radius: Float = 0.toFloat()
val badgeCount: Int?
get() {
if (text == null) {
return null
}
val text = text.toString()
try {
return Integer.parseInt(text)
} catch (e: NumberFormatException) {
return null
}
}
var badgeGravity: Int
get() {
val params = layoutParams as LayoutParams
return params.gravity
}
set(gravity) {
val params = layoutParams as LayoutParams
params.gravity = gravity
layoutParams = params
}
val badgeMargin: IntArray
get() {
val params = layoutParams as LayoutParams
return intArrayOf(params.leftMargin, params.topMargin, params.rightMargin, params.bottomMargin)
}
init {
init()
}
private fun init() {
if (layoutParams !is LayoutParams) {
val layoutParams = LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
Gravity.CENTER
)
setLayoutParams(layoutParams)
}
// set default font
setTextColor(Color.WHITE)
//setTypeface(Typeface.DEFAULT_BOLD);
setTextSize(TypedValue.COMPLEX_UNIT_SP, 11f)
setPadding(dip2Px(5f), dip2Px(1f), dip2Px(5f), dip2Px(1f))
radius = 8f
// set default background
setBackground(radius, Color.parseColor("#d3321b"))
gravity = Gravity.CENTER
// default values
isHideOnNull = true
setBadgeCount(0)
minWidth = dip2Px(16f)
minHeight = dip2Px(16f)
}
fun setBackground(dipRadius: Float, badgeColor: Int) {
val radius = dip2Px(dipRadius)
val radiusArray = floatArrayOf(
radius.toFloat(),
radius.toFloat(),
radius.toFloat(),
radius.toFloat(),
radius.toFloat(),
radius.toFloat(),
radius.toFloat(),
radius.toFloat()
)
val roundRect = RoundRectShape(radiusArray, null, null)
val bgDrawable = ShapeDrawable(roundRect)
bgDrawable.paint.color = badgeColor
background = bgDrawable
}
fun setBackground(badgeColor: Int) {
setBackground(radius, badgeColor)
}
/**
* @see android.widget.TextView.setText
*/
override fun setText(text: CharSequence, type: BufferType) {
if (isHideOnNull && TextUtils.isEmpty(text)) {
visibility = View.GONE
} else {
visibility = View.VISIBLE
}
super.setText(text, type)
}
fun setBadgeCount(count: Int) {
text = count.toString()
if (count == 0) {
visibility = View.GONE
}
}
fun setHighlight(highlight: Boolean) {
setBackground(resources.getColor(if (highlight) R.color.highlight else R.color.darker_gray))
}
fun setBadgeMargin(dipMargin: Int) {
setBadgeMargin(dipMargin, dipMargin, dipMargin, dipMargin)
}
fun setBadgeMargin(leftDipMargin: Int, topDipMargin: Int, rightDipMargin: Int, bottomDipMargin: Int) {
val params = layoutParams as LayoutParams
params.leftMargin = dip2Px(leftDipMargin.toFloat())
params.topMargin = dip2Px(topDipMargin.toFloat())
params.rightMargin = dip2Px(rightDipMargin.toFloat())
params.bottomMargin = dip2Px(bottomDipMargin.toFloat())
layoutParams = params
}
fun incrementBadgeCount(increment: Int) {
val count = badgeCount
if (count == null) {
setBadgeCount(increment)
} else {
setBadgeCount(increment + count)
}
}
fun decrementBadgeCount(decrement: Int) {
incrementBadgeCount(-decrement)
}
/**
* Attach the BadgeView to the TabWidget
* @param target the TabWidget to attach the BadgeView
* @param tabIndex index of the tab
*/
fun setTargetView(target: TabWidget, tabIndex: Int) {
val tabView = target.getChildTabViewAt(tabIndex)
setTargetView(tabView)
}
/**
* Attach the BadgeView to the target view
* @param target the view to attach the BadgeView
*/
fun setTargetView(target: View?) {
if (parent != null) {
(parent as ViewGroup).removeView(this)
}
if (target == null) {
return
}
if (target.parent is FrameLayout) {
(target.parent as FrameLayout).addView(this)
} else if (target.parent is ViewGroup) {
// use a new FrameLayout container for adding badge
val parentContainer = target.parent as ViewGroup
val groupIndex = parentContainer.indexOfChild(target)
parentContainer.removeView(target)
val badgeContainer = FrameLayout(context)
val parentLayoutParams = target.layoutParams
badgeContainer.layoutParams = parentLayoutParams
target.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
parentContainer.addView(badgeContainer, groupIndex, parentLayoutParams)
badgeContainer.addView(target)
badgeContainer.addView(this)
}
}
/**
* converts dip to px
*/
private fun dip2Px(dip: Float): Int {
return (dip * context.resources.displayMetrics.density + 0.5f).toInt()
}
}

@ -0,0 +1,212 @@
package io.legado.app.ui.widget
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.view.animation.LinearInterpolator
import io.legado.app.R
/**
* RotateLoading
* Created by Victor on 2015/4/28.
*/
class RotateLoading : View {
private var mPaint: Paint? = null
private var loadingRectF: RectF? = null
private var shadowRectF: RectF? = null
private var topDegree = 10
private var bottomDegree = 190
private var arc: Float = 0.toFloat()
private var thisWidth: Int = 0
private var changeBigger = true
private var shadowPosition: Int = 0
var isStart = false
private set
var loadingColor: Int = 0
private var speedOfDegree: Int = 0
private var speedOfArc: Float = 0.toFloat()
constructor(context: Context) : super(context) {
initView(context, null)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initView(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initView(context, attrs)
}
private fun initView(context: Context, attrs: AttributeSet?) {
loadingColor = Color.WHITE
thisWidth = dpToPx(context, DEFAULT_WIDTH.toFloat())
shadowPosition = dpToPx(getContext(), DEFAULT_SHADOW_POSITION.toFloat())
speedOfDegree = DEFAULT_SPEED_OF_DEGREE
if (null != attrs) {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.RotateLoading)
loadingColor = typedArray.getColor(R.styleable.RotateLoading_loading_color, Color.WHITE)
thisWidth = typedArray.getDimensionPixelSize(
R.styleable.RotateLoading_loading_width,
dpToPx(context, DEFAULT_WIDTH.toFloat())
)
shadowPosition = typedArray.getInt(R.styleable.RotateLoading_shadow_position, DEFAULT_SHADOW_POSITION)
speedOfDegree = typedArray.getInt(R.styleable.RotateLoading_loading_speed, DEFAULT_SPEED_OF_DEGREE)
typedArray.recycle()
}
speedOfArc = (speedOfDegree / 4).toFloat()
mPaint = Paint()
mPaint!!.color = loadingColor
mPaint!!.isAntiAlias = true
mPaint!!.style = Paint.Style.STROKE
mPaint!!.strokeWidth = thisWidth.toFloat()
mPaint!!.strokeCap = Paint.Cap.ROUND
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
arc = 10f
loadingRectF =
RectF(
(2 * thisWidth).toFloat(),
(2 * thisWidth).toFloat(),
(w - 2 * thisWidth).toFloat(),
(h - 2 * thisWidth).toFloat()
)
shadowRectF = RectF(
(2 * thisWidth + shadowPosition).toFloat(),
(2 * thisWidth + shadowPosition).toFloat(),
(w - 2 * thisWidth + shadowPosition).toFloat(),
(h - 2 * thisWidth + shadowPosition).toFloat()
)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (!isStart) {
return
}
mPaint!!.color = Color.parseColor("#1a000000")
canvas.drawArc(shadowRectF!!, topDegree.toFloat(), arc, false, mPaint!!)
canvas.drawArc(shadowRectF!!, bottomDegree.toFloat(), arc, false, mPaint!!)
mPaint!!.color = loadingColor
canvas.drawArc(loadingRectF!!, topDegree.toFloat(), arc, false, mPaint!!)
canvas.drawArc(loadingRectF!!, bottomDegree.toFloat(), arc, false, mPaint!!)
topDegree += speedOfDegree
bottomDegree += speedOfDegree
if (topDegree > 360) {
topDegree = topDegree - 360
}
if (bottomDegree > 360) {
bottomDegree = bottomDegree - 360
}
if (changeBigger) {
if (arc < 160) {
arc += speedOfArc
invalidate()
}
} else {
if (arc > speedOfDegree) {
arc -= 2 * speedOfArc
invalidate()
}
}
if (arc >= 160 || arc <= 10) {
changeBigger = !changeBigger
invalidate()
}
}
fun start() {
startAnimator()
isStart = true
invalidate()
}
fun stop() {
stopAnimator()
invalidate()
}
private fun startAnimator() {
val scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX", 0.0f, 1f)
val scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", 0.0f, 1f)
scaleXAnimator.setDuration(300)
scaleXAnimator.setInterpolator(LinearInterpolator())
scaleYAnimator.setDuration(300)
scaleYAnimator.setInterpolator(LinearInterpolator())
val animatorSet = AnimatorSet()
animatorSet.playTogether(scaleXAnimator, scaleYAnimator)
animatorSet.start()
}
private fun stopAnimator() {
val scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX", 1f, 0f)
val scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", 1f, 0f)
scaleXAnimator.setDuration(300)
scaleXAnimator.setInterpolator(LinearInterpolator())
scaleYAnimator.setDuration(300)
scaleYAnimator.setInterpolator(LinearInterpolator())
val animatorSet = AnimatorSet()
animatorSet.playTogether(scaleXAnimator, scaleYAnimator)
animatorSet.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {
}
override fun onAnimationEnd(animation: Animator) {
isStart = false
}
override fun onAnimationCancel(animation: Animator) {
}
override fun onAnimationRepeat(animation: Animator) {
}
})
animatorSet.start()
}
fun dpToPx(context: Context, dpVal: Float): Int {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.resources.displayMetrics).toInt()
}
companion object {
private val DEFAULT_WIDTH = 6
private val DEFAULT_SHADOW_POSITION = 2
private val DEFAULT_SPEED_OF_DEGREE = 10
}
}

@ -46,7 +46,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a
private val attachToActivity: Boolean
init {
inflate(context, R.layout.view_titlebar, this)
inflate(context, R.layout.view_title_bar, this)
setBackgroundColor(ThemeStore.primaryColor(context))
toolbar = findViewById(R.id.toolbar)
val a = context.obtainStyledAttributes(

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

@ -0,0 +1,56 @@
package io.legado.app.ui.widget.image
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Path
import android.util.AttributeSet
class CoverImageView : androidx.appcompat.widget.AppCompatImageView {
internal var width: Float = 0.toFloat()
internal var height: Float = 0.toFloat()
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
width = getWidth().toFloat()
height = getHeight().toFloat()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val measuredWidth = MeasureSpec.getSize(widthMeasureSpec)
val measuredHeight = measuredWidth * 7 / 5
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY))
}
override fun onDraw(canvas: Canvas) {
if (width >= 10 && height > 10) {
@SuppressLint("DrawAllocation")
val path = Path()
//四个圆角
path.moveTo(10f, 0f)
path.lineTo(width - 10, 0f)
path.quadTo(width, 0f, width, 10f)
path.lineTo(width, height - 10)
path.quadTo(width, height, width - 10, height)
path.lineTo(10f, height)
path.quadTo(0f, height, 0f, height - 10)
path.lineTo(0f, 10f)
path.quadTo(0f, 0f, 10f, 0f)
canvas.clipPath(path)
}
super.onDraw(canvas)
}
fun setHeight(height: Int) {
val width = height * 5 / 7
minimumWidth = width
}
}

@ -0,0 +1,92 @@
package io.legado.app.ui.widget.image
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Path
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import io.legado.app.R
class FilletImageView : AppCompatImageView {
internal var width: Float = 0.toFloat()
internal var height: Float = 0.toFloat()
private var leftTopRadius: Int = 0
private var rightTopRadius: Int = 0
private var rightBottomRadius: Int = 0
private var leftBottomRadius: Int = 0
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet) {
// 读取配置
val array = context.obtainStyledAttributes(attrs, R.styleable.FilletImageView)
val defaultRadius = 5
val radius = array.getDimensionPixelOffset(R.styleable.FilletImageView_radius, defaultRadius)
leftTopRadius = array.getDimensionPixelOffset(R.styleable.FilletImageView_left_top_radius, defaultRadius)
rightTopRadius = array.getDimensionPixelOffset(R.styleable.FilletImageView_right_top_radius, defaultRadius)
rightBottomRadius =
array.getDimensionPixelOffset(R.styleable.FilletImageView_right_bottom_radius, defaultRadius)
leftBottomRadius = array.getDimensionPixelOffset(R.styleable.FilletImageView_left_bottom_radius, defaultRadius)
//如果四个角的值没有设置,那么就使用通用的radius的值。
if (defaultRadius == leftTopRadius) {
leftTopRadius = radius
}
if (defaultRadius == rightTopRadius) {
rightTopRadius = radius
}
if (defaultRadius == rightBottomRadius) {
rightBottomRadius = radius
}
if (defaultRadius == leftBottomRadius) {
leftBottomRadius = radius
}
array.recycle()
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
width = getWidth().toFloat()
height = getHeight().toFloat()
}
override fun onDraw(canvas: Canvas) {
//这里做下判断,只有图片的宽高大于设置的圆角距离的时候才进行裁剪
val maxLeft = Math.max(leftTopRadius, leftBottomRadius)
val maxRight = Math.max(rightTopRadius, rightBottomRadius)
val minWidth = maxLeft + maxRight
val maxTop = Math.max(leftTopRadius, rightTopRadius)
val maxBottom = Math.max(leftBottomRadius, rightBottomRadius)
val minHeight = maxTop + maxBottom
if (width >= minWidth && height > minHeight) {
@SuppressLint("DrawAllocation") val path = Path()
//四个角:右上,右下,左下,左上
path.moveTo(leftTopRadius.toFloat(), 0f)
path.lineTo(width - rightTopRadius, 0f)
path.quadTo(width, 0f, width, rightTopRadius.toFloat())
path.lineTo(width, height - rightBottomRadius)
path.quadTo(width, height, width - rightBottomRadius, height)
path.lineTo(leftBottomRadius.toFloat(), height)
path.quadTo(0f, height, 0f, height - leftBottomRadius)
path.lineTo(0f, leftTopRadius.toFloat())
path.quadTo(0f, 0f, leftTopRadius.toFloat(), 0f)
canvas.clipPath(path)
}
super.onDraw(canvas)
}
}

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

@ -1,4 +1,5 @@
package io.legado.app.utils
// import org.apache.commons.text.StringEscapeUtils
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)
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)

@ -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.getViewModelOfActivity(clazz: Class<T>) = ViewModelProviders.of(requireActivity()).get(clazz)
fun <T : ViewModel> Fragment.getViewModelOfActivity(clazz: Class<T>) =
ViewModelProviders.of(requireActivity()).get(clazz)

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/btn_bg_press_2">
<item android:id="@android:id/mask" android:drawable="@color/btn_bg_press_2"/>
android:color="@color/btn_bg_press_2">
<item
android:id="@android:id/mask"
android:drawable="@color/btn_bg_press_2" />
</ripple>

@ -1,3 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/btn_bg_press"/>
android:color="@color/btn_bg_press" />

@ -1,34 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0"/>
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1"/>
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
android:shape="line">
<stroke
android:width="1dp"
android:color="@color/bg_divider_line"
android:dashWidth="3dp"
android:dashGap="3dp"/>
android:width="1dp"
android:color="@color/bg_divider_line"
android:dashWidth="3dp"
android:dashGap="3dp" />
</shape>

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="1dp"
android:color="@color/btn_bg_press"/>
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="@color/btn_bg_press" />
</shape>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/transparent" android:state_pressed="false"/>
<item android:drawable="@color/btn_bg_press" android:state_pressed="true"/>
<item android:drawable="@android:color/transparent" android:state_pressed="false" />
<item android:drawable="@color/btn_bg_press" android:state_pressed="true" />
</selector>

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/transparent"/>
<item android:drawable="@android:color/transparent" />
</selector>

@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
tools:ignore="PrivateResource">
<item android:drawable="@drawable/abc_textfield_search_activated_mtrl_alpha" android:state_enabled="true"
android:state_focused="true"/>
<item android:drawable="@drawable/abc_textfield_search_activated_mtrl_alpha" android:state_activated="true"
android:state_enabled="true"/>
<item android:drawable="@drawable/abc_textfield_search_default_mtrl_alpha" android:state_enabled="true"/>
<item android:drawable="@drawable/abc_textfield_search_default_mtrl_alpha"/>
<selector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:ignore="PrivateResource">
<item android:drawable="@drawable/abc_textfield_search_activated_mtrl_alpha" android:state_enabled="true" android:state_focused="true" />
<item android:drawable="@drawable/abc_textfield_search_activated_mtrl_alpha" android:state_activated="true" android:state_enabled="true" />
<item android:drawable="@drawable/abc_textfield_search_default_mtrl_alpha" android:state_enabled="true" />
<item android:drawable="@drawable/abc_textfield_search_default_mtrl_alpha" />
</selector>

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2016 L4 Digital LLC. All rights reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@ -15,25 +14,24 @@
~ limitations under the License.
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:shape="rectangle">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:shape="rectangle">
<tools:solid android:color="#777777"/>
<tools:solid android:color="#777777" />
<corners
android:topLeftRadius="@dimen/fastscroll_bubble_radius"
android:topRightRadius="@dimen/fastscroll_bubble_radius"
android:bottomLeftRadius="@dimen/fastscroll_bubble_radius"
android:bottomRightRadius="0dp"/>
android:topLeftRadius="@dimen/fastscroll_bubble_radius"
android:topRightRadius="@dimen/fastscroll_bubble_radius"
android:bottomLeftRadius="@dimen/fastscroll_bubble_radius"
android:bottomRightRadius="0dp" />
<size
android:height="@dimen/fastscroll_bubble_size"
android:width="@dimen/fastscroll_bubble_size"/>
android:height="@dimen/fastscroll_bubble_size"
android:width="@dimen/fastscroll_bubble_size" />
<padding
android:left="@dimen/fastscroll_bubble_padding"
android:right="@dimen/fastscroll_bubble_padding"/>
android:left="@dimen/fastscroll_bubble_padding"
android:right="@dimen/fastscroll_bubble_padding" />
</shape>

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2016 L4 Digital LLC. All rights reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@ -15,17 +14,16 @@
~ limitations under the License.
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:shape="rectangle">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:shape="rectangle">
<tools:solid android:color="#555555"/>
<tools:solid android:color="#555555" />
<corners android:radius="@dimen/fastscroll_handle_radius"/>
<corners android:radius="@dimen/fastscroll_handle_radius" />
<size
android:height="@dimen/fastscroll_handle_height"
android:width="@dimen/fastscroll_handle_width"/>
android:height="@dimen/fastscroll_handle_height"
android:width="@dimen/fastscroll_handle_width" />
</shape>

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2016 L4 Digital LLC. All rights reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@ -15,13 +14,12 @@
~ limitations under the License.
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:shape="rectangle">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:shape="rectangle">
<tools:solid android:color="#CCCCCC"/>
<tools:solid android:color="#CCCCCC" />
<size android:width="@dimen/fastscroll_track_width"/>
<size android:width="@dimen/fastscroll_track_width" />
</shape>

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M7.699,18.758 L7.699,13.219 L4,9.742 L20,5.242 L13.332,18.574 L10.785,16.125 L7.699,18.758 Z M9.455,13.035 L12.888,16.267 L16.987,8.288 L9.455,13.035 Z M9.035,14.477 L9.035,15.887 L9.81,15.209 L9.035,14.477 Z M6.655,10.398 L8.449,12.086 L14.544,8.248 L6.655,10.398 Z"/>
android:fillColor="#595757"
android:pathData="M7.699,18.758 L7.699,13.219 L4,9.742 L20,5.242 L13.332,18.574 L10.785,16.125 L7.699,18.758 Z M9.455,13.035 L12.888,16.267 L16.987,8.288 L9.455,13.035 Z M9.035,14.477 L9.035,15.887 L9.81,15.209 L9.035,14.477 Z M6.655,10.398 L8.449,12.086 L14.544,8.248 L6.655,10.398 Z" />
</vector>

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M12.822,20 L11.177,20 L11.177,12.821 L4,12.821 L4,11.178 L11.178,11.178 L11.178,4 L12.823,4 L12.823,11.179 L20,11.179 L20,12.822 L12.822,12.822 L12.822,20 Z"/>
android:fillColor="#595757"
android:pathData="M12.822,20 L11.177,20 L11.177,12.821 L4,12.821 L4,11.178 L11.178,11.178 L11.178,4 L12.823,4 L12.823,11.179 L20,11.179 L20,12.822 L12.822,12.822 L12.822,20 Z" />
</vector>

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M5.689,20 C5.164,20,4.74,19.844,4.432,19.537 C3.242,18.345,4.772,15.546,5.863,13.892 C5.683,13.308,5.595,12.688,5.595,12 C5.595,8.469,8.467,5.596,11.998,5.596 C12.684,5.596,13.308,5.685,13.898,5.868 C15.013,5.131,16.948,4,18.339,4 C18.84,4,19.242,4.146,19.531,4.435 C20.308,5.212,20.118,6.648,18.965,8.697 C18.724,9.127,18.433,9.588,18.099,10.076 C18.296,10.703,18.396,11.345,18.396,11.986 C18.396,15.524,15.526,18.403,11.998,18.403 C11.349,18.403,10.7,18.304,10.067,18.103 C8.774,18.991,7.013,20,5.689,20 Z M6.51,15.317 C5.331,17.292,5.196,18.449,5.357,18.611 C5.418,18.673,5.543,18.706,5.709,18.706 C6.337,18.706,7.422,18.249,8.669,17.469 C7.791,16.935,7.046,16.193,6.51,15.317 Z M11.473,17.068 C11.651,17.087,11.826,17.096,11.998,17.096 C14.806,17.096,17.089,14.803,17.089,11.985 C17.089,11.82,17.081,11.651,17.063,11.482 C16.282,12.473,15.398,13.461,14.428,14.43 C13.48,15.38,12.47,16.28,11.473,17.068 Z M11.998,6.901 C9.188,6.901,6.902,9.19,6.902,12 C6.902,14.017,8.066,15.818,9.885,16.641 C11.084,15.764,12.301,14.711,13.504,13.508 C14.686,12.326,15.765,11.076,16.635,9.883 C15.811,8.068,14.011,6.901,11.998,6.901 Z M15.317,6.516 C16.19,7.051,16.929,7.791,17.461,8.666 C17.598,8.448,17.72,8.247,17.827,8.055 C18.848,6.24,18.729,5.482,18.607,5.36 C18.605,5.357,18.549,5.304,18.335,5.304 C18.084,5.304,17.163,5.396,15.317,6.516 Z"/>
android:fillColor="#595757"
android:pathData="M5.689,20 C5.164,20,4.74,19.844,4.432,19.537 C3.242,18.345,4.772,15.546,5.863,13.892 C5.683,13.308,5.595,12.688,5.595,12 C5.595,8.469,8.467,5.596,11.998,5.596 C12.684,5.596,13.308,5.685,13.898,5.868 C15.013,5.131,16.948,4,18.339,4 C18.84,4,19.242,4.146,19.531,4.435 C20.308,5.212,20.118,6.648,18.965,8.697 C18.724,9.127,18.433,9.588,18.099,10.076 C18.296,10.703,18.396,11.345,18.396,11.986 C18.396,15.524,15.526,18.403,11.998,18.403 C11.349,18.403,10.7,18.304,10.067,18.103 C8.774,18.991,7.013,20,5.689,20 Z M6.51,15.317 C5.331,17.292,5.196,18.449,5.357,18.611 C5.418,18.673,5.543,18.706,5.709,18.706 C6.337,18.706,7.422,18.249,8.669,17.469 C7.791,16.935,7.046,16.193,6.51,15.317 Z M11.473,17.068 C11.651,17.087,11.826,17.096,11.998,17.096 C14.806,17.096,17.089,14.803,17.089,11.985 C17.089,11.82,17.081,11.651,17.063,11.482 C16.282,12.473,15.398,13.461,14.428,14.43 C13.48,15.38,12.47,16.28,11.473,17.068 Z M11.998,6.901 C9.188,6.901,6.902,9.19,6.902,12 C6.902,14.017,8.066,15.818,9.885,16.641 C11.084,15.764,12.301,14.711,13.504,13.508 C14.686,12.326,15.765,11.076,16.635,9.883 C15.811,8.068,14.011,6.901,11.998,6.901 Z M15.317,6.516 C16.19,7.051,16.929,7.791,17.461,8.666 C17.598,8.448,17.72,8.247,17.827,8.055 C18.848,6.24,18.729,5.482,18.607,5.36 C18.605,5.357,18.549,5.304,18.335,5.304 C18.084,5.304,17.163,5.396,15.317,6.516 Z" />
</vector>

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M12.167,4h-2.025c-0.604,0-1.08,0.529-1.08,1.206v13.588c0,0.677,0.476,1.206,1.08,1.206h2.025 c0.605,0,1.08-0.529,1.08-1.206V5.206C13.247,4.529,12.772,4,12.167,4z M11.792,5.454v9.531h-1.273V5.454H11.792z M10.519,18.546 v-2.106h1.273v2.106H10.519z"/>
android:fillColor="#595757"
android:pathData="M12.167,4h-2.025c-0.604,0-1.08,0.529-1.08,1.206v13.588c0,0.677,0.476,1.206,1.08,1.206h2.025 c0.605,0,1.08-0.529,1.08-1.206V5.206C13.247,4.529,12.772,4,12.167,4z M11.792,5.454v9.531h-1.273V5.454H11.792z M10.519,18.546 v-2.106h1.273v2.106H10.519z" />
<path
android:fillColor="#595757"
android:pathData="M7.104,6.693H5.079c-0.596,0-1.078,0.501-1.078,1.117v11.072C4.001,19.499,4.483,20,5.079,20h2.025 c0.596,0,1.081-0.501,1.081-1.117V7.811C8.186,7.195,7.7,6.693,7.104,6.693z M6.729,8.148v6.837H5.455V8.148H6.729z M5.455,18.546 v-2.106h1.274v2.106H5.455z"/>
android:fillColor="#595757"
android:pathData="M7.104,6.693H5.079c-0.596,0-1.078,0.501-1.078,1.117v11.072C4.001,19.499,4.483,20,5.079,20h2.025 c0.596,0,1.081-0.501,1.081-1.117V7.811C8.186,7.195,7.7,6.693,7.104,6.693z M6.729,8.148v6.837H5.455V8.148H6.729z M5.455,18.546 v-2.106h1.274v2.106H5.455z" />
<path
android:fillColor="#595757"
android:pathData="M17.976,7.433c-0.098-0.534-0.551-0.921-1.075-0.921l-2.183,0.383 c-0.584,0.108-0.969,0.689-0.858,1.294l2.006,10.89c0.099,0.534,0.55,0.92,1.074,0.92l2.183-0.383 c0.585-0.108,0.969-0.689,0.859-1.294L17.976,7.433z M15.354,8.256l1.25-0.234l1.289,7.004l-1.256,0.209L15.354,8.256z M17.235,18.484L16.9,16.667l1.257-0.209l0.33,1.797L17.235,18.484z"/>
android:fillColor="#595757"
android:pathData="M17.976,7.433c-0.098-0.534-0.551-0.921-1.075-0.921l-2.183,0.383 c-0.584,0.108-0.969,0.689-0.858,1.294l2.006,10.89c0.099,0.534,0.55,0.92,1.074,0.92l2.183-0.383 c0.585-0.108,0.969-0.689,0.859-1.294L17.976,7.433z M15.354,8.256l1.25-0.234l1.289,7.004l-1.256,0.209L15.354,8.256z M17.235,18.484L16.9,16.667l1.257-0.209l0.33,1.797L17.235,18.484z" />
</vector>

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
android:fillColor="#FF000000"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" />
</vector>

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M7,10l5,5 5,-5z"/>
android:fillColor="#FF000000"
android:pathData="M7,10l5,5 5,-5z" />
</vector>

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M7,14l5,-5 5,5z"/>
android:fillColor="#FF000000"
android:pathData="M7,14l5,-5 5,5z" />
</vector>

@ -1,12 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,3c-4.963,0 -9,4.037 -9,9s4.037,9 9,9s9,-4.037 9,-9S16.963,3 12,3zM12,13.826c-2.277,0 -4.371,1.177 -5.542,3.092C5.245,15.554 4.581,13.82 4.581,12c0,-4.091 3.328,-7.419 7.419,-7.419S19.419,7.909 19.419,12c0,1.82 -0.664,3.554 -1.877,4.918C16.371,15.003 14.277,13.826 12,13.826zM12,15.407c1.811,0 3.489,1.013 4.33,2.598c-1.27,0.926 -2.762,1.414 -4.33,1.414c-1.568,0 -3.062,-0.488 -4.332,-1.414C8.511,16.42 10.189,15.407 12,15.407z"
android:fillColor="#4A4B4A"/>
android:pathData="M12,3c-4.963,0 -9,4.037 -9,9s4.037,9 9,9s9,-4.037 9,-9S16.963,3 12,3zM12,13.826c-2.277,0 -4.371,1.177 -5.542,3.092C5.245,15.554 4.581,13.82 4.581,12c0,-4.091 3.328,-7.419 7.419,-7.419S19.419,7.909 19.419,12c0,1.82 -0.664,3.554 -1.877,4.918C16.371,15.003 14.277,13.826 12,13.826zM12,15.407c1.811,0 3.489,1.013 4.33,2.598c-1.27,0.926 -2.762,1.414 -4.33,1.414c-1.568,0 -3.062,-0.488 -4.332,-1.414C8.511,16.42 10.189,15.407 12,15.407z"
android:fillColor="#4A4B4A" />
<path
android:pathData="M12,6.014c-2.178,0 -3.951,1.746 -3.951,3.893c0,2.149 1.772,3.899 3.951,3.899s3.951,-1.75 3.951,-3.899C15.951,7.76 14.178,6.014 12,6.014zM12,12.225c-1.307,0 -2.37,-1.041 -2.37,-2.318c0,-1.274 1.063,-2.312 2.37,-2.312s2.37,1.037 2.37,2.312C14.37,11.184 13.307,12.225 12,12.225z"
android:fillColor="#4A4B4A"/>
android:pathData="M12,6.014c-2.178,0 -3.951,1.746 -3.951,3.893c0,2.149 1.772,3.899 3.951,3.899s3.951,-1.75 3.951,-3.899C15.951,7.76 14.178,6.014 12,6.014zM12,12.225c-1.307,0 -2.37,-1.041 -2.37,-2.318c0,-1.274 1.063,-2.312 2.37,-2.312s2.37,1.037 2.37,2.312C14.37,11.184 13.307,12.225 12,12.225z"
android:fillColor="#4A4B4A" />
</vector>

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M19.109,6.212h-2.16l-0.002-0.817c0-0.366-0.164-0.66-0.44-0.788 c-0.133-0.062-0.278-0.091-0.445-0.091c-0.295,0-0.595,0.092-0.885,0.181l-5.121,1.516H4.891c-0.569,0-1.016,0.407-1.016,0.927 v9.907c0,0.52,0.446,0.926,1.016,0.926h5.283c0.693,0.19,4.949,1.359,5.308,1.463c0.115,0.033,0.229,0.05,0.339,0.05 c0.529,0,1.083-0.422,1.098-0.84l0.002-0.673h2.189c0.569,0,1.016-0.406,1.016-0.926V7.139C20.125,6.619,19.679,6.212,19.109,6.212 z M18.687,7.65v8.883h-1.763l0.023-8.883H18.687z M15.516,17.95c-0.723-0.204-2.282-0.65-3.459-0.988 c-0.794-0.228-1.414-0.405-1.485-0.425l-5.258-0.004V7.65h5.225l4.972-1.524L15.516,17.95z"/>
android:fillColor="#595757"
android:pathData="M19.109,6.212h-2.16l-0.002-0.817c0-0.366-0.164-0.66-0.44-0.788 c-0.133-0.062-0.278-0.091-0.445-0.091c-0.295,0-0.595,0.092-0.885,0.181l-5.121,1.516H4.891c-0.569,0-1.016,0.407-1.016,0.927 v9.907c0,0.52,0.446,0.926,1.016,0.926h5.283c0.693,0.19,4.949,1.359,5.308,1.463c0.115,0.033,0.229,0.05,0.339,0.05 c0.529,0,1.083-0.422,1.098-0.84l0.002-0.673h2.189c0.569,0,1.016-0.406,1.016-0.926V7.139C20.125,6.619,19.679,6.212,19.109,6.212 z M18.687,7.65v8.883h-1.763l0.023-8.883H18.687z M15.516,17.95c-0.723-0.204-2.282-0.65-3.459-0.988 c-0.794-0.228-1.414-0.405-1.485-0.425l-5.258-0.004V7.65h5.225l4.972-1.524L15.516,17.95z" />
<path
android:fillColor="#595757"
android:pathData="M 9.544 8.915 L 6.366 12.092 L 9.544 15.269 L 10.562 14.252 L 9.12 12.811 L 14.217 12.811 L 14.217 11.372 L 9.12 11.372 L 10.562 9.932 Z"/>
android:fillColor="#595757"
android:pathData="M 9.544 8.915 L 6.366 12.092 L 9.544 15.269 L 10.562 14.252 L 9.12 12.811 L 14.217 12.811 L 14.217 11.372 L 9.12 11.372 L 10.562 9.932 Z" />
</vector>

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M19.109,6.212h-2.16l-0.002-0.817c0-0.366-0.164-0.66-0.44-0.788 c-0.133-0.062-0.278-0.091-0.445-0.091c-0.295,0-0.595,0.092-0.885,0.181l-5.121,1.516H4.891c-0.569,0-1.016,0.407-1.016,0.927 v9.907c0,0.52,0.446,0.926,1.016,0.926h5.283c0.693,0.19,4.949,1.359,5.308,1.463c0.115,0.033,0.229,0.05,0.339,0.05 c0.529,0,1.083-0.422,1.098-0.84l0.002-0.673h2.189c0.569,0,1.016-0.406,1.016-0.926V7.139C20.125,6.619,19.679,6.212,19.109,6.212 z M12.057,16.962c-0.794-0.228-1.414-0.405-1.485-0.425l-5.258-0.004V7.65h5.225l4.972-1.524l0.006,11.824 C14.793,17.746,13.233,17.3,12.057,16.962z M18.687,16.533h-1.763l0.023-8.883h1.739V16.533z"/>
android:fillColor="#595757"
android:pathData="M19.109,6.212h-2.16l-0.002-0.817c0-0.366-0.164-0.66-0.44-0.788 c-0.133-0.062-0.278-0.091-0.445-0.091c-0.295,0-0.595,0.092-0.885,0.181l-5.121,1.516H4.891c-0.569,0-1.016,0.407-1.016,0.927 v9.907c0,0.52,0.446,0.926,1.016,0.926h5.283c0.693,0.19,4.949,1.359,5.308,1.463c0.115,0.033,0.229,0.05,0.339,0.05 c0.529,0,1.083-0.422,1.098-0.84l0.002-0.673h2.189c0.569,0,1.016-0.406,1.016-0.926V7.139C20.125,6.619,19.679,6.212,19.109,6.212 z M12.057,16.962c-0.794-0.228-1.414-0.405-1.485-0.425l-5.258-0.004V7.65h5.225l4.972-1.524l0.006,11.824 C14.793,17.746,13.233,17.3,12.057,16.962z M18.687,16.533h-1.763l0.023-8.883h1.739V16.533z" />
<path
android:fillColor="#595757"
android:pathData="M 8.208 9.5 H 9.646 V 14.5 H 8.208 V 9.5 Z"/>
android:fillColor="#595757"
android:pathData="M 8.208 9.5 H 9.646 V 14.5 H 8.208 V 9.5 Z" />
<path
android:fillColor="#595757"
android:pathData="M 11.396 9.5 H 12.834 V 14.5 H 11.396 V 9.5 Z"/>
android:fillColor="#595757"
android:pathData="M 11.396 9.5 H 12.834 V 14.5 H 11.396 V 9.5 Z" />
</vector>

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="64.063"
android:viewportHeight="64">
android:width="24dp"
android:height="24dp"
android:viewportWidth="64.063"
android:viewportHeight="64">
<path
android:fillColor="#000000"
android:pathData="M54.054,49.348H24.72c-3.033,0-5.5-2.466-5.5-5.499V18.94l5.12,5.121c0.358,0.358,0.828,0.537,1.296,0.537 c0.469,0,0.938-0.179,1.297-0.537c0.715-0.716,0.715-1.877,0-2.592l-8.25-8.25c-0.716-0.716-1.876-0.716-2.592,0l-8.25,8.25 c-0.715,0.715-0.715,1.876,0,2.592c0.717,0.716,1.877,0.716,2.593,0l5.12-5.121v24.908c0,5.054,4.113,9.166,9.167,9.166h29.333 c1.014,0,1.833-0.819,1.833-1.833S55.067,49.348,54.054,49.348L54.054,49.348z"/>
android:fillColor="#000000"
android:pathData="M54.054,49.348H24.72c-3.033,0-5.5-2.466-5.5-5.499V18.94l5.12,5.121c0.358,0.358,0.828,0.537,1.296,0.537 c0.469,0,0.938-0.179,1.297-0.537c0.715-0.716,0.715-1.877,0-2.592l-8.25-8.25c-0.716-0.716-1.876-0.716-2.592,0l-8.25,8.25 c-0.715,0.715-0.715,1.876,0,2.592c0.717,0.716,1.877,0.716,2.593,0l5.12-5.121v24.908c0,5.054,4.113,9.166,9.167,9.166h29.333 c1.014,0,1.833-0.819,1.833-1.833S55.067,49.348,54.054,49.348L54.054,49.348z" />
</vector>

@ -1,29 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M15.923,11.848 C13.675,11.848,11.846,13.678,11.846,15.924 C11.846,18.172,13.675,20,15.923,20 S20,18.172,20,15.924 C20,13.678,18.171,11.848,15.923,11.848 Z M15.923,18.713 C14.385,18.713,13.133,17.461,13.133,15.924 C13.133,14.385,14.385,13.135,15.923,13.135 C17.461,13.135,18.713,14.385,18.713,15.924 C18.713,17.461,17.461,18.713,15.923,18.713 Z"/>
android:fillColor="#595757"
android:pathData="M15.923,11.848 C13.675,11.848,11.846,13.678,11.846,15.924 C11.846,18.172,13.675,20,15.923,20 S20,18.172,20,15.924 C20,13.678,18.171,11.848,15.923,11.848 Z M15.923,18.713 C14.385,18.713,13.133,17.461,13.133,15.924 C13.133,14.385,14.385,13.135,15.923,13.135 C17.461,13.135,18.713,14.385,18.713,15.924 C18.713,17.461,17.461,18.713,15.923,18.713 Z" />
<path
android:fillColor="#595757"
android:pathData="M16.567,13.961 L15.279,13.961 L15.279,16.568 L17.886,16.568 L17.886,15.279 L16.567,15.279 Z"/>
android:fillColor="#595757"
android:pathData="M16.567,13.961 L15.279,13.961 L15.279,16.568 L17.886,16.568 L17.886,15.279 L16.567,15.279 Z" />
<path
android:fillColor="#595757"
android:pathData="M5.287,5.623 C5.287,5.439,5.439,5.289,5.625,5.289 L16.412,5.289 C16.599,5.289,16.751,5.439,16.751,5.623 L16.751,11.019 L18.038,11.019 L18.038,5.623 C18.038,4.729,17.309,4,16.412,4 L5.625,4 C4.73,4,4,4.729,4,5.623 L4,18.375 C4,19.273,4.73,20,5.625,20 L11.018,20 L11.018,18.713 L5.625,18.713 C5.439,18.713,5.287,18.561,5.287,18.375 L5.287,18.039 L11.018,18.039 L11.018,16.752 L5.287,16.752 L5.287,5.623 Z"/>
android:fillColor="#595757"
android:pathData="M5.287,5.623 C5.287,5.439,5.439,5.289,5.625,5.289 L16.412,5.289 C16.599,5.289,16.751,5.439,16.751,5.623 L16.751,11.019 L18.038,11.019 L18.038,5.623 C18.038,4.729,17.309,4,16.412,4 L5.625,4 C4.73,4,4,4.729,4,5.623 L4,18.375 C4,19.273,4.73,20,5.625,20 L11.018,20 L11.018,18.713 L5.625,18.713 C5.439,18.713,5.287,18.561,5.287,18.375 L5.287,18.039 L11.018,18.039 L11.018,16.752 L5.287,16.752 L5.287,5.623 Z" />
<path
android:fillColor="#595757"
android:pathData="M5.96,6.115 L7.247,6.115 L7.247,7.095 L5.96,7.095 L5.96,6.115 Z"/>
android:fillColor="#595757"
android:pathData="M5.96,6.115 L7.247,6.115 L7.247,7.095 L5.96,7.095 L5.96,6.115 Z" />
<path
android:fillColor="#595757"
android:pathData="M14.788,6.115 L16.075,6.115 L16.075,7.095 L14.788,7.095 L14.788,6.115 Z"/>
android:fillColor="#595757"
android:pathData="M14.788,6.115 L16.075,6.115 L16.075,7.095 L14.788,7.095 L14.788,6.115 Z" />
<path
android:fillColor="#595757"
android:pathData="M5.96,14.943 L7.247,14.943 L7.247,15.923 L5.96,15.923 L5.96,14.943 Z"/>
android:fillColor="#595757"
android:pathData="M5.96,14.943 L7.247,14.943 L7.247,15.923 L5.96,15.923 L5.96,14.943 Z" />
<path
android:fillColor="#595757"
android:pathData="M11.474,11.475 L13.387,9.561 C13.65,9.987,13.809,10.483,13.809,11.02 L15.096,11.02 C15.096,10.127,14.799,9.308,14.311,8.636 L14.908,8.039 L13.997,7.131 L13.4,7.727 C12.728,7.24,11.909,6.944,11.018,6.944 C8.77,6.944,6.941,8.772,6.941,11.02 S8.77,15.096,11.018,15.096 L11.018,13.807 C9.48,13.807,8.228,12.557,8.228,11.02 C8.228,9.479,9.479,8.229,11.018,8.229 C11.554,8.229,12.05,8.388,12.476,8.651 L10.563,10.563 L11.474,11.475 Z"/>
android:fillColor="#595757"
android:pathData="M11.474,11.475 L13.387,9.561 C13.65,9.987,13.809,10.483,13.809,11.02 L15.096,11.02 C15.096,10.127,14.799,9.308,14.311,8.636 L14.908,8.039 L13.997,7.131 L13.4,7.727 C12.728,7.24,11.909,6.944,11.018,6.944 C8.77,6.944,6.941,8.772,6.941,11.02 S8.77,15.096,11.018,15.096 L11.018,13.807 C9.48,13.807,8.228,12.557,8.228,11.02 C8.228,9.479,9.479,8.229,11.018,8.229 C11.554,8.229,12.05,8.388,12.476,8.651 L10.563,10.563 L11.474,11.475 Z" />
</vector>

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="680.31"
android:viewportWidth="680.31">
android:width="24dp"
android:height="24dp"
android:viewportHeight="680.31"
android:viewportWidth="680.31">
<path
android:fillColor="#2C2C2C"
android:pathData="M339.865,79.038c-147.014,0-266.518,119.198-266.518,266.519 c0,147.011,119.198,266.519,266.518,266.519c147.013,0,266.52-119.201,266.52-266.519 C606.078,198.542,486.878,79.038,339.865,79.038L339.865,79.038z M339.865,587.929c-133.871,0-242.373-108.505-242.373-242.373 c0-133.872,108.502-242.066,242.373-242.066c133.868,0,242.372,108.5,242.372,242.373 C582.237,479.731,473.432,587.929,339.865,587.929L339.865,587.929z M339.865,587.929"/>
android:fillColor="#2C2C2C"
android:pathData="M339.865,79.038c-147.014,0-266.518,119.198-266.518,266.519 c0,147.011,119.198,266.519,266.518,266.519c147.013,0,266.52-119.201,266.52-266.519 C606.078,198.542,486.878,79.038,339.865,79.038L339.865,79.038z M339.865,587.929c-133.871,0-242.373-108.505-242.373-242.373 c0-133.872,108.502-242.066,242.373-242.066c133.868,0,242.372,108.5,242.372,242.373 C582.237,479.731,473.432,587.929,339.865,587.929L339.865,587.929z M339.865,587.929" />
<path
android:fillColor="#2C2C2C"
android:pathData="M305.329,491.346c20.782,0,28.118,33.619,28.118,33.619h12.836c0,0,7.337-33.619,28.12-33.619h133.869 c7.95,0,14.673-6.725,14.673-14.671V242.25c0-33.316-33.316-33.316-33.316-33.316H361.261c-10.697,0-21.396,13.449-21.396,20.479 c0-7.03-10.391-20.479-21.088-20.479H190.103c0,0-33.317,0-33.317,33.316v234.426c0,8.253,6.418,14.671,14.67,14.671H305.329z M348.117,236.75c0-6.115,4.89-11.31,11.005-11.31h139.065c3.973,0,7.336,3.361,7.336,7.64l0.607,235.647 c0,4.279-3.36,7.644-7.333,7.644H372.873c-14.06,0-24.756,15.589-24.756,15.589V236.75z M173.902,233.08 c0-4.279,3.364-7.64,7.336-7.64h139.066c6.112,0,11.003,4.891,11.003,11.31v254.903c0,0-11.003-15.589-24.759-15.589H180.627 c-3.974,0-7.337-3.36-7.337-7.639L173.902,233.08z M173.902,233.08"/>
android:fillColor="#2C2C2C"
android:pathData="M305.329,491.346c20.782,0,28.118,33.619,28.118,33.619h12.836c0,0,7.337-33.619,28.12-33.619h133.869 c7.95,0,14.673-6.725,14.673-14.671V242.25c0-33.316-33.316-33.316-33.316-33.316H361.261c-10.697,0-21.396,13.449-21.396,20.479 c0-7.03-10.391-20.479-21.088-20.479H190.103c0,0-33.317,0-33.317,33.316v234.426c0,8.253,6.418,14.671,14.67,14.671H305.329z M348.117,236.75c0-6.115,4.89-11.31,11.005-11.31h139.065c3.973,0,7.336,3.361,7.336,7.64l0.607,235.647 c0,4.279-3.36,7.644-7.333,7.644H372.873c-14.06,0-24.756,15.589-24.756,15.589V236.75z M173.902,233.08 c0-4.279,3.364-7.64,7.336-7.64h139.066c6.112,0,11.003,4.891,11.003,11.31v254.903c0,0-11.003-15.589-24.759-15.589H180.627 c-3.974,0-7.337-3.36-7.337-7.639L173.902,233.08z M173.902,233.08" />
</vector>

@ -1,15 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,12m-0.756,0a0.756,0.756 0,1 1,1.512 0a0.756,0.756 0,1 1,-1.512 0"
android:fillColor="#4A4B4A"/>
android:pathData="M12,12m-0.756,0a0.756,0.756 0,1 1,1.512 0a0.756,0.756 0,1 1,-1.512 0"
android:fillColor="#4A4B4A" />
<path
android:pathData="M7.038,16.963l6.94,-2.985l2.984,-6.939l-6.938,2.985L7.038,16.963zM14.195,9.804l-1.321,3.071l-3.069,1.322l1.321,-3.07L14.195,9.804z"
android:fillColor="#4A4B4A"/>
android:pathData="M7.038,16.963l6.94,-2.985l2.984,-6.939l-6.938,2.985L7.038,16.963zM14.195,9.804l-1.321,3.071l-3.069,1.322l1.321,-3.07L14.195,9.804z"
android:fillColor="#4A4B4A" />
<path
android:pathData="M12,3c-4.963,0 -9,4.037 -9,9s4.037,9 9,9s9,-4.037 9,-9S16.963,3 12,3zM12,19.419c-4.091,0 -7.419,-3.328 -7.419,-7.419S7.909,4.581 12,4.581S19.419,7.909 19.419,12S16.091,19.419 12,19.419z"
android:fillColor="#4A4B4A"/>
android:pathData="M12,3c-4.963,0 -9,4.037 -9,9s4.037,9 9,9s9,-4.037 9,-9S16.963,3 12,3zM12,19.419c-4.091,0 -7.419,-3.328 -7.419,-7.419S7.909,4.581 12,4.581S19.419,7.909 19.419,12S16.091,19.419 12,19.419z"
android:fillColor="#4A4B4A" />
</vector>

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M20,7.046 L4,7.046 L4,5.522 L20,5.522 L20,7.046 Z"/>
android:fillColor="#595757"
android:pathData="M20,7.046 L4,7.046 L4,5.522 L20,5.522 L20,7.046 Z" />
<path
android:fillColor="#595757"
android:pathData="M20,10.855 L4,10.855 L4,9.334 L20,9.334 L20,10.855 Z"/>
android:fillColor="#595757"
android:pathData="M20,10.855 L4,10.855 L4,9.334 L20,9.334 L20,10.855 Z" />
<path
android:fillColor="#595757"
android:pathData="M20,14.666 L4,14.666 L4,13.145 L20,13.145 L20,14.666 Z"/>
android:fillColor="#595757"
android:pathData="M20,14.666 L4,14.666 L4,13.145 L20,13.145 L20,14.666 Z" />
<path
android:fillColor="#595757"
android:pathData="M20,18.477 L4,18.477 L4,16.954 L20,16.954 L20,18.477 Z"/>
android:fillColor="#595757"
android:pathData="M20,18.477 L4,18.477 L4,16.954 L20,16.954 L20,18.477 Z" />
</vector>

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M5.938,4v16h1.414l4.648-2.789L16.649,20h1.411V4H5.938z M16.606,18.278l-4.605-2.763l-4.609,2.764 V5.454h9.215V18.278z"/>
android:fillColor="#595757"
android:pathData="M5.938,4v16h1.414l4.648-2.789L16.649,20h1.411V4H5.938z M16.606,18.278l-4.605-2.763l-4.609,2.764 V5.454h9.215V18.278z" />
</vector>

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M12,20 C7.59,20,4,16.412,4,12 S7.59,4,12,4 L12.848,4 L12.698,4.835 C12.693,4.862,12.221,7.656,13.793,9.529 C14.782,10.711,16.402,11.306,18.606,11.307 L18.606,11.307 C18.816,11.307,19.032,11.304,19.255,11.29 L20,11.256 L20,12 C20,16.412,16.411,20,12,20 Z M11.215,5.463 C7.955,5.854,5.418,8.635,5.418,12 C5.418,15.631,8.371,18.583,12,18.583 C15.384,18.583,18.18,16.015,18.543,12.727 C15.925,12.713,13.958,11.943,12.698,10.43 C11.305,8.762,11.165,6.641,11.215,5.463 Z"/>
android:fillColor="#595757"
android:pathData="M12,20 C7.59,20,4,16.412,4,12 S7.59,4,12,4 L12.848,4 L12.698,4.835 C12.693,4.862,12.221,7.656,13.793,9.529 C14.782,10.711,16.402,11.306,18.606,11.307 L18.606,11.307 C18.816,11.307,19.032,11.304,19.255,11.29 L20,11.256 L20,12 C20,16.412,16.411,20,12,20 Z M11.215,5.463 C7.955,5.854,5.418,8.635,5.418,12 C5.418,15.631,8.371,18.583,12,18.583 C15.384,18.583,18.18,16.015,18.543,12.727 C15.925,12.713,13.958,11.943,12.698,10.43 C11.305,8.762,11.165,6.641,11.215,5.463 Z" />
</vector>

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M12,4c-4.412,0-8,3.588-8,8s3.588,8,8,8c4.41,0,8-3.588,8-8S16.41,4,12,4z M12,18.545 c-3.608,0-6.546-2.936-6.546-6.545S8.392,5.455,12,5.455c3.607,0,6.545,2.936,6.545,6.545S15.607,18.545,12,18.545z"/>
android:fillColor="#595757"
android:pathData="M12,4c-4.412,0-8,3.588-8,8s3.588,8,8,8c4.41,0,8-3.588,8-8S16.41,4,12,4z M12,18.545 c-3.608,0-6.546-2.936-6.546-6.545S8.392,5.455,12,5.455c3.607,0,6.545,2.936,6.545,6.545S15.607,18.545,12,18.545z" />
<path
android:fillColor="#595757"
android:pathData="M 13.426 9.546 L 12.002 10.972 L 10.576 9.546 L 9.547 10.575 L 10.973 12 L 9.547 13.425 L 10.576 14.454 L 12.002 13.028 L 13.426 14.454 L 14.454 13.425 L 13.029 12 L 14.454 10.575 Z"/>
android:fillColor="#595757"
android:pathData="M 13.426 9.546 L 12.002 10.972 L 10.576 9.546 L 9.547 10.575 L 10.973 12 L 9.547 13.425 L 10.576 14.454 L 12.002 13.028 L 13.426 14.454 L 14.454 13.425 L 13.029 12 L 14.454 10.575 Z" />
</vector>

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M20,7.046H4V5.522h16V7.046z"/>
android:fillColor="#595757"
android:pathData="M20,7.046H4V5.522h16V7.046z" />
<path
android:fillColor="#595757"
android:pathData="M20,10.855H4V9.334h16V10.855z"/>
android:fillColor="#595757"
android:pathData="M20,10.855H4V9.334h16V10.855z" />
<path
android:fillColor="#595757"
android:pathData="M20,14.666H4v-1.521h16V14.666z"/>
android:fillColor="#595757"
android:pathData="M20,14.666H4v-1.521h16V14.666z" />
<path
android:fillColor="#595757"
android:pathData="M20,18.477H4v-1.523h16V18.477z"/>
android:fillColor="#595757"
android:pathData="M20,18.477H4v-1.523h16V18.477z" />
</vector>

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
android:fillColor="#FF000000"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" />
</vector>

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M20,6.182h-1.454v1.249C17.067,5.315,14.646,4,12,4c-4.412,0-8,3.589-8,8s3.588,8,8,8 c3.789,0,7.086-2.691,7.84-6.401l-1.426-0.289C17.798,16.344,15.1,18.546,12,18.546c-3.608,0-6.546-2.937-6.546-6.546 S8.392,5.454,12,5.454c2.399,0,4.576,1.32,5.721,3.395h-1.842v1.454H20V6.182z"/>
android:fillColor="#595757"
android:pathData="M20,6.182h-1.454v1.249C17.067,5.315,14.646,4,12,4c-4.412,0-8,3.589-8,8s3.588,8,8,8 c3.789,0,7.086-2.691,7.84-6.401l-1.426-0.289C17.798,16.344,15.1,18.546,12,18.546c-3.608,0-6.546-2.937-6.546-6.546 S8.392,5.454,12,5.454c2.399,0,4.576,1.32,5.721,3.395h-1.842v1.454H20V6.182z" />
<path
android:fillColor="#595757"
android:pathData="M11.273,8.363c-1.604,0-2.909,1.305-2.909,2.91c0,1.604,1.305,2.909,2.909,2.909 c0.537,0,1.035-0.157,1.468-0.412l2.14,2.139l1.027-1.029l-2.139-2.139c0.256-0.432,0.412-0.93,0.412-1.468 C14.182,9.668,12.877,8.363,11.273,8.363z M9.818,11.273c0-0.802,0.652-1.455,1.455-1.455c0.801,0,1.453,0.653,1.453,1.455 c0,0.801-0.652,1.454-1.453,1.454C10.471,12.727,9.818,12.074,9.818,11.273z"/>
android:fillColor="#595757"
android:pathData="M11.273,8.363c-1.604,0-2.909,1.305-2.909,2.91c0,1.604,1.305,2.909,2.909,2.909 c0.537,0,1.035-0.157,1.468-0.412l2.14,2.139l1.027-1.029l-2.139-2.139c0.256-0.432,0.412-0.93,0.412-1.468 C14.182,9.668,12.877,8.363,11.273,8.363z M9.818,11.273c0-0.802,0.652-1.455,1.455-1.455c0.801,0,1.453,0.653,1.453,1.455 c0,0.801-0.652,1.454-1.453,1.454C10.471,12.727,9.818,12.074,9.818,11.273z" />
</vector>

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M 18.303 8.091 L 14.939 8.091 L 14.939 4.727 L 15.848 4.727 L 15.848 7.182 L 18.303 7.182 Z"/>
android:fillColor="#595757"
android:pathData="M 18.303 8.091 L 14.939 8.091 L 14.939 4.727 L 15.848 4.727 L 15.848 7.182 L 18.303 7.182 Z" />
<path
android:fillColor="#595757"
android:pathData="M19.03,18.061H6.91V4h8.785l3.335,3.335V18.061z M8.363,16.606h9.213V7.938l-2.483-2.484H8.363 V16.606z"/>
android:fillColor="#595757"
android:pathData="M19.03,18.061H6.91V4h8.785l3.335,3.335V18.061z M8.363,16.606h9.213V7.938l-2.483-2.484H8.363 V16.606z" />
<path
android:fillColor="#595757"
android:pathData="M 17.09 20 L 4.969 20 L 4.969 5.939 L 7.636 5.939 L 7.636 7.394 L 6.424 7.394 L 6.424 18.546 L 15.636 18.546 L 15.636 17.333 L 17.09 17.333 Z"/>
android:fillColor="#595757"
android:pathData="M 17.09 20 L 4.969 20 L 4.969 5.939 L 7.636 5.939 L 7.636 7.394 L 6.424 7.394 L 6.424 18.546 L 15.636 18.546 L 15.636 17.333 L 17.09 17.333 Z" />
</vector>

@ -1,35 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M16.638,8.494l1.585-1.586l-1.132-1.131l-1.585,1.586C15.933,7.687,16.313,8.066,16.638,8.494z"/>
android:fillColor="#595757"
android:pathData="M16.638,8.494l1.585-1.586l-1.132-1.131l-1.585,1.586C15.933,7.687,16.313,8.066,16.638,8.494z" />
<path
android:fillColor="#595757"
android:pathData="M8.495,7.363L6.909,5.777L5.778,6.909l1.584,1.585C7.687,8.067,8.067,7.687,8.495,7.363z"/>
android:fillColor="#595757"
android:pathData="M8.495,7.363L6.909,5.777L5.778,6.909l1.584,1.585C7.687,8.067,8.067,7.687,8.495,7.363z" />
<path
android:fillColor="#595757"
android:pathData="M12.001,6.181c0.271,0,0.537,0.025,0.799,0.062V4h-1.6v2.242 C11.462,6.206,11.728,6.181,12.001,6.181z"/>
android:fillColor="#595757"
android:pathData="M12.001,6.181c0.271,0,0.537,0.025,0.799,0.062V4h-1.6v2.242 C11.462,6.206,11.728,6.181,12.001,6.181z" />
<path
android:fillColor="#595757"
android:pathData="M6.181,12c0-0.271,0.025-0.537,0.062-0.8H4v1.6h2.242C6.206,12.538,6.181,12.272,6.181,12z"/>
android:fillColor="#595757"
android:pathData="M6.181,12c0-0.271,0.025-0.537,0.062-0.8H4v1.6h2.242C6.206,12.538,6.181,12.272,6.181,12z" />
<path
android:fillColor="#595757"
android:pathData="M15.506,16.638l1.585,1.585l1.131-1.131l-1.584-1.586C16.313,15.934,15.933,16.313,15.506,16.638z"/>
android:fillColor="#595757"
android:pathData="M15.506,16.638l1.585,1.585l1.131-1.131l-1.584-1.586C16.313,15.934,15.933,16.313,15.506,16.638z" />
<path
android:fillColor="#595757"
android:pathData="M17.759,11.2c0.035,0.263,0.061,0.528,0.061,0.8c0,0.272-0.025,0.538-0.061,0.8H20v-1.6H17.759z"/>
android:fillColor="#595757"
android:pathData="M17.759,11.2c0.035,0.263,0.061,0.528,0.061,0.8c0,0.272-0.025,0.538-0.061,0.8H20v-1.6H17.759z" />
<path
android:fillColor="#595757"
android:pathData="M7.363,15.506l-1.585,1.586l1.131,1.131l1.585-1.586C8.067,16.313,7.687,15.934,7.363,15.506z"/>
android:fillColor="#595757"
android:pathData="M7.363,15.506l-1.585,1.586l1.131,1.131l1.585-1.586C8.067,16.313,7.687,15.934,7.363,15.506z" />
<path
android:fillColor="#595757"
android:pathData="M12.001,17.819c-0.273,0-0.539-0.024-0.801-0.062V20h1.6v-2.242 C12.538,17.795,12.272,17.819,12.001,17.819z"/>
android:fillColor="#595757"
android:pathData="M12.001,17.819c-0.273,0-0.539-0.024-0.801-0.062V20h1.6v-2.242 C12.538,17.795,12.272,17.819,12.001,17.819z" />
<path
android:fillColor="#595757"
android:pathData="M12,16.6c-2.536,0-4.6-2.063-4.6-4.6S9.464,7.4,12,7.4s4.6,2.063,4.6,4.6S14.536,16.6,12,16.6z M12,9 c-1.654,0-3,1.346-3,3s1.346,3,3,3s3-1.346,3-3S13.654,9,12,9z"/>
android:fillColor="#595757"
android:pathData="M12,16.6c-2.536,0-4.6-2.063-4.6-4.6S9.464,7.4,12,7.4s4.6,2.063,4.6,4.6S14.536,16.6,12,16.6z M12,9 c-1.654,0-3,1.346-3,3s1.346,3,3,3s3-1.346,3-3S13.654,9,12,9z" />
</vector>

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M11.999,4c-4.411,0-8,3.588-8,8s3.589,8,8,8c4.41,0,8-3.588,8-8S16.409,4,11.999,4z M11.999,18.546 c-3.609,0-6.547-2.937-6.547-6.546s2.938-6.546,6.547-6.546S18.544,8.391,18.544,12S15.608,18.546,11.999,18.546z"/>
android:fillColor="#595757"
android:pathData="M11.999,4c-4.411,0-8,3.588-8,8s3.589,8,8,8c4.41,0,8-3.588,8-8S16.409,4,11.999,4z M11.999,18.546 c-3.609,0-6.547-2.937-6.547-6.546s2.938-6.546,6.547-6.546S18.544,8.391,18.544,12S15.608,18.546,11.999,18.546z" />
<path
android:fillColor="#595757"
android:pathData="M 12.727 10.546 L 11.271 10.546 L 11.271 14.667 L 11.028 14.667 L 11.028 16.121 L 12.969 16.121 L 12.969 14.667 L 12.727 14.667 Z"/>
android:fillColor="#595757"
android:pathData="M 12.727 10.546 L 11.271 10.546 L 11.271 14.667 L 11.028 14.667 L 11.028 16.121 L 12.969 16.121 L 12.969 14.667 L 12.727 14.667 Z" />
<path
android:fillColor="#595757"
android:pathData="M 11.271 8.121 H 12.727 V 9.091 H 11.271 V 8.121 Z"/>
android:fillColor="#595757"
android:pathData="M 11.271 8.121 H 12.727 V 9.091 H 11.271 V 8.121 Z" />
</vector>

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M15.045,19.68 L8.955,19.68 C7.274,19.68,5.854,18.367,5.726,16.696 L5.322,11.43 L4,11.43 L4,7.492 L6.722,7.492 C6.603,7.211,6.541,6.913,6.541,6.602 C6.541,5.344,7.567,4.321,8.826,4.321 C9.935,4.321,10.678,4.755,11.391,5.82 C11.481,5.956,11.683,6.285,12.001,6.82 C12.319,6.285,12.521,5.956,12.609,5.821 C13.322,4.755,14.066,4.321,15.175,4.321 C16.434,4.321,17.46,5.344,17.46,6.602 C17.46,6.914,17.397,7.211,17.279,7.493 L20,7.493 L20,11.431 L18.678,11.431 L18.273,16.697 C18.145,18.367,16.726,19.68,15.045,19.68 Z M12.698,18.287 L15.045,18.287 C16.002,18.287,16.808,17.539,16.88,16.586 L17.276,11.43 L12.698,11.43 L12.698,18.287 Z M6.723,11.43 L7.12,16.586 C7.191,17.539,7.998,18.287,8.955,18.287 L11.301,18.287 L11.301,11.43 L6.723,11.43 Z M12.698,10.033 L18.603,10.033 L18.603,8.89 L12.698,8.89 L12.698,10.033 Z M5.397,10.033 L11.301,10.033 L11.301,8.89 L5.397,8.89 L5.397,10.033 Z M13.224,7.492 L15.175,7.492 C15.665,7.492,16.065,7.094,16.065,6.601 C16.065,6.114,15.666,5.712,15.175,5.712 C14.609,5.712,14.272,5.84,13.772,6.593 C13.683,6.727,13.454,7.105,13.224,7.492 Z M8.825,5.713 C8.335,5.713,7.935,6.114,7.935,6.602 C7.935,7.094,8.334,7.493,8.825,7.493 L10.776,7.493 C10.546,7.106,10.318,6.727,10.23,6.597 C9.728,5.841,9.392,5.713,8.825,5.713 Z"/>
android:fillColor="#595757"
android:pathData="M15.045,19.68 L8.955,19.68 C7.274,19.68,5.854,18.367,5.726,16.696 L5.322,11.43 L4,11.43 L4,7.492 L6.722,7.492 C6.603,7.211,6.541,6.913,6.541,6.602 C6.541,5.344,7.567,4.321,8.826,4.321 C9.935,4.321,10.678,4.755,11.391,5.82 C11.481,5.956,11.683,6.285,12.001,6.82 C12.319,6.285,12.521,5.956,12.609,5.821 C13.322,4.755,14.066,4.321,15.175,4.321 C16.434,4.321,17.46,5.344,17.46,6.602 C17.46,6.914,17.397,7.211,17.279,7.493 L20,7.493 L20,11.431 L18.678,11.431 L18.273,16.697 C18.145,18.367,16.726,19.68,15.045,19.68 Z M12.698,18.287 L15.045,18.287 C16.002,18.287,16.808,17.539,16.88,16.586 L17.276,11.43 L12.698,11.43 L12.698,18.287 Z M6.723,11.43 L7.12,16.586 C7.191,17.539,7.998,18.287,8.955,18.287 L11.301,18.287 L11.301,11.43 L6.723,11.43 Z M12.698,10.033 L18.603,10.033 L18.603,8.89 L12.698,8.89 L12.698,10.033 Z M5.397,10.033 L11.301,10.033 L11.301,8.89 L5.397,8.89 L5.397,10.033 Z M13.224,7.492 L15.175,7.492 C15.665,7.492,16.065,7.094,16.065,6.601 C16.065,6.114,15.666,5.712,15.175,5.712 C14.609,5.712,14.272,5.84,13.772,6.593 C13.683,6.727,13.454,7.105,13.224,7.492 Z M8.825,5.713 C8.335,5.713,7.935,6.114,7.935,6.602 C7.935,7.094,8.334,7.493,8.825,7.493 L10.776,7.493 C10.546,7.106,10.318,6.727,10.23,6.597 C9.728,5.841,9.392,5.713,8.825,5.713 Z" />
</vector>

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
android:fillColor="#FFFFFFFF"
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z" />
</vector>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save