Merge pull request #29 from gedoor/master

up
pull/379/head
口口吕 5 years ago committed by GitHub
commit 384aea9339
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      app/src/main/AndroidManifest.xml
  2. 9
      app/src/main/assets/updateLog.md
  3. 1
      app/src/main/java/io/legado/app/constant/EventBus.kt
  4. 14
      app/src/main/java/io/legado/app/help/permission/PermissionsCompat.kt
  5. 2
      app/src/main/java/io/legado/app/help/permission/Request.kt
  6. 11
      app/src/main/java/io/legado/app/service/TTSReadAloudService.kt
  7. 6
      app/src/main/java/io/legado/app/ui/book/arrange/ArrangeBookActivity.kt
  8. 16
      app/src/main/java/io/legado/app/ui/book/arrange/ArrangeBookAdapter.kt
  9. 5
      app/src/main/java/io/legado/app/ui/book/chapterlist/ChapterListFragment.kt
  10. 22
      app/src/main/java/io/legado/app/ui/book/local/ImportBookActivity.kt
  11. 3
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  12. 24
      app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudDialog.kt
  13. 12
      app/src/main/java/io/legado/app/ui/filechooser/FilePicker.kt
  14. 2
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  15. 36
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt
  16. 58
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt
  17. 4
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  18. 34
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt
  19. 35
      app/src/main/java/io/legado/app/ui/widget/dialog/TextDialog.kt
  20. 50
      app/src/main/res/layout/activity_import_book.xml
  21. 268
      app/src/main/res/layout/dialog_read_aloud.xml
  22. 20
      app/src/main/res/layout/dialog_text_view.xml
  23. 2
      app/src/main/res/layout/fragment_bookshelf.xml
  24. 2
      app/src/main/res/layout/view_read_menu.xml
  25. 5
      app/src/main/res/values/strings.xml

@ -23,6 +23,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true" android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme.Light" android:theme="@style/AppTheme.Light"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,UnusedAttribute"> tools:ignore="AllowBackup,GoogleAppIndexingWarning,UnusedAttribute">
<!--主入口--> <!--主入口-->
@ -91,7 +92,7 @@
<!--书籍详情页--> <!--书籍详情页-->
<activity <activity
android:name=".ui.book.info.BookInfoActivity" android:name=".ui.book.info.BookInfoActivity"
android:launchMode="singleTask" /> android:launchMode="singleTop" />
<!--书籍信息编辑--> <!--书籍信息编辑-->
<activity <activity
android:name="io.legado.app.ui.book.info.edit.BookInfoEditActivity" android:name="io.legado.app.ui.book.info.edit.BookInfoEditActivity"

@ -2,11 +2,18 @@
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 * 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。
* 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
**2020/03/13**
* 更改书架控件,ViewPager2替换回2.0使用的ViewPager,解决下拉不流畅问题
* 修复点击作者搜索后,打开的详情页还是原来的书籍的bug
* 修改朗读菜单
**2020/03/12**
* 导入本地添加需要权限模式
**2020/03/11** **2020/03/11**
* 修复调节上边距时下边距一起动的bug * 修复调节上边距时下边距一起动的bug
* 适配沚水的web阅读 by 六月 * 适配沚水的web阅读 by 六月
* 分组管理页面调整 by yangyxd * 分组管理页面调整 by yangyxd
* 导入本地添加需要权限模式
**2020/03/10** **2020/03/10**
* 优化文字选择菜单弹出位置 * 优化文字选择菜单弹出位置

@ -11,7 +11,6 @@ object EventBus {
const val TIME_CHANGED = "timeChanged" const val TIME_CHANGED = "timeChanged"
const val UP_CONFIG = "upConfig" const val UP_CONFIG = "upConfig"
const val OPEN_CHAPTER = "openChapter" const val OPEN_CHAPTER = "openChapter"
const val REPLACE = "replace"
const val AUDIO_SUB_TITLE = "audioSubTitle" const val AUDIO_SUB_TITLE = "audioSubTitle"
const val AUDIO_STATE = "audioState" const val AUDIO_STATE = "audioState"
const val AUDIO_PROGRESS = "audioProgress" const val AUDIO_PROGRESS = "audioProgress"

@ -1,8 +1,11 @@
package io.legado.app.help.permission package io.legado.app.help.permission
import android.os.Build
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import org.jetbrains.anko.startActivity
import java.util.ArrayList
class PermissionsCompat private constructor() { class PermissionsCompat private constructor() {
@ -12,6 +15,17 @@ class PermissionsCompat private constructor() {
RequestManager.pushRequest(request) RequestManager.pushRequest(request)
} }
companion object {
// 检查权限, 如果已经拥有返回 true
fun check(activity: AppCompatActivity, vararg permissions: String): Boolean {
var request: Request = Request(activity)
var pers = ArrayList<String>()
pers.addAll(listOf(*permissions))
var data = request.getDeniedPermissions(pers.toTypedArray())
return data == null;
}
}
class Builder { class Builder {
private val request: Request private val request: Request

@ -102,7 +102,7 @@ internal class Request : OnRequestPermissionsResultCallback {
deniedCallback = null deniedCallback = null
} }
private fun getDeniedPermissions(permissions: Array<String>?): Array<String>? { fun getDeniedPermissions(permissions: Array<String>?): Array<String>? {
if (permissions != null) { if (permissions != null) {
val deniedPermissionList = ArrayList<String>() val deniedPermissionList = ArrayList<String>()
for (permission in permissions) { for (permission in permissions) {

@ -29,7 +29,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
} }
} }
private var ttsIsSuccess: Boolean = false private var ttsInitFinish = false
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@ -42,22 +42,23 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener
clearTTS() clearTTS()
} }
@Synchronized
override fun onInit(status: Int) { override fun onInit(status: Int) {
launch {
if (status == TextToSpeech.SUCCESS) { if (status == TextToSpeech.SUCCESS) {
textToSpeech?.language = Locale.CHINA textToSpeech?.language = Locale.CHINA
textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener())
ttsIsSuccess = true ttsInitFinish = true
play() play()
} else { } else {
launch {
toast(R.string.tts_init_failed) toast(R.string.tts_init_failed)
} }
} }
} }
@Suppress("DEPRECATION") @Synchronized
override fun play() { override fun play() {
if (contentList.isEmpty() || !ttsIsSuccess) { if (contentList.isEmpty() || !ttsInitFinish) {
return return
} }
if (requestFocus()) { if (requestFocus()) {

@ -6,12 +6,14 @@ import android.view.MenuItem
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.App import io.legado.app.App
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookGroup import io.legado.app.data.entities.BookGroup
import io.legado.app.help.ItemTouchCallback
import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.noButton
import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.dialogs.okButton
@ -64,6 +66,10 @@ class ArrangeBookActivity : VMBaseActivity<ArrangeBookViewModel>(R.layout.activi
recycler_view.addItemDecoration(VerticalDivider(this)) recycler_view.addItemDecoration(VerticalDivider(this))
adapter = ArrangeBookAdapter(this, this) adapter = ArrangeBookAdapter(this, this)
recycler_view.adapter = adapter recycler_view.adapter = adapter
val itemTouchCallback = ItemTouchCallback()
itemTouchCallback.onItemTouchCallbackListener = adapter
itemTouchCallback.isCanDrag = true
ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view)
select_action_bar.setMainActionText(R.string.move_to_group) select_action_bar.setMainActionText(R.string.move_to_group)
select_action_bar.inflateMenu(R.menu.arrange_book_sel) select_action_bar.inflateMenu(R.menu.arrange_book_sel)
select_action_bar.setOnMenuItemClickListener(this) select_action_bar.setOnMenuItemClickListener(this)

@ -7,14 +7,13 @@ import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.base.adapter.SimpleRecyclerAdapter
import io.legado.app.data.entities.Book import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookGroup import io.legado.app.data.entities.BookGroup
import io.legado.app.utils.gone import io.legado.app.help.ItemTouchCallback
import io.legado.app.utils.visible
import kotlinx.android.synthetic.main.item_arrange_book.view.* import kotlinx.android.synthetic.main.item_arrange_book.view.*
import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onClick
class ArrangeBookAdapter(context: Context, val callBack: CallBack) : class ArrangeBookAdapter(context: Context, val callBack: CallBack) :
SimpleRecyclerAdapter<Book>(context, R.layout.item_arrange_book) { SimpleRecyclerAdapter<Book>(context, R.layout.item_arrange_book),
ItemTouchCallback.OnItemTouchCallbackListener {
val groupRequestCode = 12 val groupRequestCode = 12
private val selectedBooks: HashSet<Book> = hashSetOf() private val selectedBooks: HashSet<Book> = hashSetOf()
var actionItem: Book? = null var actionItem: Book? = null
@ -56,12 +55,7 @@ class ArrangeBookAdapter(context: Context, val callBack: CallBack) :
override fun convert(holder: ItemViewHolder, item: Book, payloads: MutableList<Any>) { override fun convert(holder: ItemViewHolder, item: Book, payloads: MutableList<Any>) {
with(holder.itemView) { with(holder.itemView) {
tv_name.text = item.name tv_name.text = item.name
// tv_name.text = if (item.author.isEmpty()) { tv_author.text = item.author
// item.name
// } else {
// "${item.name}(${item.author})"
// }
tv_author.text = item.author // resources.getString(R.string.author_show, item.author)
tv_author.visibility = if (item.author.isEmpty()) View.GONE else View.VISIBLE tv_author.visibility = if (item.author.isEmpty()) View.GONE else View.VISIBLE
tv_group_s.text = getGroupName(item.group) tv_group_s.text = getGroupName(item.group)
checkbox.isChecked = selectedBooks.contains(item) checkbox.isChecked = selectedBooks.contains(item)
@ -115,7 +109,7 @@ class ArrangeBookAdapter(context: Context, val callBack: CallBack) :
groupNames.add(it.groupName) groupNames.add(it.groupName)
} }
} }
return groupNames; return groupNames
} }
private fun getGroupName(groupId: Int): String { private fun getGroupName(groupId: Int): String {

@ -36,6 +36,7 @@ class ChapterListFragment : VMBaseFragment<ChapterListViewModel>(R.layout.fragme
private var durChapterIndex = 0 private var durChapterIndex = 0
private lateinit var mLayoutManager: UpLinearLayoutManager private lateinit var mLayoutManager: UpLinearLayoutManager
private var tocLiveData: LiveData<List<BookChapter>>? = null private var tocLiveData: LiveData<List<BookChapter>>? = null
private var scrollToDurChapter = false
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
viewModel.chapterCallBack = this viewModel.chapterCallBack = this
@ -74,7 +75,6 @@ class ChapterListFragment : VMBaseFragment<ChapterListViewModel>(R.layout.fragme
book?.let { book?.let {
durChapterIndex = it.durChapterIndex durChapterIndex = it.durChapterIndex
tv_current_chapter_info.text = it.durChapterTitle tv_current_chapter_info.text = it.durChapterTitle
mLayoutManager.scrollToPositionWithOffset(durChapterIndex, 0)
initCacheFileNames(it) initCacheFileNames(it)
} }
} }
@ -85,7 +85,10 @@ class ChapterListFragment : VMBaseFragment<ChapterListViewModel>(R.layout.fragme
tocLiveData = App.db.bookChapterDao().observeByBook(viewModel.bookUrl) tocLiveData = App.db.bookChapterDao().observeByBook(viewModel.bookUrl)
tocLiveData?.observe(viewLifecycleOwner, Observer { tocLiveData?.observe(viewLifecycleOwner, Observer {
adapter.setItems(it) adapter.setItems(it)
if (!scrollToDurChapter) {
mLayoutManager.scrollToPositionWithOffset(durChapterIndex, 0) mLayoutManager.scrollToPositionWithOffset(durChapterIndex, 0)
scrollToDurChapter = true
}
}) })
} }

@ -8,6 +8,7 @@ import android.os.Bundle
import android.provider.DocumentsContract import android.provider.DocumentsContract
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
@ -17,6 +18,8 @@ import io.legado.app.App
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.help.AppConfig import io.legado.app.help.AppConfig
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.ui.filechooser.FileChooserDialog import io.legado.app.ui.filechooser.FileChooserDialog
import io.legado.app.ui.filechooser.FilePicker import io.legado.app.ui.filechooser.FilePicker
import io.legado.app.ui.widget.SelectActionBar import io.legado.app.ui.widget.SelectActionBar
@ -80,6 +83,7 @@ class ImportBookActivity : VMBaseActivity<ImportBookViewModel>(R.layout.activity
} }
} }
}) })
} }
private fun initEvent() { private fun initEvent() {
@ -124,6 +128,24 @@ class ImportBookActivity : VMBaseActivity<ImportBookViewModel>(R.layout.activity
subDocs.clear() subDocs.clear()
path = it path = it
} }
} ?: let {
// 没有权限就显示一个授权提示和按钮
if (PermissionsCompat.check(this, *Permissions.Group.STORAGE)) {
hint_per.visibility = View.GONE
} else {
hint_per.visibility = View.VISIBLE
tv_request_per.onClick {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
hint_per.visibility = View.GONE
initData()
upRootDoc()
}
.request()
}
}
} }
upPath() upPath()
} }

@ -735,9 +735,6 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
} }
} }
} }
observeEvent<String>(EventBus.REPLACE) {
ReplaceEditDialog().show(supportFragmentManager, "replaceEditDialog")
}
observeEvent<Boolean>(PreferKey.keepLight) { observeEvent<Boolean>(PreferKey.keepLight) {
upScreenTimeOut() upScreenTimeOut()
} }

@ -21,7 +21,6 @@ import io.legado.app.utils.observeEvent
import io.legado.app.utils.putPrefBoolean import io.legado.app.utils.putPrefBoolean
import kotlinx.android.synthetic.main.dialog_read_aloud.* import kotlinx.android.synthetic.main.dialog_read_aloud.*
import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onClick
import org.jetbrains.anko.sdk27.listeners.onLongClick
class ReadAloudDialog : BaseDialogFragment() { class ReadAloudDialog : BaseDialogFragment() {
var callBack: CallBack? = null var callBack: CallBack? = null
@ -34,7 +33,7 @@ class ReadAloudDialog : BaseDialogFragment() {
it.windowManager?.defaultDisplay?.getMetrics(dm) it.windowManager?.defaultDisplay?.getMetrics(dm)
} }
dialog?.window?.let { dialog?.window?.let {
it.setBackgroundDrawableResource(R.color.transparent) it.setBackgroundDrawableResource(R.color.background)
it.decorView.setPadding(0, 0, 0, 0) it.decorView.setPadding(0, 0, 0, 0)
val attr = it.attributes val attr = it.attributes
attr.dimAmount = 0.0f attr.dimAmount = 0.0f
@ -54,10 +53,10 @@ class ReadAloudDialog : BaseDialogFragment() {
} }
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
ll_bottom_bg.setBackgroundColor(requireContext().bottomBackground) root_view.setBackgroundColor(requireContext().bottomBackground)
initOnChange() initOnChange()
initData() initData()
initOnClick() initEvent()
} }
private fun initData() { private fun initData() {
@ -101,22 +100,19 @@ class ReadAloudDialog : BaseDialogFragment() {
}) })
} }
private fun initOnClick() { private fun initEvent() {
iv_menu.onClick { callBack?.showMenuBar(); dismiss() } ll_main_menu.onClick { callBack?.showMenuBar(); dismiss() }
iv_other_config.onClick { ll_setting.onClick {
ReadAloudConfigDialog().show(childFragmentManager, "readAloudConfigDialog") ReadAloudConfigDialog().show(childFragmentManager, "readAloudConfigDialog")
} }
tv_pre.onClick { ReadBook.moveToPrevChapter(upContent = true, toLast = false) }
tv_next.onClick { ReadBook.moveToNextChapter(true) }
iv_stop.onClick { ReadAloud.stop(requireContext()); dismiss() } iv_stop.onClick { ReadAloud.stop(requireContext()); dismiss() }
iv_play_pause.onClick { callBack?.onClickReadAloud() } iv_play_pause.onClick { callBack?.onClickReadAloud() }
iv_play_prev.onClick { ReadAloud.prevParagraph(requireContext()) } iv_play_prev.onClick { ReadAloud.prevParagraph(requireContext()) }
iv_play_prev.onLongClick {
ReadBook.moveToPrevChapter(upContent = true, toLast = false)
true
}
iv_play_next.onClick { ReadAloud.nextParagraph(requireContext()) } iv_play_next.onClick { ReadAloud.nextParagraph(requireContext()) }
iv_play_next.onLongClick { ReadBook.moveToNextChapter(true); true } ll_catalog.onClick { callBack?.openChapterList() }
fabToc.onClick { callBack?.openChapterList() } ll_to_backstage.onClick { callBack?.finish() }
fabBack.onClick { callBack?.finish() }
} }
private fun upPlayState() { private fun upPlayState() {

@ -31,7 +31,7 @@ object FilePicker {
0 -> default?.invoke() 0 -> default?.invoke()
1 -> { 1 -> {
try { try {
val intent = getSelectDirIntent() val intent = createSelectDirIntent()
activity.startActivityForResult(intent, requestCode) activity.startActivityForResult(intent, requestCode)
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
e.printStackTrace() e.printStackTrace()
@ -68,7 +68,7 @@ object FilePicker {
0 -> default?.invoke() 0 -> default?.invoke()
1 -> { 1 -> {
try { try {
val intent = getSelectDirIntent() val intent = createSelectDirIntent()
fragment.startActivityForResult(intent, requestCode) fragment.startActivityForResult(intent, requestCode)
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
e.printStackTrace() e.printStackTrace()
@ -106,7 +106,7 @@ object FilePicker {
0 -> default?.invoke() 0 -> default?.invoke()
1 -> { 1 -> {
try { try {
val intent = getSelectFileIntent() val intent = createSelectFileIntent()
intent.type = type//设置类型 intent.type = type//设置类型
activity.startActivityForResult(intent, requestCode) activity.startActivityForResult(intent, requestCode)
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
@ -147,7 +147,7 @@ object FilePicker {
0 -> default?.invoke() 0 -> default?.invoke()
1 -> { 1 -> {
try { try {
val intent = getSelectFileIntent() val intent = createSelectFileIntent()
intent.type = type//设置类型 intent.type = type//设置类型
fragment.startActivityForResult(intent, requestCode) fragment.startActivityForResult(intent, requestCode)
} catch (e: java.lang.Exception) { } catch (e: java.lang.Exception) {
@ -168,14 +168,14 @@ object FilePicker {
}.show() }.show()
} }
private fun getSelectFileIntent(): Intent { private fun createSelectFileIntent(): Intent {
val intent = Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE) intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
return intent return intent
} }
private fun getSelectDirIntent(): Intent { private fun createSelectDirIntent(): Intent {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
return intent return intent

@ -78,7 +78,7 @@ class MainActivity : VMBaseActivity<MainViewModel>(R.layout.activity_main),
putPrefInt(PreferKey.versionCode, App.INSTANCE.versionCode) putPrefInt(PreferKey.versionCode, App.INSTANCE.versionCode)
if (!BuildConfig.DEBUG) { if (!BuildConfig.DEBUG) {
val log = String(assets.open("updateLog.md").readBytes()) val log = String(assets.open("updateLog.md").readBytes())
TextDialog.show(supportFragmentManager, log, TextDialog.MD) TextDialog.show(supportFragmentManager, log, TextDialog.MD, 5000)
} }
} }
} }

@ -1,36 +0,0 @@
package io.legado.app.ui.main.bookshelf
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import io.legado.app.data.entities.BookGroup
import io.legado.app.ui.main.bookshelf.books.BooksFragment
class BookshelfAdapter(fragment: Fragment, val callBack: CallBack) :
FragmentStateAdapter(fragment) {
private val ids = hashSetOf<Long>()
override fun getItemCount(): Int {
return callBack.groupSize
}
override fun getItemId(position: Int): Long {
return callBack.getGroup(position).groupId.toLong()
}
override fun containsItem(itemId: Long): Boolean {
return ids.contains(itemId)
}
override fun createFragment(position: Int): Fragment {
val groupId = callBack.getGroup(position).groupId
ids.add(groupId.toLong())
return BooksFragment.newInstance(position, groupId)
}
interface CallBack {
val groupSize: Int
fun getGroup(position: Int): BookGroup
}
}

@ -7,10 +7,12 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import io.legado.app.App import io.legado.app.App
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseFragment import io.legado.app.base.VMBaseFragment
@ -29,6 +31,7 @@ import io.legado.app.ui.book.download.DownloadActivity
import io.legado.app.ui.book.group.GroupManageDialog import io.legado.app.ui.book.group.GroupManageDialog
import io.legado.app.ui.book.local.ImportBookActivity import io.legado.app.ui.book.local.ImportBookActivity
import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.book.search.SearchActivity
import io.legado.app.ui.main.bookshelf.books.BooksFragment
import io.legado.app.ui.widget.text.AutoCompleteTextView import io.legado.app.ui.widget.text.AutoCompleteTextView
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.android.synthetic.main.dialog_bookshelf_config.view.* import kotlinx.android.synthetic.main.dialog_bookshelf_config.view.*
@ -42,15 +45,14 @@ import org.jetbrains.anko.startActivity
class BookshelfFragment : VMBaseFragment<BookshelfViewModel>(R.layout.fragment_bookshelf), class BookshelfFragment : VMBaseFragment<BookshelfViewModel>(R.layout.fragment_bookshelf),
TabLayout.OnTabSelectedListener, TabLayout.OnTabSelectedListener,
SearchView.OnQueryTextListener, SearchView.OnQueryTextListener,
GroupManageDialog.CallBack, GroupManageDialog.CallBack {
BookshelfAdapter.CallBack {
override val viewModel: BookshelfViewModel override val viewModel: BookshelfViewModel
get() = getViewModel(BookshelfViewModel::class.java) get() = getViewModel(BookshelfViewModel::class.java)
private lateinit var bookshelfAdapter: BookshelfAdapter
private var bookGroupLiveData: LiveData<List<BookGroup>>? = null private var bookGroupLiveData: LiveData<List<BookGroup>>? = null
private val bookGroups = mutableListOf<BookGroup>() private val bookGroups = mutableListOf<BookGroup>()
private val fragmentMap = hashMapOf<Int, Fragment>()
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
setSupportToolbar(toolbar) setSupportToolbar(toolbar)
@ -79,26 +81,17 @@ class BookshelfFragment : VMBaseFragment<BookshelfViewModel>(R.layout.fragment_b
} }
} }
override val groupSize: Int
get() = bookGroups.size
override fun getGroup(position: Int): BookGroup {
return bookGroups[position]
}
private val selectedGroup: BookGroup private val selectedGroup: BookGroup
get() = bookGroups[view_pager_bookshelf.currentItem] get() = bookGroups[view_pager_bookshelf.currentItem]
private fun initView() { private fun initView() {
ATH.applyEdgeEffectColor(view_pager_bookshelf)
tab_layout.isTabIndicatorFullWidth = false tab_layout.isTabIndicatorFullWidth = false
tab_layout.tabMode = TabLayout.MODE_SCROLLABLE tab_layout.tabMode = TabLayout.MODE_SCROLLABLE
tab_layout.setSelectedTabIndicatorColor(requireContext().accentColor) tab_layout.setSelectedTabIndicatorColor(requireContext().accentColor)
ATH.applyEdgeEffectColor(view_pager_bookshelf) tab_layout.setupWithViewPager(view_pager_bookshelf)
bookshelfAdapter = BookshelfAdapter(this, this) view_pager_bookshelf.offscreenPageLimit = 1
view_pager_bookshelf.adapter = bookshelfAdapter view_pager_bookshelf.adapter = TabFragmentPageAdapter(childFragmentManager)
TabLayoutMediator(tab_layout, view_pager_bookshelf) { tab, position ->
tab.text = bookGroups[position].groupName
}.attach()
} }
private fun initBookGroupData() { private fun initBookGroupData() {
@ -119,7 +112,7 @@ class BookshelfFragment : VMBaseFragment<BookshelfViewModel>(R.layout.fragment_b
bookGroups.add(AppConst.bookGroupAudio) bookGroups.add(AppConst.bookGroupAudio)
} }
bookGroups.addAll(it) bookGroups.addAll(it)
bookshelfAdapter.notifyDataSetChanged() view_pager_bookshelf.adapter?.notifyDataSetChanged()
tab_layout.getTabAt(getPrefInt(PreferKey.saveTabPosition, 0))?.select() tab_layout.getTabAt(getPrefInt(PreferKey.saveTabPosition, 0))?.select()
tab_layout.addOnTabSelectedListener(this) tab_layout.addOnTabSelectedListener(this)
} }
@ -149,7 +142,7 @@ class BookshelfFragment : VMBaseFragment<BookshelfViewModel>(R.layout.fragment_b
if (AppConfig.bookGroupAllShow) { if (AppConfig.bookGroupAllShow) {
bookGroups.add(0, AppConst.bookGroupAll) bookGroups.add(0, AppConst.bookGroupAll)
} }
bookshelfAdapter.notifyDataSetChanged() view_pager_bookshelf.adapter?.notifyDataSetChanged()
} }
} }
@ -212,4 +205,31 @@ class BookshelfFragment : VMBaseFragment<BookshelfViewModel>(R.layout.fragment_b
putPrefInt(PreferKey.saveTabPosition, it) putPrefInt(PreferKey.saveTabPosition, it)
} }
} }
private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) :
FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getPageTitle(position: Int): CharSequence? {
return bookGroups[position].groupName
}
override fun getItemPosition(`object`: Any): Int {
return POSITION_NONE
}
override fun getItem(position: Int): Fragment {
val group = bookGroups[position]
var fragment = fragmentMap[group.groupId]
if (fragment == null) {
fragment = BooksFragment.newInstance(position, group.groupId)
fragmentMap[group.groupId] = fragment
}
return fragment
}
override fun getCount(): Int {
return bookGroups.size
}
}
} }

@ -246,8 +246,8 @@ class ReadRssActivity : VMBaseActivity<ReadRssViewModel>(R.layout.activity_rss_r
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
private fun readAloud() { private fun readAloud() {
if (viewModel.textToSpeech.isSpeaking) { if (viewModel.textToSpeech?.isSpeaking == true) {
viewModel.textToSpeech.stop() viewModel.textToSpeech?.stop()
upTtsMenu(false) upTtsMenu(false)
} else { } else {
web_view.settings.javaScriptEnabled = true web_view.settings.javaScriptEnabled = true

@ -35,7 +35,9 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
val contentLiveData = MutableLiveData<String>() val contentLiveData = MutableLiveData<String>()
val urlLiveData = MutableLiveData<AnalyzeUrl>() val urlLiveData = MutableLiveData<AnalyzeUrl>()
var star = false var star = false
var textToSpeech: TextToSpeech = TextToSpeech(context, this) var textToSpeech: TextToSpeech? = null
private var ttsInitFinish = false
private var ttsText = ""
fun initData(intent: Intent) { fun initData(intent: Intent) {
execute { execute {
@ -143,28 +145,42 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
} }
} }
@Synchronized
override fun onInit(status: Int) { override fun onInit(status: Int) {
launch {
if (status == TextToSpeech.SUCCESS) { if (status == TextToSpeech.SUCCESS) {
textToSpeech.language = Locale.CHINA textToSpeech?.language = Locale.CHINA
textToSpeech.setOnUtteranceProgressListener(TTSUtteranceListener()) textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener())
ttsInitFinish = true
play()
} else { } else {
launch {
toast(R.string.tts_init_failed) toast(R.string.tts_init_failed)
} }
} }
} }
@Synchronized
private fun play() {
if (!ttsInitFinish) return
textToSpeech?.stop()
ttsText.split("\n", " ", "  ").forEach {
textToSpeech?.speak(it, TextToSpeech.QUEUE_ADD, null, "rss")
}
}
fun readAloud(text: String) { fun readAloud(text: String) {
textToSpeech.stop() ttsText = text
text.split("\n", " ", "  ").forEach { textToSpeech?.let {
textToSpeech.speak(it, TextToSpeech.QUEUE_ADD, null, "rss") play()
} ?: let {
textToSpeech = TextToSpeech(context, this)
} }
} }
override fun onCleared() { override fun onCleared() {
super.onCleared() super.onCleared()
textToSpeech.stop() textToSpeech?.stop()
textToSpeech.shutdown() textToSpeech?.shutdown()
} }
/** /**

@ -5,29 +5,40 @@ import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import kotlinx.android.synthetic.main.dialog_text_view.* import kotlinx.android.synthetic.main.dialog_text_view.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import ru.noties.markwon.Markwon import ru.noties.markwon.Markwon
class TextDialog : DialogFragment() { class TextDialog : BaseDialogFragment() {
companion object { companion object {
const val MD = 1 const val MD = 1
fun show(fragmentManager: FragmentManager, content: String?, mode: Int = 0) { fun show(
fragmentManager: FragmentManager,
content: String?,
mode: Int = 0,
time: Long = 0
) {
TextDialog().apply { TextDialog().apply {
val bundle = Bundle() val bundle = Bundle()
bundle.putString("content", content) bundle.putString("content", content)
bundle.putInt("mode", mode) bundle.putInt("mode", mode)
bundle.putLong("time", time)
arguments = bundle arguments = bundle
isCancelable = false
}.show(fragmentManager, "textDialog") }.show(fragmentManager, "textDialog")
} }
} }
private var time = 0L
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = DisplayMetrics() val dm = DisplayMetrics()
@ -43,8 +54,7 @@ class TextDialog : DialogFragment() {
return inflater.inflate(R.layout.dialog_text_view, container) return inflater.inflate(R.layout.dialog_text_view, container)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
arguments?.let { arguments?.let {
val content = it.getString("content") ?: "" val content = it.getString("content") ?: ""
when (it.getInt("mode")) { when (it.getInt("mode")) {
@ -57,8 +67,21 @@ class TextDialog : DialogFragment() {
} }
else -> text_view.text = content else -> text_view.text = content
} }
time = it.getLong("time", 0L)
}
if (time > 0) {
badge_view.setBadgeCount((time / 1000).toInt())
launch {
while (time > 0) {
delay(1000)
time -= 1000
badge_view.setBadgeCount((time / 1000).toInt())
if (time <= 0) {
dialog?.setCancelable(true)
}
}
}
} }
} }
} }

@ -1,20 +1,23 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<io.legado.app.ui.widget.TitleBar <io.legado.app.ui.widget.TitleBar
android:id="@+id/titleBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:title="@string/book_local" /> app:title="@string/book_local" />
<!--path--> <!--path-->
<LinearLayout <LinearLayout
android:id="@+id/layTop"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/titleBar"
android:background="@color/background" android:background="@color/background"
android:minHeight="36dp" android:minHeight="36dp"
android:padding="8dp" android:padding="8dp"
@ -53,12 +56,51 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
app:layout_constraintTop_toBottomOf="@id/layTop"
app:layout_constraintBottom_toTopOf="@id/select_action_bar"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" /> android:layout_weight="1" />
<io.legado.app.ui.widget.SelectActionBar <io.legado.app.ui.widget.SelectActionBar
android:id="@+id/select_action_bar" android:id="@+id/select_action_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" />
<LinearLayout
android:id="@+id/hint_per"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:orientation="vertical"
android:padding="36dp"
android:gravity="center"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="@string/tip_local_perm_request_storage"
android:layout_marginBottom="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</TextView>
<io.legado.app.ui.widget.text.AccentBgTextView
android:id="@+id/tv_request_per"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:minHeight="42dp"
android:gravity="center"
android:text="@string/request_permission"
android:textSize="14sp"
app:radius="30dp" />
</LinearLayout>
</LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -1,90 +1,38 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"> xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_view"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabToc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:contentDescription="@string/chapter_list"
android:src="@drawable/ic_toc"
android:tint="@color/tv_text_default"
android:tooltipText="@string/chapter_list"
app:backgroundTint="@color/background_menu"
app:elevation="2dp"
app:fabSize="mini"
app:pressedTranslationZ="2dp"
tools:ignore="UnusedAttribute" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:contentDescription="@string/to_backstage"
android:src="@drawable/ic_visibility_off"
android:tint="@color/tv_text_default"
android:tooltipText="@string/to_backstage"
app:backgroundTint="@color/background_menu"
app:elevation="2dp"
app:fabSize="mini"
app:pressedTranslationZ="2dp"
tools:ignore="UnusedAttribute" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<View style="@style/Style.Shadow.Bottom" />
<LinearLayout
android:id="@+id/ll_bottom_bg"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/background_menu" android:background="@color/background_menu"
android:padding="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageView <TextView
android:id="@+id/iv_menu" android:id="@+id/tv_pre"
android:layout_width="30dp" android:layout_width="wrap_content"
android:layout_height="30dp" android:layout_height="wrap_content"
android:layout_marginLeft="8dp" android:layout_marginStart="10dp"
android:layout_marginRight="8dp" android:layout_marginEnd="10dp"
android:background="?android:attr/selectableItemBackgroundBorderless" android:background="?android:attr/selectableItemBackgroundBorderless"
android:tooltipText="@string/menu" android:clickable="true"
android:contentDescription="@string/menu" android:focusable="true"
android:src="@drawable/ic_menu" android:paddingTop="10dp"
android:tint="@color/tv_text_default" android:paddingBottom="10dp"
tools:ignore="UnusedAttribute" /> android:text="@string/previous_chapter"
android:textColor="@color/tv_text_default"
android:textSize="14sp" />
<View <View
android:layout_width="0dp" android:layout_width="0dp"
@ -148,18 +96,20 @@
android:layout_height="1dp" android:layout_height="1dp"
android:layout_weight="1" /> android:layout_weight="1" />
<ImageView <TextView
android:id="@+id/iv_other_config" android:id="@+id/tv_next"
android:layout_width="30dp" android:layout_width="wrap_content"
android:layout_height="30dp" android:layout_height="wrap_content"
android:layout_marginLeft="8dp" android:layout_marginStart="10dp"
android:layout_marginRight="8dp" android:layout_marginEnd="10dp"
android:background="?android:attr/selectableItemBackgroundBorderless" android:background="?android:attr/selectableItemBackgroundBorderless"
android:tooltipText="@string/other_aloud_setting" android:clickable="true"
android:contentDescription="@string/other_aloud_setting" android:focusable="true"
android:src="@drawable/ic_settings" android:paddingTop="10dp"
android:tint="@color/tv_text_default" android:paddingBottom="10dp"
tools:ignore="UnusedAttribute" /> android:text="@string/next_chapter"
android:textColor="@color/tv_text_default"
android:textSize="14sp" />
</LinearLayout> </LinearLayout>
@ -168,7 +118,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="8dp"> android:padding="6dp">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:layout_width="30dp" android:layout_width="30dp"
@ -194,11 +144,6 @@
</LinearLayout> </LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.8dp"
android:background="@color/divider" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -235,13 +180,156 @@
<io.legado.app.lib.theme.view.ATESeekBar <io.legado.app.lib.theme.view.ATESeekBar
android:id="@+id/seek_tts_SpeechRate" android:id="@+id/seek_tts_SpeechRate"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="30dp" android:layout_height="wrap_content"
android:layout_marginStart="15dp" android:layout_marginStart="15dp"
android:layout_marginEnd="15dp" android:layout_marginEnd="15dp"
android:max="45" /> android:max="45" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="8dp"
android:baselineAligned="false"
android:orientation="horizontal">
<!--目录按钮-->
<LinearLayout
android:id="@+id/ll_catalog"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/chapter_list"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="7dp">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:contentDescription="@string/chapter_list"
android:src="@drawable/ic_toc"
app:tint="@color/tv_text_default"
tools:ignore="NestedWeights" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
android:text="@string/chapter_list"
android:textColor="@color/tv_text_default"
android:textSize="12sp" />
</LinearLayout>
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
<!--调节按钮-->
<LinearLayout
android:id="@+id/ll_main_menu"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/read_aloud"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="7dp">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:contentDescription="@string/main_menu"
android:src="@drawable/ic_menu"
app:tint="@color/tv_text_default"
tools:ignore="NestedWeights" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
android:text="@string/main_menu"
android:textColor="@color/tv_text_default"
android:textSize="12sp" />
</LinearLayout>
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
<!--界面按钮-->
<LinearLayout
android:id="@+id/ll_to_backstage"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/interface_setting"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="7dp">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:contentDescription="@string/to_backstage"
android:src="@drawable/ic_visibility_off"
app:tint="@color/tv_text_default"
tools:ignore="NestedWeights" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
android:text="@string/to_backstage"
android:textColor="@color/tv_text_default"
android:textSize="12sp" />
</LinearLayout>
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
<!--设置按钮-->
<LinearLayout
android:id="@+id/ll_setting"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/setting"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="7dp">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:contentDescription="@string/aloud_config"
android:src="@drawable/ic_settings"
app:tint="@color/tv_text_default"
tools:ignore="NestedWeights" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="3dp"
android:text="@string/aloud_config"
android:textColor="@color/tv_text_default"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

@ -1,7 +1,25 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<io.legado.app.ui.widget.text.InertiaScrollTextView xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<io.legado.app.ui.widget.text.InertiaScrollTextView
android:id="@+id/text_view" android:id="@+id/text_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:padding="12dp" android:padding="12dp"
android:textIsSelectable="true" /> android:textIsSelectable="true" />
<io.legado.app.ui.widget.text.BadgeView
android:id="@+id/badge_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:visibility="invisible"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -14,7 +14,7 @@
app:contentLayout="@layout/view_tab_layout_min" app:contentLayout="@layout/view_tab_layout_min"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<androidx.viewpager2.widget.ViewPager2 <androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager_bookshelf" android:id="@+id/view_pager_bookshelf"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"

@ -210,7 +210,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="50dp" android:layout_height="wrap_content"
android:baselineAligned="false" android:baselineAligned="false"
android:orientation="horizontal"> android:orientation="horizontal">

@ -628,7 +628,6 @@
<string name="more_menu">更多菜单</string> <string name="more_menu">更多菜单</string>
<string name="reduce"></string> <string name="reduce"></string>
<string name="plus"></string> <string name="plus"></string>
<string name="other_aloud_setting">其它朗读设置</string>
<string name="system_typeface">系统内置字体样式</string> <string name="system_typeface">系统内置字体样式</string>
<string name="delete_book_file">删除源文件</string> <string name="delete_book_file">删除源文件</string>
<string name="default1">预设一</string> <string name="default1">预设一</string>
@ -646,5 +645,7 @@
<string name="bar_elevation">导航栏阴影</string> <string name="bar_elevation">导航栏阴影</string>
<string name="bar_elevation_s">当前阴影大小(elevation): %s</string> <string name="bar_elevation_s">当前阴影大小(elevation): %s</string>
<string name="btn_default_s">默认</string> <string name="btn_default_s">默认</string>
<string name="main_menu">主菜单</string>
<string name="request_permission">点击授予权限</string>
<string name="tip_local_perm_request_storage">阅读需要访问存储卡权限,请点击下方的"授予权限"按钮,或前往“设置”—“应用权限”—打开所需权限。如果授予权限后仍然不正常,请点击右上角的“选择文件夹”,使用系统文件夹选择器。</string>
</resources> </resources>

Loading…
Cancel
Save