Merge remote-tracking branch 'origin/master'

# Conflicts:
#	app/src/main/res/layout/fragment_bookshelf.xml
pull/32/head
Invinciblelee 6 years ago
commit fe05789ebc
  1. 7
      app/build.gradle
  2. 2
      app/src/main/AndroidManifest.xml
  3. 2
      app/src/main/java/io/legado/app/base/BaseActivity.kt
  4. 6
      app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt
  5. 6
      app/src/main/java/io/legado/app/data/entities/BaseBook.kt
  6. 23
      app/src/main/java/io/legado/app/data/entities/Book.kt
  7. 30
      app/src/main/java/io/legado/app/help/AdapterDataObserverProxy.kt
  8. 2
      app/src/main/java/io/legado/app/help/storage/Restore.kt
  9. 24
      app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt
  10. 11
      app/src/main/java/io/legado/app/ui/bookshelf/BookshelfViewModel.kt
  11. 14
      app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt
  12. 7
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  13. 33
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt
  14. 38
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt
  15. 52
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt
  16. 6
      app/src/main/java/io/legado/app/ui/main/booksource/BookSourceFragment.kt
  17. 8
      app/src/main/java/io/legado/app/ui/main/myconfig/PreferenceFragment.kt
  18. 112
      app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt
  19. 5
      app/src/main/java/io/legado/app/utils/AlertDialogExtensions.kt
  20. 232
      app/src/main/java/io/legado/app/utils/FileUtils.kt
  21. 5
      app/src/main/java/io/legado/app/utils/GsonExtensions.kt
  22. 20
      app/src/main/java/io/legado/app/utils/ViewExtensions.kt
  23. 9
      app/src/main/res/drawable/ic_explore_black_24dp.xml
  24. 9
      app/src/main/res/drawable/ic_library_books_black_24dp.xml
  25. 9
      app/src/main/res/drawable/ic_person_black_24dp.xml
  26. 9
      app/src/main/res/drawable/ic_storage_black_24dp.xml
  27. 18
      app/src/main/res/layout/activity_about.xml
  28. 12
      app/src/main/res/layout/activity_bookshelf.xml
  29. 80
      app/src/main/res/layout/activity_qrcode_capture.xml
  30. 39
      app/src/main/res/layout/dialog_input.xml
  31. 25
      app/src/main/res/layout/fragment_bookshelf.xml
  32. 7
      app/src/main/res/layout/item_book_group.xml
  33. 7
      app/src/main/res/layout/item_bookshelf_list_add.xml
  34. 24
      app/src/main/res/menu/activity_main_bnv.xml
  35. 2
      app/src/main/res/menu/book_source.xml
  36. 10
      app/src/main/res/menu/qr_code_scan.xml
  37. 2
      app/src/main/res/values-night/colors.xml
  38. 6
      app/src/main/res/values/colors.xml
  39. 2
      app/src/main/res/values/strings.xml
  40. 8
      app/src/main/res/values/styles.xml
  41. 2
      app/src/main/res/xml/pref_config_theme.xml
  42. 65
      app/src/main/res/xml/pref_main.xml

@ -126,7 +126,14 @@ dependencies {
//Glide
implementation 'com.github.bumptech.glide:glide:4.9.0'
//
implementation 'cn.bingoogolapple:bga-qrcode-zxing:1.3.6'
//
implementation 'com.jaredrummler:colorpicker:1.1.0'
//
implementation 'com.afollestad.material-dialogs:core:3.0.0-rc3'
implementation 'com.afollestad.material-dialogs:input:3.0.0-rc3'
implementation 'com.afollestad.material-dialogs:files:3.0.0-rc3'
}

@ -43,6 +43,8 @@
android:theme="@style/Activity.Permission"/>
<activity android:name=".ui.config.ConfigActivity"/>
<activity android:name=".ui.sourceedit.SourceEditActivity"/>
<activity android:name=".ui.bookshelf.BookshelfActivity" />
<activity android:name=".ui.qrcode.QrCodeActivity" />
</application>
</manifest>

@ -11,6 +11,7 @@ import androidx.lifecycle.ViewModel
import io.legado.app.R
import io.legado.app.lib.theme.ColorUtils
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.utils.disableAutoFill
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.setIconColor
@ -23,6 +24,7 @@ abstract class BaseActivity<VM : ViewModel> : AppCompatActivity() {
protected abstract val layoutID: Int
override fun onCreate(savedInstanceState: Bundle?) {
window.decorView.disableAutoFill()
initTheme()
setupSystemBar()
super.onCreate(savedInstanceState)

@ -2,6 +2,8 @@ package io.legado.app.data.dao
import androidx.paging.DataSource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import io.legado.app.data.entities.BookGroup
@ -11,5 +13,9 @@ interface BookGroupDao {
@Query("SELECT * FROM book_groups ORDER BY `order`")
fun observeAll(): DataSource.Factory<Int, BookGroup>
@get:Query("SELECT MAX(groupId) FROM book_groups")
val maxId: Int
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(bookGroup: BookGroup)
}

@ -0,0 +1,6 @@
package io.legado.app.data.entities
interface BaseBook {
var variableMap: HashMap<String, String>?
fun putVariable(key: String, value: String)
}

@ -1,10 +1,15 @@
package io.legado.app.data.entities
import android.os.Parcelable
import android.text.TextUtils.isEmpty
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import com.google.gson.Gson
import io.legado.app.constant.AppConst.NOT_AVAILABLE
import io.legado.app.utils.fromJson
import kotlinx.android.parcel.IgnoredOnParcel
import kotlinx.android.parcel.Parcelize
@Parcelize
@ -40,7 +45,10 @@ data class Book(
var order: Int = 0, // 手动排序
var useReplaceRule: Boolean = true, // 正文使用净化替换规则
var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息)
) : Parcelable {
) : Parcelable, BaseBook {
@IgnoredOnParcel
@Ignore
override var variableMap: HashMap<String, String>? = null
fun getUnreadChapterNum() = Math.max(totalChapterNum - durChapterIndex - 1, 0)
@ -52,4 +60,17 @@ data class Book(
fun getDisplayDescription() = customDescription ?: description
private fun initVariableMap() {
if (variableMap == null) {
variableMap = if (isEmpty(variable)) {
HashMap()
} else {
Gson().fromJson<HashMap<String, String>>(variable!!)
}
}
}
override fun putVariable(key: String, value: String) {
initVariableMap()
}
}

@ -0,0 +1,30 @@
package io.legado.app.help
import androidx.recyclerview.widget.RecyclerView
internal class AdapterDataObserverProxy(var adapterDataObserver: RecyclerView.AdapterDataObserver, var headerCount: Int) : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
adapterDataObserver.onChanged()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
adapterDataObserver.onItemRangeChanged(positionStart + headerCount, itemCount)
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
adapterDataObserver.onItemRangeChanged(positionStart + headerCount, itemCount, payload)
}
// 当第n个数据被获取,更新第n+1个position
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
adapterDataObserver.onItemRangeInserted(positionStart + headerCount, itemCount)
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
adapterDataObserver.onItemRangeRemoved(positionStart + headerCount, itemCount)
}
override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
super.onItemRangeMoved(fromPosition + headerCount, toPosition + headerCount, itemCount)
}
}

@ -26,7 +26,7 @@ object Restore {
}
fun importYueDuData(context: Context) {
val yuedu = File(getSdPath(), "YueDu")
val yuedu = File(FileUtils.getSdPath(), "YueDu")
val jsonPath = JsonPath.using(
Configuration.builder()
.options(Option.SUPPRESS_EXCEPTIONS)

@ -0,0 +1,24 @@
package io.legado.app.ui.bookshelf
import android.os.Bundle
import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_bookshelf.*
class BookshelfActivity : BaseActivity<BookshelfViewModel>() {
override val viewModel: BookshelfViewModel
get() = getViewModel(BookshelfViewModel::class.java)
override val layoutID: Int
get() = R.layout.activity_bookshelf
override fun onViewModelCreated(viewModel: BookshelfViewModel, savedInstanceState: Bundle?) {
if (viewModel.bookGroup == null) {
viewModel.bookGroup = intent.getParcelableExtra("data")
}
viewModel.bookGroup?.let {
title_bar.title = it.groupName
}
}
}

@ -0,0 +1,11 @@
package io.legado.app.ui.bookshelf
import android.app.Application
import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.BookGroup
class BookshelfViewModel(application: Application) : BaseViewModel(application) {
var bookGroup: BookGroup? = null
}

@ -54,7 +54,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
upTheme(false)
}
.setNegativeButton(R.string.cancel) { _, _ -> upTheme(false) }
.show().upTint
.show().upTint()
}
} else {
upTheme(false)
@ -74,7 +74,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
upTheme(true)
}
.setNegativeButton(R.string.cancel) { _, _ -> upTheme(true) }
.show().upTint
.show().upTint()
}
} else {
upTheme(true)
@ -93,11 +93,11 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
.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("colorPrimary", App.INSTANCE.getCompatColor(R.color.colorPrimary))
.putInt("colorAccent", App.INSTANCE.getCompatColor(R.color.colorAccent))
.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("colorPrimaryNight", App.INSTANCE.getCompatColor(R.color.colorPrimary))
.putInt("colorAccentNight", App.INSTANCE.getCompatColor(R.color.colorAccent))
.putInt("colorBackgroundNight", App.INSTANCE.getCompatColor(R.color.md_grey_800))
.apply()
App.INSTANCE.upThemeStore()
@ -105,7 +105,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar
Handler().postDelayed({ activity?.recreate() }, 100)
}
.setNegativeButton(R.string.cancel, null)
.show().upTint
.show().upTint()
}
}
}

@ -15,11 +15,13 @@ 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.Selector
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
import io.legado.app.ui.main.myconfig.MyConfigFragment
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_main.*
@ -34,6 +36,11 @@ class MainActivity : BaseActivity<MainViewModel>(), BottomNavigationView.OnNavig
override fun onViewModelCreated(viewModel: MainViewModel, savedInstanceState: Bundle?) {
bottom_navigation_view.setBackgroundColor(ThemeStore.backgroundColor(this))
val colorStateList = Selector.colorBuild()
.setDefaultColor(bottom_navigation_view.context.getCompatColor(R.color.btn_bg_press_tp))
.setSelectedColor(ThemeStore.primaryColor(bottom_navigation_view.context)).create()
bottom_navigation_view.itemIconTintList = colorStateList
bottom_navigation_view.itemTextColor = colorStateList
view_pager_main.offscreenPageLimit = 3
view_pager_main.adapter = TabFragmentPageAdapter(supportFragmentManager)
view_pager_main.addOnPageChangeListener(this)

@ -8,6 +8,8 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.R
import io.legado.app.data.entities.BookGroup
import io.legado.app.help.AdapterDataObserverProxy
import kotlinx.android.synthetic.main.item_book_group.view.*
class BookGroupAdapter : PagedListAdapter<BookGroup, BookGroupAdapter.MyViewHolder>(DIFF_CALLBACK) {
@ -24,15 +26,44 @@ class BookGroupAdapter : PagedListAdapter<BookGroup, BookGroupAdapter.MyViewHold
}
}
var callBack: CallBack? = null
private val defaultGroups = arrayOf(BookGroup(-1, "全部"),
BookGroup(-2, "本地"),
BookGroup(-3, "音频"))
private val addBookGroup = BookGroup(-10, "+")
override fun getItemCount(): Int {
return super.getItemCount() + defaultGroups.size + 1
}
override fun registerAdapterDataObserver(observer: RecyclerView.AdapterDataObserver) {
super.registerAdapterDataObserver(AdapterDataObserverProxy(observer, defaultGroups.size))
}
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) {
when {
position < defaultGroups.size -> holder.bind(defaultGroups[position], callBack)
position == itemCount - 1 -> holder.bind(addBookGroup, callBack)
else -> currentList?.get(position - defaultGroups.size)?.let {
holder.bind(it, callBack)
}
}
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(bookGroup: BookGroup, callBack: CallBack?) = with(itemView) {
tv_group.text = bookGroup.groupName
tv_group.setOnClickListener { callBack?.open(bookGroup) }
}
}
interface CallBack {
fun open(bookGroup: BookGroup)
}
}

@ -16,7 +16,7 @@ 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) {
class BookshelfAdapter : PagedListAdapter<Book, RecyclerView.ViewHolder>(DIFF_CALLBACK) {
companion object {
@JvmField
@ -33,13 +33,40 @@ class BookshelfAdapter : PagedListAdapter<Book, BookshelfAdapter.MyViewHolder>(D
var callBack: CallBack? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
override fun getItemViewType(position: Int): Int {
if (position == itemCount - 1) {
return 1
}
return super.getItemViewType(position)
}
override fun getItemCount(): Int {
return super.getItemCount() + 1
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (viewType == 1) {
return AddViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_bookshelf_list_add, parent, false))
}
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)
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is MyViewHolder -> {
currentList?.get(position)?.let {
holder.bind(it, callBack)
}
}
is AddViewHolder -> holder.bind(callBack)
}
}
class AddViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(callBack: CallBack?) = with(itemView) {
setOnClickListener { callBack?.search() }
}
}
@ -76,5 +103,6 @@ class BookshelfAdapter : PagedListAdapter<Book, BookshelfAdapter.MyViewHolder>(D
interface CallBack {
fun open(book: Book)
fun search()
}
}

@ -7,16 +7,26 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.input.input
import io.legado.app.App
import io.legado.app.R
import io.legado.app.base.BaseFragment
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookGroup
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.ui.bookshelf.BookshelfActivity
import io.legado.app.utils.disableAutoFill
import kotlinx.android.synthetic.main.fragment_bookshelf.*
import kotlinx.android.synthetic.main.view_title_bar.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jetbrains.anko.startActivity
import org.jetbrains.anko.textColor
class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf) {
class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf), BookGroupAdapter.CallBack {
private lateinit var bookshelfAdapter: BookshelfAdapter
private lateinit var bookGroupAdapter: BookGroupAdapter
@ -25,6 +35,7 @@ class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setSupportToolbar(toolbar)
initSearchView()
initRecyclerView()
initBookGroupData()
initBookshelfData()
@ -34,11 +45,25 @@ class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf) {
menuInflater.inflate(R.menu.bookshelf, menu)
}
private fun initSearchView() {
search_view.visibility = View.VISIBLE
search_view.onActionViewExpanded()
search_view.queryHint = getString(R.string.search_book_key)
search_view.clearFocus()
}
private fun initRecyclerView() {
refresh_layout.setColorSchemeColors(ThemeStore.accentColor(refresh_layout.context))
refresh_layout.setOnRefreshListener {
refresh_layout.isRefreshing = false
}
tv_recent_reading.textColor = ThemeStore.accentColor(tv_recent_reading.context)
rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
bookGroupAdapter = BookGroupAdapter()
rv_book_group.adapter = bookGroupAdapter
bookGroupAdapter.callBack = this
rv_bookshelf.layoutManager = LinearLayoutManager(context)
rv_bookshelf.addItemDecoration(DividerItemDecoration(rv_bookshelf.context, LinearLayoutManager.VERTICAL))
bookshelfAdapter = BookshelfAdapter()
rv_bookshelf.adapter = bookshelfAdapter
}
@ -55,4 +80,29 @@ class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf) {
bookshelfLiveData?.observe(viewLifecycleOwner, Observer { bookshelfAdapter.submitList(it) })
}
override fun open(bookGroup: BookGroup) {
when (bookGroup.groupId) {
-10 -> context?.let {
MaterialDialog(it).show {
window?.decorView?.disableAutoFill()
title(text = "新建分组")
input(hint = "分组名称") { _, charSequence ->
run {
GlobalScope.launch {
App.db.bookGroupDao().insert(
BookGroup(
App.db.bookGroupDao().maxId + 1,
charSequence.toString()
)
)
}
}
}
positiveButton(R.string.ok)
}
}
else -> context?.startActivity<BookshelfActivity>(Pair("data", bookGroup))
}
}
}

@ -17,6 +17,7 @@ import io.legado.app.R
import io.legado.app.base.BaseFragment
import io.legado.app.data.entities.BookSource
import io.legado.app.help.ItemTouchCallback
import io.legado.app.ui.qrcode.QrCodeActivity
import io.legado.app.ui.sourceedit.SourceEditActivity
import kotlinx.android.synthetic.main.fragment_book_source.*
import kotlinx.android.synthetic.main.view_title_bar.*
@ -46,6 +47,9 @@ class BookSourceFragment : BaseFragment(R.layout.fragment_book_source), BookSour
R.id.action_add_book_source -> {
context?.startActivity<SourceEditActivity>()
}
R.id.action_import_book_source_qr -> {
context?.startActivity<QrCodeActivity>()
}
}
}
@ -101,6 +105,6 @@ class BookSourceFragment : BaseFragment(R.layout.fragment_book_source), BookSour
}
override fun edit(bookSource: BookSource) {
context?.let { it.startActivity<SourceEditActivity>(Pair("data", bookSource.origin)) }
context?.startActivity<SourceEditActivity>(Pair("data", bookSource.origin))
}
}

@ -6,6 +6,7 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import io.legado.app.App
import io.legado.app.R
import io.legado.app.ui.about.AboutActivity
import io.legado.app.ui.config.ConfigActivity
import io.legado.app.ui.config.ConfigViewModel
import org.jetbrains.anko.startActivity
@ -39,19 +40,20 @@ class PreferenceFragment : PreferenceFragmentCompat(), SharedPreferences.OnShare
when (preference.key) {
"setting" -> {
requireContext().startActivity<ConfigActivity>(
Pair("configType", ConfigViewModel.TYPE_CONFIG)
Pair("configType", ConfigViewModel.TYPE_CONFIG)
)
}
"web_dav_setting" -> {
requireContext().startActivity<ConfigActivity>(
Pair("configType", ConfigViewModel.TYPE_WEB_DAV_CONFIG)
Pair("configType", ConfigViewModel.TYPE_WEB_DAV_CONFIG)
)
}
"theme_setting" -> {
requireContext().startActivity<ConfigActivity>(
Pair("configType", ConfigViewModel.TYPE_THEME_CONFIG)
Pair("configType", ConfigViewModel.TYPE_THEME_CONFIG)
)
}
"about" -> requireContext().startActivity<AboutActivity>()
}
}
return super.onPreferenceTreeClick(preference)

@ -0,0 +1,112 @@
package io.legado.app.ui.qrcode
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.lifecycle.AndroidViewModel
import cn.bingoogolapple.qrcode.core.QRCodeView
import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.utils.FileUtils
import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_qrcode_capture.*
import kotlinx.android.synthetic.main.view_title_bar.*
class QrCodeActivity : BaseActivity<AndroidViewModel>(), QRCodeView.Delegate {
override val viewModel: AndroidViewModel
get() = getViewModel(AndroidViewModel::class.java)
override val layoutID: Int
get() = R.layout.activity_qrcode_capture
private val requestQrImage = 202
private var flashlightIsOpen: Boolean = false
override fun onViewModelCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) {
setSupportActionBar(toolbar)
zxingview.setDelegate(this)
fab_flashlight.setOnClickListener {
if (flashlightIsOpen) {
flashlightIsOpen = false
zxingview.closeFlashlight()
} else {
flashlightIsOpen = true
zxingview.openFlashlight()
}
}
}
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.qr_code_scan, menu)
return super.onCompatCreateOptionsMenu(menu)
}
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_choose_from_gallery -> {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, requestQrImage)
}
}
return super.onCompatOptionsItemSelected(item)
}
override fun onStart() {
super.onStart()
startCamera()
}
private fun startCamera() {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.CAMERA)
.rationale(R.string.qr_per)
.onGranted {
zxingview.startCamera() // 打开后置摄像头开始预览,但是并未开始识别
zxingview.startSpotAndShowRect() // 显示扫描框,并开始识别
}.request()
}
override fun onStop() {
zxingview.stopCamera() // 关闭摄像头预览,并且隐藏扫描框
super.onStop()
}
override fun onDestroy() {
zxingview.onDestroy() // 销毁二维码扫描控件
super.onDestroy()
}
override fun onScanQRCodeSuccess(result: String) {
val intent = Intent()
intent.putExtra("result", result)
setResult(RESULT_OK, intent)
finish()
}
override fun onCameraAmbientBrightnessChanged(isDark: Boolean) {
}
override fun onScanQRCodeOpenCameraError() {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
data?.data?.let {
zxingview.startSpotAndShowRect() // 显示扫描框,并开始识别
if (resultCode == Activity.RESULT_OK && requestCode == requestQrImage) {
val picturePath = FileUtils.getPath(this, it)
// 本来就用到 QRCodeView 时可直接调 QRCodeView 的方法,走通用的回调
zxingview.decodeQRCode(picturePath)
}
}
}
}

@ -3,5 +3,6 @@ package io.legado.app.utils
import androidx.appcompat.app.AlertDialog
import io.legado.app.lib.theme.ATH
val AlertDialog.upTint: AlertDialog
get() = ATH.setAlertDialogTint(this)
fun AlertDialog.upTint(): AlertDialog {
return ATH.setAlertDialogTint(this)
}

@ -1,5 +1,235 @@
package io.legado.app.utils
import android.annotation.TargetApi
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.storage.StorageManager
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.util.Log
import androidx.core.content.ContextCompat
import java.io.File
import java.io.IOException
import java.lang.reflect.Array
import java.util.*
fun getSdPath() = Environment.getExternalStorageDirectory().absolutePath
object FileUtils {
fun getSdPath() = Environment.getExternalStorageDirectory().absolutePath
fun getFileByPath(filePath: String): File? {
return if (isSpace(filePath)) null else File(filePath)
}
fun isSpace(s: String?): Boolean {
if (s == null) return true
var i = 0
val len = s.length
while (i < len) {
if (!Character.isWhitespace(s[i])) {
return false
}
++i
}
return true
}
fun getSdCardPath(): String {
var sdCardDirectory = Environment.getExternalStorageDirectory().absolutePath
try {
sdCardDirectory = File(sdCardDirectory).canonicalPath
} catch (ioe: IOException) {
}
return sdCardDirectory
}
fun getStorageData(pContext: Context): ArrayList<String>? {
val storageManager = pContext.getSystemService(Context.STORAGE_SERVICE) as StorageManager
try {
val getVolumeList = storageManager.javaClass.getMethod("getVolumeList")
val storageValumeClazz = Class.forName("android.os.storage.StorageVolume")
val getPath = storageValumeClazz.getMethod("getPath")
val invokeVolumeList = getVolumeList.invoke(storageManager)
val length = Array.getLength(invokeVolumeList)
val list = ArrayList<String>()
for (i in 0 until length) {
val storageValume = Array.get(invokeVolumeList, i)//得到StorageVolume对象
val path = getPath.invoke(storageValume) as String
list.add(path)
}
return list
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
fun getExtSdCardPaths(con: Context): ArrayList<String> {
val paths = ArrayList<String>()
val files = ContextCompat.getExternalFilesDirs(con, "external")
val firstFile = files[0]
for (file in files) {
if (file != null && file != firstFile) {
val index = file.absolutePath.lastIndexOf("/Android/data")
if (index < 0) {
Log.w("", "Unexpected external file dir: " + file.absolutePath)
} else {
var path = file.absolutePath.substring(0, index)
try {
path = File(path).canonicalPath
} catch (e: IOException) {
// Keep non-canonical path.
}
paths.add(path)
}
}
}
return paths
}
@TargetApi(Build.VERSION_CODES.KITKAT)
fun getPath(context: Context, uri: Uri): String? {
val isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
if ("primary".equals(type, ignoreCase = true)) {
return Environment.getExternalStorageDirectory().toString() + "/" + split[1]
}
} else if (isDownloadsDocument(uri)) {
val id = DocumentsContract.getDocumentId(uri)
val split = id.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
if ("raw".equals(
type,
ignoreCase = true
)
) { //处理某些机型(比如Goole Pixel )ID是raw:/storage/emulated/0/Download/c20f8664da05ab6b4644913048ea8c83.mp4
return split[1]
}
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id)
)
return getDataColumn(context, contentUri, null, null)
} else if (isMediaDocument(uri)) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
var contentUri: Uri? = null
if ("image" == type) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else if ("video" == type) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
} else if ("audio" == type) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
}
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
return getDataColumn(context, contentUri, selection, selectionArgs)
}// MediaProvider
// DownloadsProvider
} else if ("content".equals(uri.scheme!!, ignoreCase = true)) {
// Return the remote address
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(
context,
uri,
null,
null
)
} else if ("file".equals(uri.scheme!!, ignoreCase = true)) {
return uri.path
}// File
// MediaStore (and general)
return null
}
fun getDataColumn(
context: Context, uri: Uri?, selection: String?,
selectionArgs: kotlin.Array<String>?
): String? {
val column = "_data"
val projection = arrayOf(column)
try {
context.contentResolver.query(
uri!!,
projection,
selection,
selectionArgs,
null
)!!.use { cursor ->
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(index)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
fun isExternalStorageDocument(uri: Uri): Boolean {
return "com.android.externalstorage.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
fun isDownloadsDocument(uri: Uri): Boolean {
return "com.android.providers.downloads.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
fun isMediaDocument(uri: Uri): Boolean {
return "com.android.providers.media.documents" == uri.authority
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
fun isGooglePhotosUri(uri: Uri): Boolean {
return "com.google.android.apps.photos.content" == uri.authority
}
}

@ -0,0 +1,5 @@
package io.legado.app.utils
import com.google.gson.Gson
inline fun <reified T> Gson.fromJson(json: String) = fromJson(json, T::class.java)

@ -0,0 +1,20 @@
package io.legado.app.utils
import android.content.Context
import android.os.Build
import android.view.View
import android.view.inputmethod.InputMethodManager
import io.legado.app.App
fun View.hidehideSoftInput() = run {
val imm = App.INSTANCE.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
imm?.let {
imm.hideSoftInputFromWindow(this.windowToken, 0)
}
}
fun View.disableAutoFill() = run {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
}
}

@ -0,0 +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">
<path
android:fillColor="#FF000000"
android:pathData="M12,10.9c-0.61,0 -1.1,0.49 -1.1,1.1s0.49,1.1 1.1,1.1c0.61,0 1.1,-0.49 1.1,-1.1s-0.49,-1.1 -1.1,-1.1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM14.19,14.19L6,18l3.81,-8.19L18,6l-3.81,8.19z"/>
</vector>

@ -0,0 +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">
<path
android:fillColor="#FF000000"
android:pathData="M4,6L2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM19,11L9,11L9,9h10v2zM15,15L9,15v-2h6v2zM19,7L9,7L9,5h10v2z"/>
</vector>

@ -0,0 +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">
<path
android:fillColor="#FF000000"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

@ -0,0 +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">
<path
android:fillColor="#FF000000"
android:pathData="M2,20h20v-4L2,16v4zM4,17h2v2L4,19v-2zM2,4v4h20L22,4L2,4zM6,7L4,7L4,5h2v2zM2,14h20v-4L2,10v4zM4,11h2v2L4,13v-2z"/>
</vector>

@ -1,8 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="io.legado.app.ui.about.AboutActivity">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context="io.legado.app.ui.about.AboutActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
<io.legado.app.ui.widget.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title="@string/about"/>
</LinearLayout>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<io.legado.app.ui.widget.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cn.bingoogolapple.qrcode.zxing.ZXingView
android:id="@+id/zxingview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:qrcv_animTime="1000"
app:qrcv_barCodeTipText="将条码放入框内,即可自动扫描"
app:qrcv_barcodeRectHeight="120dp"
app:qrcv_borderColor="@android:color/white"
app:qrcv_borderSize="1dp"
app:qrcv_cornerColor="@color/colorPrimaryDark"
app:qrcv_cornerDisplayType="center"
app:qrcv_cornerLength="20dp"
app:qrcv_cornerSize="3dp"
app:qrcv_isAutoZoom="true"
app:qrcv_isBarcode="false"
app:qrcv_isOnlyDecodeScanBoxArea="false"
app:qrcv_isScanLineReverse="true"
app:qrcv_isShowDefaultGridScanLineDrawable="false"
app:qrcv_isShowDefaultScanLineDrawable="true"
app:qrcv_isShowLocationPoint="true"
app:qrcv_isShowTipBackground="true"
app:qrcv_isShowTipTextAsSingleLine="false"
app:qrcv_isTipTextBelowRect="false"
app:qrcv_maskColor="#33FFFFFF"
app:qrcv_qrCodeTipText="将二维码放入框内,即可自动扫描"
app:qrcv_rectWidth="300dp"
app:qrcv_scanLineColor="@color/colorPrimaryDark"
app:qrcv_scanLineMargin="0dp"
app:qrcv_scanLineSize="0.5dp"
app:qrcv_tipTextColor="@android:color/white"
app:qrcv_tipTextSize="12sp"
app:qrcv_toolbarHeight="?attr/actionBarSize"
app:qrcv_topOffset="100dp"
app:qrcv_verticalBias="-1" />
<io.legado.app.ui.widget.TitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:title="@string/scan_qr_code" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:padding="16dp">
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_flashlight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="@string/read_aloud"
android:src="@drawable/ic_daytime"
android:tint="@color/tv_text_default"
app:backgroundTint="@color/background_menu"
app:elevation="2dp"
app:fabSize="mini"
app:pressedTranslationZ="2dp" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</RelativeLayout>

@ -0,0 +1,39 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/ll_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<io.legado.app.lib.theme.view.ATEAutoCompleteTextView
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:completionThreshold="0"
android:maxLines="5"
tools:ignore="LabelFor"/>
<TextView
android:id="@+id/tv_ok"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="@drawable/selector_fillet_btn_bg"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/ok"
android:textColor="@color/tv_text_default"/>
</LinearLayout>

@ -11,14 +11,31 @@
android:layout_height="wrap_content"
app:attachToActivity="false"
app:title="@string/bookshelf"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_book_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_bookshelf"
<TextView
android:id="@+id/tv_recent_reading"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
android:layout_height="wrap_content"
android:background="@color/background"
android:elevation="3dp"
android:padding="5dp"
android:text="@string/recent_reading"/>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_bookshelf"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_ib_pre"
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:padding="5dp" />

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:text="@string/add"
android:textSize="24sp" />

@ -4,20 +4,20 @@
tools:showIn="bottom_navigation_view">
<item
android:id="@+id/menu_bookshelf"
android:icon="@drawable/ic_menu_camera"
android:title="书架" />
android:id="@+id/menu_bookshelf"
android:icon="@drawable/ic_library_books_black_24dp"
android:title="@string/bookshelf"/>
<item
android:id="@+id/menu_find_book"
android:icon="@drawable/ic_menu_gallery"
android:title="发现" />
android:id="@+id/menu_find_book"
android:icon="@drawable/ic_explore_black_24dp"
android:title="@string/find"/>
<item
android:id="@+id/menu_book_source"
android:icon="@drawable/ic_menu_slideshow"
android:title="书源" />
android:id="@+id/menu_book_source"
android:icon="@drawable/ic_storage_black_24dp"
android:title="@string/book_source"/>
<item
android:id="@+id/menu_my_config"
android:icon="@drawable/ic_menu_manage"
android:title="我的" />
android:id="@+id/menu_my_config"
android:icon="@drawable/ic_person_black_24dp"
android:title="@string/my"/>
</menu>

@ -72,7 +72,7 @@
app:showAsAction="never" />
<item
android:id="@+id/action_import_book_source_rwm"
android:id="@+id/action_import_book_source_qr"
android:icon="@drawable/ic_import"
android:title="@string/import_by_qr_code"
app:showAsAction="never" />

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_choose_from_gallery"
android:title="@string/gallery"
app:showAsAction="always" />
</menu>

@ -11,7 +11,7 @@
<color name="bg_divider_line">#363636</color>
<color name="btn_bg_press">#804D4D4D</color>
<color name="btn_bg_press_2">#80686868</color>
<color name="btn_bg_press_tp">#88111111</color>
<color name="btn_bg_press_tp">#80C7C7C7</color>
<color name="darker_gray">#66666666</color>
<color name="tv_btn_normal_black">#737373</color>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">@color/md_teal_800</color>
<color name="colorPrimaryDark">@color/md_teal_900</color>
<color name="colorPrimary">@color/md_light_blue_500</color>
<color name="colorPrimaryDark">@color/md_light_blue_600</color>
<color name="colorAccent">@color/md_pink_A400</color>
<color name="text_default">#222222</color>
<color name="divider">#66666666</color>
@ -23,7 +23,7 @@
<color name="btn_bg_press">#80ACACAC</color>
<color name="btn_bg_press_2">#80858585</color>
<color name="btn_bg_press_tp">#88000000</color>
<color name="btn_bg_press_tp">#802C2C2C</color>
<color name="tv_btn_normal_black">#737373</color>
<color name="tv_btn_press_black">#adadad</color>

@ -33,6 +33,7 @@
<string name="enable">启用</string>
<string name="bookshelf">书架</string>
<string name="recent_reading">最近阅读</string>
<string name="last_read">最后阅读</string>
<string name="read_summary">让阅读成为一种习惯。</string>
<string name="update_log">更新日志</string>
@ -470,4 +471,5 @@
<string name="edit_find">编辑发现</string>
<string name="change_icon_summary">切换软件显示在桌面的图标</string>
<string name="help">帮助</string>
<string name="my">我的</string>
</resources>

@ -48,13 +48,7 @@
<item name="colorAccent">@color/md_grey_900</item>
</style>
<style name="AppTheme.AlertDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert">
<item name="colorAccent">@color/colorAccent</item>
<item name="android:background">@color/background_card</item>
<item name="android:textColor">@color/tv_text_default</item>
<item name="android:textColorPrimary">@color/tv_text_default</item>
<item name="textColorAlertDialogListItem">@color/tv_text_default</item>
</style>
<style name="AppTheme.AlertDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert"/>
//**************************************************************System
Style******************************************************************************//

@ -31,7 +31,7 @@
android:title="@string/e_ink_mode"
app:iconSpaceReserved="false" />
<Preference
<androidx.preference.Preference
android:key="defaultTheme"
android:summary="@string/restore_default_theme"
android:title="@string/default_theme"

@ -2,29 +2,56 @@
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.preference.Preference
android:key="setting"
android:title="设置"
android:summary="与功能相关的一些设置"
app:iconSpaceReserved="false" />
<androidx.preference.Preference
android:key="web_dav_setting"
android:title="云备份设置"
android:summary="通过WebDav云备份"
app:iconSpaceReserved="false" />
<androidx.preference.Preference
android:key="theme_setting"
android:title="主题设置"
android:summary="与界面/颜色相关的一些设置"
app:iconSpaceReserved="false" />
<io.legado.app.lib.theme.prefs.ATESwitchPreference
android:defaultValue="false"
android:key="isNightTheme"
android:summary="开启/关闭暗色主题"
android:title="暗色主题"
app:iconSpaceReserved="false" />
<io.legado.app.lib.theme.prefs.ATESwitchPreference
android:defaultValue="false"
android:key="webService"
android:title="Web服务"
app:iconSpaceReserved="false" />
<io.legado.app.lib.theme.prefs.ATEPreferenceCategory
android:title="设置"
app:iconSpaceReserved="false">
<androidx.preference.Preference
android:key="web_dav_setting"
android:summary="通过WebDav云备份"
android:title="云备份设置"
app:iconSpaceReserved="false" />
<androidx.preference.Preference
android:key="theme_setting"
android:summary="与界面/颜色相关的一些设置"
android:title="主题设置"
app:iconSpaceReserved="false" />
<androidx.preference.Preference
android:key="setting"
android:summary="与功能相关的一些设置"
android:title="其它设置"
app:iconSpaceReserved="false" />
</io.legado.app.lib.theme.prefs.ATEPreferenceCategory>
<io.legado.app.lib.theme.prefs.ATEPreferenceCategory app:iconSpaceReserved="false">
<androidx.preference.Preference
android:key="donate"
android:summary="您的支持是我更新的动力"
android:title="@string/donate"
app:iconSpaceReserved="false" />
<androidx.preference.Preference
android:key="about"
android:summary="公众号[开源阅读软件]"
android:title="@string/about"
app:iconSpaceReserved="false" />
</io.legado.app.lib.theme.prefs.ATEPreferenceCategory>
</androidx.preference.PreferenceScreen>
Loading…
Cancel
Save