pull/47/head
Celeter 5 years ago
commit 3c5051282e
  1. 5
      app/build.gradle
  2. 69
      app/src/debug/google-services .json
  3. 0
      app/src/debug/google-services.json
  4. 28
      app/src/main/AndroidManifest.xml
  5. 2
      app/src/main/java/io/legado/app/data/dao/BookDao.kt
  6. 12
      app/src/main/java/io/legado/app/help/BlurTransformation.kt
  7. 259
      app/src/main/java/io/legado/app/help/ImageLoader.kt
  8. 34
      app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt
  9. 8
      app/src/main/java/io/legado/app/service/AudioPlayService.kt
  10. 2
      app/src/main/java/io/legado/app/service/help/AudioPlay.kt
  11. 108
      app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt
  12. 125
      app/src/main/java/io/legado/app/ui/audio/AudioPlayViewModel.kt
  13. 2
      app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
  14. 42
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  15. 148
      app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt
  16. 2
      app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt
  17. 2
      app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt
  18. 6
      app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt
  19. 7
      app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt
  20. 25
      app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt
  21. 12
      app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt
  22. 2
      app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt
  23. 2
      app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt
  24. 2
      app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt
  25. 2
      app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt
  26. 2
      app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt
  27. 22
      app/src/main/res/layout/activity_audio_play.xml
  28. 4
      app/src/main/res/layout/item_text.xml
  29. 1
      app/src/main/res/values/strings.xml
  30. 2
      build.gradle

@ -37,6 +37,11 @@ android {
versionName version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
project.ext.set("archivesBaseName", name + "_" + version)
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.incremental":"true"]
}
}
}
buildTypes {
release {

@ -1,69 +0,0 @@
{
"project_info": {
"project_number": "453392274790",
"firebase_url": "https://legado-fca69.firebaseio.com",
"project_id": "legado-fca69",
"storage_bucket": "legado-fca69.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:453392274790:android:1d2b1eefbe0e78cff624a7",
"android_client_info": {
"package_name": "io.legado.app"
}
},
"oauth_client": [
{
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyD90mfNLhA7cAzzI9SonpSz5mrF5BnmyJA"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:453392274790:android:c4eac14b1410eec5f624a7",
"android_client_info": {
"package_name": "io.legado.app.debug"
}
},
"oauth_client": [
{
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyD90mfNLhA7cAzzI9SonpSz5mrF5BnmyJA"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

@ -56,12 +56,24 @@
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity android:name=".ui.config.ConfigActivity" />
<activity android:name=".ui.replacerule.ReplaceRuleActivity" />
<activity android:name="io.legado.app.ui.book.search.SearchActivity" />
<activity android:name=".ui.about.AboutActivity" />
<activity android:name=".ui.qrcode.QrCodeActivity" />
<activity android:name=".ui.about.DonateActivity" />
<activity
android:name=".ui.config.ConfigActivity"
android:launchMode="singleTask" />
<activity
android:name=".ui.replacerule.ReplaceRuleActivity"
android:launchMode="singleTask" />
<activity
android:name="io.legado.app.ui.book.search.SearchActivity"
android:launchMode="singleTask" />
<activity
android:name=".ui.about.AboutActivity"
android:launchMode="singleTask" />
<activity
android:name=".ui.qrcode.QrCodeActivity"
android:launchMode="singleTask" />
<activity
android:name=".ui.about.DonateActivity"
android:launchMode="singleTask" />
<activity android:name=".ui.book.info.BookInfoActivity" />
<activity android:name="io.legado.app.ui.book.info.edit.BookInfoEditActivity" />
<activity android:name=".ui.book.source.debug.BookSourceDebugActivity" />
@ -79,7 +91,9 @@
</activity>
<activity android:name=".ui.chapterlist.ChapterListActivity" />
<activity android:name=".ui.rss.read.ReadRssActivity" />
<activity android:name=".ui.audio.AudioPlayActivity" />
<activity
android:name=".ui.audio.AudioPlayActivity"
android:launchMode="singleTask" />
<activity android:name=".ui.explore.ExploreShowActivity" />
<activity android:name=".ui.rss.source.manage.RssSourceActivity" />
<activity android:name=".ui.rss.source.debug.RssSourceDebugActivity" />

@ -53,4 +53,6 @@ interface BookDao {
@Query("delete from books where bookUrl = :bookUrl")
fun delete(bookUrl: String)
@Query("update books set durChapterPos = :pos where bookUrl = :bookUrl")
fun upProgress(bookUrl: String, pos: Int)
}

@ -13,17 +13,23 @@ import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import java.security.MessageDigest
import kotlin.math.min
import kotlin.math.roundToInt
/**
* 模糊
* @radius: 0..25
*/
class BlurTransformation(context: Context, private val radius: Int) : BitmapTransformation() {
private val rs: RenderScript = RenderScript.create(context)
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
val blurredBitmap = toTransform.copy(Bitmap.Config.ARGB_8888, true)
//图片缩小1/2
val width = (min(outWidth, toTransform.width) / 2f).roundToInt()
val height = (min(outHeight, toTransform.height) / 2f).roundToInt()
val blurredBitmap = Bitmap.createScaledBitmap(toTransform, width, height, false);
// Allocate memory for Renderscript to work with
//分配用于渲染脚本的内存
val input = Allocation.createFromBitmap(
@ -40,7 +46,7 @@ class BlurTransformation(context: Context, private val radius: Int) : BitmapTran
script.setInput(input)
// Set the blur radius
//设置模糊半径
//设置模糊半径0..25
script.setRadius(radius.toFloat())
// Start the ScriptIntrinsicBlur

@ -4,264 +4,45 @@ import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.widget.ImageView
import androidx.annotation.DrawableRes
import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.Transformation
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.load.resource.gif.GifDrawable
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.transition.Transition
import java.io.File
object ImageLoader {
fun load(context: Context, url: String?): ImageLoadBuilder<String> {
return ImageLoadBuilder(context, url)
}
fun load(context: Context, @DrawableRes resId: Int?): ImageLoadBuilder<Int> {
return ImageLoadBuilder(context, resId)
}
fun load(context: Context, file: File?): ImageLoadBuilder<File> {
return ImageLoadBuilder(context, file)
}
fun load(context: Context, uri: Uri?): ImageLoadBuilder<Uri> {
return ImageLoadBuilder(context, uri)
}
fun load(context: Context, drawable: Drawable?): ImageLoadBuilder<Drawable> {
return ImageLoadBuilder(context, drawable)
fun load(context: Context, path: String?): RequestBuilder<Drawable> {
if (path?.startsWith("http", true) == true) {
return Glide.with(context).load(path)
}
kotlin.runCatching {
return Glide.with(context).load(File(path))
}
return Glide.with(context).load(path)
}
fun load(context: Context, bitmap: Bitmap?): ImageLoadBuilder<Bitmap> {
return ImageLoadBuilder(context, bitmap)
fun load(context: Context, @DrawableRes resId: Int?): RequestBuilder<Drawable> {
return Glide.with(context).load(resId)
}
fun load(context: Context, bytes: ByteArray?): ImageLoadBuilder<ByteArray> {
return ImageLoadBuilder(context, bytes)
fun load(context: Context, file: File?): RequestBuilder<Drawable> {
return Glide.with(context).load(file)
}
fun with(context: Context): ImageLoadBuilder<Any> {
return ImageLoadBuilder(context)
fun load(context: Context, uri: Uri?): RequestBuilder<Drawable> {
return Glide.with(context).load(uri)
}
fun clear(imageView: ImageView) {
with(imageView.context).clear(imageView)
fun load(context: Context, drawable: Drawable?): RequestBuilder<Drawable> {
return Glide.with(context).load(drawable)
}
class ImageLoadBuilder<S> constructor(context: Context, private var source: S? = null) {
private val manager: RequestManager = Glide.with(context)
private var requestOptions: RequestOptions = RequestOptions()
private var crossFade: Boolean = false
private var noCache: Boolean = false
fun load(source: S): ImageLoadBuilder<S> {
this.source = source
return this
}
fun bitmapTransform(transformation: Transformation<Bitmap>): ImageLoadBuilder<S> {
requestOptions = requestOptions.apply(RequestOptions.bitmapTransform(transformation))
return this
}
fun toRound(corner: Int): ImageLoadBuilder<S> {
requestOptions = requestOptions.transform(RoundedCorners(corner))
return this
}
fun toCropRound(corner: Int): ImageLoadBuilder<S> {
requestOptions = requestOptions.transform(CenterCrop(), RoundedCorners(corner))
return this
}
fun toCircle(): ImageLoadBuilder<S> {
requestOptions = requestOptions.circleCrop()
return this
}
fun centerInside(): ImageLoadBuilder<S> {
requestOptions = requestOptions.centerInside()
return this
}
fun fitCenter(): ImageLoadBuilder<S> {
requestOptions = requestOptions.fitCenter()
return this
}
fun centerCrop(): ImageLoadBuilder<S> {
requestOptions = requestOptions.centerCrop()
return this
}
fun crossFade(): ImageLoadBuilder<S> {
crossFade = true
return this
}
fun noCache(): ImageLoadBuilder<S> {
noCache = true
return this
}
fun placeholder(placeholder: Drawable): ImageLoadBuilder<S> {
requestOptions = requestOptions.placeholder(placeholder)
return this
}
fun placeholder(@DrawableRes resId: Int): ImageLoadBuilder<S> {
requestOptions = requestOptions.placeholder(resId)
return this
}
fun error(drawable: Drawable): ImageLoadBuilder<S> {
requestOptions = requestOptions.error(drawable)
return this
}
fun error(@DrawableRes resId: Int): ImageLoadBuilder<S> {
requestOptions = requestOptions.error(resId)
return this
}
fun override(width: Int, height: Int): ImageLoadBuilder<S> {
requestOptions = requestOptions.override(width, height)
return this
}
fun override(size: Int): ImageLoadBuilder<S> {
requestOptions = requestOptions.override(size)
return this
}
fun clear(imageView: ImageView) {
manager.clear(imageView)
}
fun downloadOnly(target: ImageViewTarget<File>) {
manager.downloadOnly().load(source).into(Target(target))
}
fun setAsDrawable(imageView: ImageView) {
asDrawable().into(imageView)
}
fun setAsDrawable(target: ImageViewTarget<Drawable>) {
asDrawable().into(Target(target))
}
fun setAsBitmap(imageView: ImageView) {
asBitmap().into(imageView)
}
fun setAsBitmap(target: ImageViewTarget<Bitmap>) {
asBitmap().into(Target(target))
}
fun setAsGif(imageView: ImageView) {
asGif().into(imageView)
}
fun setAsGif(target: ImageViewTarget<GifDrawable>) {
asGif().into(Target(target))
}
fun setAsFile(imageView: ImageView) {
asFile().into(imageView)
}
fun setAsFile(target: ImageViewTarget<File>) {
asFile().into(Target(target))
}
private fun asDrawable(): RequestBuilder<Drawable> {
var builder: RequestBuilder<Drawable> = ensureOptions(manager.asDrawable().load(source))
if (crossFade) {
builder = builder.transition(DrawableTransitionOptions.withCrossFade())
}
return builder
}
private fun asBitmap(): RequestBuilder<Bitmap> {
var builder: RequestBuilder<Bitmap> = ensureOptions(manager.asBitmap().load(source))
if (crossFade) {
builder = builder.transition(BitmapTransitionOptions.withCrossFade())
}
return builder
}
private fun asGif(): RequestBuilder<GifDrawable> {
var builder: RequestBuilder<GifDrawable> = ensureOptions(manager.asGif().load(source))
if (crossFade) {
builder = builder.transition(DrawableTransitionOptions.withCrossFade())
}
return builder
}
private fun asFile(): RequestBuilder<File> {
return manager.asFile().load(source)
}
private fun <ResourceType> ensureOptions(builder: RequestBuilder<ResourceType>): RequestBuilder<ResourceType> {
return builder.apply(requestOptions.diskCacheStrategy(if (noCache) DiskCacheStrategy.NONE else DiskCacheStrategy.AUTOMATIC))
}
private inner class Target<R> constructor(private val target: ImageViewTarget<R>) :
com.bumptech.glide.request.target.ImageViewTarget<R>(target.view) {
init {
if (this.target.waitForLayout) {
waitForLayout()
}
}
override fun onResourceReady(resource: R, transition: Transition<in R>?) {
if (!target.onResourceReady(resource)) {
super.onResourceReady(resource, transition)
}
}
override fun setResource(resource: R?) {
target.setResource(resource)
}
}
fun load(context: Context, bitmap: Bitmap?): RequestBuilder<Drawable> {
return Glide.with(context).load(bitmap)
}
abstract class ImageViewTarget<R>(val view: ImageView) {
internal var waitForLayout: Boolean = false
fun waitForLayout(): ImageViewTarget<R> {
waitForLayout = true
return this
}
fun setResource(resource: R?) {
}
fun onResourceReady(resource: R?): Boolean {
return false
}
fun load(context: Context, bytes: ByteArray?): RequestBuilder<Drawable> {
return Glide.with(context).load(bytes)
}
}

@ -4,11 +4,18 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.view.KeyEvent
import io.legado.app.App
import io.legado.app.constant.Bus
import io.legado.app.data.entities.Book
import io.legado.app.help.ActivityHelp
import io.legado.app.ui.audio.AudioPlayActivity
import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.utils.postEvent
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
@ -33,15 +40,24 @@ class MediaButtonReceiver : BroadcastReceiver() {
}
private fun readAloud(context: Context) {
if (ActivityHelp.isExist(AudioPlayActivity::class.java)) {
postEvent(Bus.AUDIO_PLAY_BUTTON, true)
} else if (!ActivityHelp.isExist(ReadBookActivity::class.java)) {
val intent = Intent(context, ReadBookActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra("readAloud", true)
context.startActivity(intent)
} else {
postEvent(Bus.READ_ALOUD_BUTTON, true)
when {
ActivityHelp.isExist(AudioPlayActivity::class.java) ->
postEvent(Bus.AUDIO_PLAY_BUTTON, true)
ActivityHelp.isExist(ReadBookActivity::class.java) ->
postEvent(Bus.READ_ALOUD_BUTTON, true)
else -> {
GlobalScope.launch(Main) {
val lastBook: Book? = withContext(IO) {
App.db.bookDao().lastReadBook
}
lastBook?.let {
val intent = Intent(context, ReadBookActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra("readAloud", true)
context.startActivity(intent)
}
}
}
}
}
}

@ -24,6 +24,7 @@ import io.legado.app.help.IntentHelp
import io.legado.app.help.MediaHelp
import io.legado.app.receiver.MediaButtonReceiver
import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.utils.LogUtils
import io.legado.app.utils.postEvent
import kotlinx.coroutines.launch
import org.jetbrains.anko.toast
@ -73,7 +74,7 @@ class AudioPlayService : BaseService(),
Action.play -> {
title = intent.getStringExtra("title") ?: ""
subtitle = intent.getStringExtra("subtitle") ?: ""
position = intent.getIntExtra("pageIndex", 0)
position = intent.getIntExtra("position", 0)
play(intent.getStringExtra("url"))
}
Action.pause -> pause(true)
@ -107,8 +108,10 @@ class AudioPlayService : BaseService(),
mediaPlayer.setDataSource(url)
mediaPlayer.prepareAsync()
} catch (e: Exception) {
LogUtils.d("AudioPlayService", e.localizedMessage + " " + url)
launch {
toast(e.localizedMessage + " " + url)
stopSelf()
}
}
}
@ -153,6 +156,9 @@ class AudioPlayService : BaseService(),
}
override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
launch {
toast("error: $what $extra")
}
return true
}

@ -13,7 +13,7 @@ object AudioPlay {
intent.putExtra("title", title)
intent.putExtra("subtitle", subtitle)
intent.putExtra("url", url)
intent.putExtra("dataKey", position)
intent.putExtra("position", position)
context.startService(intent)
}

@ -1,23 +1,38 @@
package io.legado.app.ui.audio
import android.app.Activity
import android.content.Intent
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.widget.SeekBar
import androidx.lifecycle.Observer
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.request.RequestOptions
import io.legado.app.BuildConfig
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.Bus
import io.legado.app.constant.Status
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.help.BlurTransformation
import io.legado.app.help.ImageLoader
import io.legado.app.help.storage.Backup
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.noButton
import io.legado.app.lib.dialogs.okButton
import io.legado.app.service.help.AudioPlay
import io.legado.app.ui.chapterlist.ChapterListActivity
import io.legado.app.ui.main.MainActivity
import io.legado.app.utils.applyTint
import io.legado.app.utils.getViewModel
import io.legado.app.utils.observeEvent
import kotlinx.android.synthetic.main.activity_audio_play.*
import kotlinx.android.synthetic.main.view_title_bar.*
import org.apache.commons.lang3.time.DateFormatUtils
import org.jetbrains.anko.sdk27.listeners.onClick
import org.jetbrains.anko.sdk27.listeners.onLongClick
import org.jetbrains.anko.startActivity
import org.jetbrains.anko.startActivityForResult
class AudioPlayActivity : VMBaseActivity<AudioPlayViewModel>(R.layout.activity_audio_play),
AudioPlayViewModel.CallBack {
@ -25,13 +40,15 @@ class AudioPlayActivity : VMBaseActivity<AudioPlayViewModel>(R.layout.activity_a
override val viewModel: AudioPlayViewModel
get() = getViewModel(AudioPlayViewModel::class.java)
private var requestCodeChapter = 8461
private var adjustProgress = false
private var status = Status.STOP
override fun onActivityCreated(savedInstanceState: Bundle?) {
setSupportActionBar(toolbar)
viewModel.callBack = this
viewModel.bookData.observe(this, Observer { upView(it) })
viewModel.titleData.observe(this, Observer { title_bar.title = it })
viewModel.coverData.observe(this, Observer { upCover(it) })
viewModel.initData(intent)
initView()
}
@ -45,14 +62,14 @@ class AudioPlayActivity : VMBaseActivity<AudioPlayViewModel>(R.layout.activity_a
true
}
iv_skip_next.onClick {
viewModel.moveToNext()
}
iv_skip_previous.onClick {
viewModel.moveToPrev()
}
player_progress.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
tv_dur_time.text = DateFormatUtils.format(progress.toLong(), "mm:ss")
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
@ -64,43 +81,89 @@ class AudioPlayActivity : VMBaseActivity<AudioPlayViewModel>(R.layout.activity_a
AudioPlay.adjustProgress(this@AudioPlayActivity, player_progress.progress)
}
})
iv_chapter.onClick {
viewModel.book?.let {
startActivityForResult<ChapterListActivity>(
requestCodeChapter,
Pair("bookUrl", it.bookUrl)
)
}
}
}
private fun upView(book: Book) {
actionBar?.title = book.name
ImageLoader.load(this, book.getDisplayCover())
private fun upCover(path: String) {
ImageLoader.load(this, path)
.placeholder(R.drawable.image_cover_default)
.error(R.drawable.image_cover_default)
.centerCrop()
.setAsDrawable(iv_cover)
ImageLoader.load(this, book.getDisplayCover())
.placeholder(R.drawable.image_cover_default)
.error(R.drawable.image_cover_default)
.into(iv_cover)
ImageLoader.load(this, path)
.thumbnail(defaultCover())
.centerCrop()
.bitmapTransform(BlurTransformation(this, 25))
.setAsDrawable(iv_bg)
.apply(RequestOptions.bitmapTransform(BlurTransformation(this, 25)))
.into(iv_bg)
}
private fun defaultCover(): RequestBuilder<Drawable> {
return ImageLoader.load(this, R.drawable.image_cover_default)
.apply(RequestOptions.bitmapTransform(BlurTransformation(this, 25)))
}
private fun playButton() {
when (status) {
Status.PLAY -> AudioPlay.pause(this)
Status.PAUSE -> AudioPlay.resume(this)
else -> viewModel.bookData.value?.let {
viewModel.loadContent(it, viewModel.durChapterIndex)
}
else -> viewModel.loadContent(viewModel.durChapterIndex)
}
}
override fun contentLoadFinish(bookChapter: BookChapter, content: String) {
AudioPlay.play(
this,
viewModel.bookData.value?.name,
viewModel.book?.name,
bookChapter.title,
content,
viewModel.durPageIndex
)
viewModel.bookData.value?.let {
viewModel.loadContent(it, viewModel.durChapterIndex + 1)
viewModel.loadContent(viewModel.durChapterIndex + 1)
}
override fun finish() {
viewModel.book?.let {
if (!viewModel.inBookshelf) {
this.alert(title = getString(R.string.add_to_shelf)) {
message = getString(R.string.check_add_bookshelf, it.name)
okButton { viewModel.inBookshelf = true }
noButton { viewModel.removeFromBookshelf { super.finish() } }
}.show().applyTint()
} else {
if (status == Status.PLAY) {
startActivity<MainActivity>()
} else {
super.finish()
}
}
} ?: super.finish()
}
override fun onDestroy() {
super.onDestroy()
AudioPlay.stop(this)
if (!BuildConfig.DEBUG) {
Backup.autoBackup()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
requestCodeChapter -> data?.getIntExtra("index", viewModel.durChapterIndex)?.let {
if (it != viewModel.durChapterIndex) {
viewModel.loadContent(it)
}
}
}
}
}
@ -120,10 +183,15 @@ class AudioPlayActivity : VMBaseActivity<AudioPlayViewModel>(R.layout.activity_a
}
}
observeEvent<Int>(Bus.AUDIO_PROGRESS) {
viewModel.durPageIndex = it
if (!adjustProgress) player_progress.progress = it
tv_dur_time.text = DateFormatUtils.format(it.toLong(), "mm:ss")
viewModel.saveProgress()
}
observeEvent<Int>(Bus.AUDIO_SIZE) {
player_progress.max = it
tv_all_time.text = DateFormatUtils.format(it.toLong(), "mm:ss")
}
}
}

@ -6,7 +6,6 @@ import androidx.lifecycle.MutableLiveData
import io.legado.app.App
import io.legado.app.R
import io.legado.app.base.BaseViewModel
import io.legado.app.constant.BookType
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.help.BookHelp
@ -16,13 +15,14 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class AudioPlayViewModel(application: Application) : BaseViewModel(application) {
var titleData = MutableLiveData<String>()
var coverData = MutableLiveData<String>()
var book: Book? = null
var inBookshelf = false
var bookData = MutableLiveData<Book>()
var chapterSize = 0
private var chapterSize = 0
var callBack: CallBack? = null
var durChapterIndex = 0
var durPageIndex = 0
var isLocalBook = true
var webBook: WebBook? = null
private val loadingChapters = arrayListOf<Int>()
@ -30,16 +30,16 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
execute {
inBookshelf = intent.getBooleanExtra("inBookshelf", true)
val bookUrl = intent.getStringExtra("bookUrl")
val book = if (!bookUrl.isNullOrEmpty()) {
book = if (!bookUrl.isNullOrEmpty()) {
App.db.bookDao().getBook(bookUrl)
} else {
App.db.bookDao().lastReadBook
}
book?.let {
book?.let { book ->
titleData.postValue(book.name)
coverData.postValue(book.getDisplayCover())
durChapterIndex = book.durChapterIndex
durPageIndex = book.durChapterPos
isLocalBook = book.origin == BookType.local
bookData.postValue(book)
App.db.bookSourceDao().getBookSource(book.origin)?.let {
webBook = WebBook(it)
}
@ -57,7 +57,7 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
chapterSize = count
}
}
saveRead(book)
saveRead()
}
}
@ -96,36 +96,40 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
}
}
fun loadContent(book: Book, index: Int) {
if (addLoading(index)) {
execute {
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter ->
BookHelp.getContent(book, chapter)?.let {
contentLoadFinish(chapter, it)
removeLoading(chapter.index)
} ?: download(book, chapter)
} ?: removeLoading(index)
}.onError {
removeLoading(index)
fun loadContent(index: Int) {
book?.let { book ->
if (addLoading(index)) {
execute {
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter ->
BookHelp.getContent(book, chapter)?.let {
contentLoadFinish(chapter, it)
removeLoading(chapter.index)
} ?: download(chapter)
} ?: removeLoading(index)
}.onError {
removeLoading(index)
}
}
}
}
private fun download(book: Book, chapter: BookChapter) {
webBook?.getContent(book, chapter, scope = this)
?.onSuccess(Dispatchers.IO) { content ->
if (content.isNullOrEmpty()) {
contentLoadFinish(chapter, context.getString(R.string.content_empty))
removeLoading(chapter.index)
} else {
BookHelp.saveContent(book, chapter, content)
contentLoadFinish(chapter, content)
private fun download(chapter: BookChapter) {
book?.let { book ->
webBook?.getContent(book, chapter, scope = this)
?.onSuccess(Dispatchers.IO) { content ->
if (content.isNullOrEmpty()) {
contentLoadFinish(chapter, context.getString(R.string.content_empty))
removeLoading(chapter.index)
} else {
BookHelp.saveContent(book, chapter, content)
contentLoadFinish(chapter, content)
removeLoading(chapter.index)
}
}?.onError {
contentLoadFinish(chapter, it.localizedMessage)
removeLoading(chapter.index)
}
}?.onError {
contentLoadFinish(chapter, it.localizedMessage)
removeLoading(chapter.index)
}
}
}
private fun addLoading(index: Int): Boolean {
@ -148,23 +152,23 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
}
}
fun changeTo(book: Book) {
fun changeTo(book1: Book) {
execute {
bookData.value?.let {
book?.let {
App.db.bookDao().delete(it.bookUrl)
}
withContext(Dispatchers.Main) {
}
App.db.bookDao().insert(book)
bookData.postValue(book)
App.db.bookSourceDao().getBookSource(book.origin)?.let {
App.db.bookDao().insert(book1)
book = book1
App.db.bookSourceDao().getBookSource(book1.origin)?.let {
webBook = WebBook(it)
}
if (book.tocUrl.isEmpty()) {
loadBookInfo(book) { upChangeDurChapterIndex(book, it) }
if (book1.tocUrl.isEmpty()) {
loadBookInfo(book1) { upChangeDurChapterIndex(book1, it) }
} else {
loadChapterList(book) { upChangeDurChapterIndex(book, it) }
loadChapterList(book1) { upChangeDurChapterIndex(book1, it) }
}
}
}
@ -184,20 +188,29 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
}
}
fun moveToPrev() {
if (durChapterIndex > 0) {
durChapterIndex--
durPageIndex = 0
book?.durChapterIndex = durChapterIndex
saveRead()
loadContent(durChapterIndex)
}
}
fun moveToNext() {
if (durChapterIndex < chapterSize - 1) {
durChapterIndex++
bookData.value?.let {
it.durChapterIndex = durChapterIndex
saveRead(it)
loadContent(it, durChapterIndex)
}
durPageIndex = 0
book?.durChapterIndex = durChapterIndex
saveRead()
loadContent(durChapterIndex)
} else {
AudioPlay.stop(context)
}
}
fun saveRead(book: Book? = bookData.value) {
private fun saveRead() {
execute {
book?.let { book ->
book.lastCheckCount = 0
@ -209,6 +222,24 @@ class AudioPlayViewModel(application: Application) : BaseViewModel(application)
}
}
fun saveProgress() {
execute {
book?.let {
App.db.bookDao().upProgress(it.bookUrl, durPageIndex)
}
}
}
fun removeFromBookshelf(success: (() -> Unit)?) {
execute {
book?.let {
App.db.bookDao().delete(it.bookUrl)
}
}.onSuccess {
success?.invoke()
}
}
interface CallBack {
fun contentLoadFinish(bookChapter: BookChapter, content: String)
}

@ -89,7 +89,7 @@ class BookInfoActivity : VMBaseActivity<BookInfoViewModel>(R.layout.activity_boo
.placeholder(R.drawable.image_cover_default)
.error(R.drawable.image_cover_default)
.centerCrop()
.setAsDrawable(iv_cover)
.into(iv_cover)
}
val kinds = book.getKindList()
if (kinds.isEmpty()) {

@ -64,6 +64,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
override val viewModel: ReadBookViewModel
get() = getViewModel(ReadBookViewModel::class.java)
private val requestCodeChapterList = 568
private val requestCodeEditSource = 111
private var timeElectricityReceiver: TimeElectricityReceiver? = null
override var readAloudStatus = Status.STOP
@ -73,7 +74,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
setSupportActionBar(toolbar)
initView()
viewModel.callBack = this
viewModel.bookData.observe(this, Observer { title_bar.title = it.name })
viewModel.titleDate.observe(this, Observer { title_bar.title = it })
viewModel.initData(intent)
}
@ -140,12 +141,12 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
when (item.itemId) {
R.id.menu_change_source -> {
read_menu.runMenuOut()
viewModel.bookData.value?.let {
viewModel.book?.let {
ChangeSourceDialog.show(supportFragmentManager, it.name, it.author)
}
}
R.id.menu_refresh -> {
viewModel.bookData.value?.let {
viewModel.book?.let {
viewModel.curTextChapter = null
page_view.upContent()
viewModel.refreshContent(it)
@ -198,7 +199,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> {
page_view.snackbar("转到后台", "确定") {
page_view.snackbar(R.string.to_backstage, R.string.ok) {
startActivity<MainActivity>()
}
return true
@ -254,20 +255,16 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
* 加载章节内容
*/
override fun loadContent() {
viewModel.bookData.value?.let {
viewModel.loadContent(it, viewModel.durChapterIndex)
viewModel.loadContent(it, viewModel.durChapterIndex + 1)
viewModel.loadContent(it, viewModel.durChapterIndex - 1)
}
viewModel.loadContent(viewModel.durChapterIndex)
viewModel.loadContent(viewModel.durChapterIndex + 1)
viewModel.loadContent(viewModel.durChapterIndex - 1)
}
/**
* 加载章节内容, index章节序号
*/
override fun loadContent(index: Int) {
viewModel.bookData.value?.let {
viewModel.loadContent(it, index)
}
viewModel.loadContent(index)
}
/**
@ -336,10 +333,10 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
}
override val curOrigin: String?
get() = viewModel.bookData.value?.origin
get() = viewModel.book?.origin
override val oldBook: Book?
get() = viewModel.bookData.value
get() = viewModel.book
override fun changeTo(book: Book) {
viewModel.changeTo(book)
@ -435,8 +432,11 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
}
override fun openChapterList() {
viewModel.bookData.value?.let {
startActivity<ChapterListActivity>(Pair("bookUrl", it.bookUrl))
viewModel.book?.let {
startActivityForResult<ChapterListActivity>(
requestCodeChapterList,
Pair("bookUrl", it.bookUrl)
)
}
}
@ -471,7 +471,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
* 朗读
*/
private fun readAloud(play: Boolean = true) {
val book = viewModel.bookData.value
val book = viewModel.book
val textChapter = viewModel.curTextChapter
if (book != null && textChapter != null) {
val key = IntentDataHelp.putData(textChapter)
@ -510,12 +510,16 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
requestCodeEditSource -> viewModel.upBookSource()
requestCodeChapterList ->
data?.getIntExtra("index", viewModel.durChapterIndex)?.let {
viewModel.openChapter(it)
}
}
}
}
override fun finish() {
viewModel.bookData.value?.let {
viewModel.book?.let {
if (!viewModel.inBookshelf) {
this.alert(title = getString(R.string.add_to_shelf)) {
message = getString(R.string.check_add_bookshelf, it.name)
@ -552,7 +556,7 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
observeEvent<String>(Bus.TIME_CHANGED) { page_view.upTime() }
observeEvent<Int>(Bus.BATTERY_CHANGED) { page_view.upBattery(it) }
observeEvent<BookChapter>(Bus.OPEN_CHAPTER) {
viewModel.openChapter(it)
viewModel.openChapter(it.index)
page_view.upContent()
}
observeEvent<Boolean>(Bus.READ_ALOUD_BUTTON) {

@ -21,8 +21,9 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ReadBookViewModel(application: Application) : BaseViewModel(application) {
var titleDate = MutableLiveData<String>()
var book: Book? = null
var inBookshelf = false
var bookData = MutableLiveData<Book>()
var chapterSize = 0
var callBack: CallBack? = null
var durChapterIndex = 0
@ -38,22 +39,23 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
execute {
inBookshelf = intent.getBooleanExtra("inBookshelf", true)
IntentDataHelp.getData<Book>(intent.getStringExtra("key"))?.let {
setBook(it)
initBook(it)
} ?: intent.getStringExtra("bookUrl")?.let {
App.db.bookDao().getBook(it)?.let { book ->
setBook(book)
initBook(book)
}
} ?: App.db.bookDao().lastReadBook?.let {
setBook(it)
initBook(it)
}
}
}
private fun setBook(book: Book) {
private fun initBook(book: Book) {
this.book = book
titleDate.postValue(book.name)
durChapterIndex = book.durChapterIndex
durPageIndex = book.durChapterPos
isLocalBook = book.origin == BookType.local
bookData.postValue(book)
App.db.bookSourceDao().getBookSource(book.origin)?.let {
webBook = WebBook(it)
}
@ -72,7 +74,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
callBack?.loadContent()
}
if (inBookshelf) {
saveRead(book)
saveRead()
}
}
@ -117,19 +119,17 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
prevTextChapter = curTextChapter
curTextChapter = nextTextChapter
nextTextChapter = null
bookData.value?.let {
book?.let {
if (curTextChapter == null) {
loadContent(it, durChapterIndex)
loadContent(durChapterIndex)
} else if (upContent) {
callBack?.upContent()
}
loadContent(it, durChapterIndex.plus(1))
loadContent(durChapterIndex.plus(1))
launch(IO) {
for (i in 2..10) {
delay(100)
bookData.value?.let { book ->
download(book, durChapterIndex + i)
}
download(durChapterIndex + i)
}
}
}
@ -140,70 +140,74 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
nextTextChapter = curTextChapter
curTextChapter = prevTextChapter
prevTextChapter = null
bookData.value?.let {
book?.let {
if (curTextChapter == null) {
loadContent(it, durChapterIndex)
loadContent(durChapterIndex)
} else if (upContent) {
callBack?.upContent()
}
loadContent(it, durChapterIndex.minus(1))
loadContent(durChapterIndex.minus(1))
launch(IO) {
for (i in -5..-2) {
delay(100)
bookData.value?.let { book ->
download(book, durChapterIndex + i)
}
download(durChapterIndex + i)
}
}
}
}
fun loadContent(book: Book, index: Int) {
if (addLoading(index)) {
execute {
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter ->
BookHelp.getContent(book, chapter)?.let {
contentLoadFinish(chapter, it)
removeLoading(chapter.index)
} ?: download(book, chapter)
} ?: removeLoading(index)
}.onError {
removeLoading(index)
fun loadContent(index: Int) {
book?.let { book ->
if (addLoading(index)) {
execute {
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter ->
BookHelp.getContent(book, chapter)?.let {
contentLoadFinish(chapter, it)
removeLoading(chapter.index)
} ?: download(chapter)
} ?: removeLoading(index)
}.onError {
removeLoading(index)
}
}
}
}
private fun download(book: Book, index: Int) {
if (addLoading(index)) {
execute {
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter ->
if (BookHelp.hasContent(book, chapter)) {
removeLoading(chapter.index)
} else {
download(book, chapter)
}
} ?: removeLoading(index)
}.onError {
removeLoading(index)
private fun download(index: Int) {
book?.let { book ->
if (addLoading(index)) {
execute {
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter ->
if (BookHelp.hasContent(book, chapter)) {
removeLoading(chapter.index)
} else {
download(chapter)
}
} ?: removeLoading(index)
}.onError {
removeLoading(index)
}
}
}
}
private fun download(book: Book, chapter: BookChapter) {
webBook?.getContent(book, chapter, scope = this)
?.onSuccess(IO) { content ->
if (content.isNullOrEmpty()) {
contentLoadFinish(chapter, context.getString(R.string.content_empty))
removeLoading(chapter.index)
} else {
BookHelp.saveContent(book, chapter, content)
contentLoadFinish(chapter, content)
private fun download(chapter: BookChapter) {
book?.let { book ->
webBook?.getContent(book, chapter, scope = this)
?.onSuccess(IO) { content ->
if (content.isNullOrEmpty()) {
contentLoadFinish(chapter, context.getString(R.string.content_empty))
removeLoading(chapter.index)
} else {
BookHelp.saveContent(book, chapter, content)
contentLoadFinish(chapter, content)
removeLoading(chapter.index)
}
}?.onError {
contentLoadFinish(chapter, it.localizedMessage)
removeLoading(chapter.index)
}
}?.onError {
contentLoadFinish(chapter, it.localizedMessage)
removeLoading(chapter.index)
}
}
}
private fun addLoading(index: Int): Boolean {
@ -225,19 +229,19 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
if (chapter.index in durChapterIndex - 1..durChapterIndex + 1) {
val c = BookHelp.disposeContent(
chapter.title,
bookData.value!!.name,
book!!.name,
webBook?.bookSource?.bookSourceUrl,
content,
bookData.value!!.useReplaceRule
book!!.useReplaceRule
)
callBack?.contentLoadFinish(chapter, c)
}
}
}
fun changeTo(book: Book) {
fun changeTo(book1: Book) {
execute {
bookData.value?.let {
book?.let {
App.db.bookDao().delete(it.bookUrl)
}
prevTextChapter = null
@ -246,15 +250,15 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
withContext(Main) {
callBack?.upContent()
}
App.db.bookDao().insert(book)
bookData.postValue(book)
App.db.bookSourceDao().getBookSource(book.origin)?.let {
App.db.bookDao().insert(book1)
book = book1
App.db.bookSourceDao().getBookSource(book1.origin)?.let {
webBook = WebBook(it)
}
if (book.tocUrl.isEmpty()) {
loadBookInfo(book) { upChangeDurChapterIndex(book, it) }
if (book1.tocUrl.isEmpty()) {
loadBookInfo(book1) { upChangeDurChapterIndex(book1, it) }
} else {
loadChapterList(book) { upChangeDurChapterIndex(book, it) }
loadChapterList(book1) { upChangeDurChapterIndex(book1, it) }
}
}
}
@ -279,19 +283,19 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
}
}
fun openChapter(chapter: BookChapter) {
fun openChapter(index: Int) {
prevTextChapter = null
curTextChapter = null
nextTextChapter = null
if (chapter.index != durChapterIndex) {
durChapterIndex = chapter.index
if (index != durChapterIndex) {
durChapterIndex = index
durPageIndex = 0
}
saveRead()
callBack?.loadContent()
}
fun saveRead(book: Book? = bookData.value) {
fun saveRead() {
execute {
book?.let { book ->
book.lastCheckCount = 0
@ -308,7 +312,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
fun removeFromBookshelf(success: (() -> Unit)?) {
execute {
bookData.value?.let {
book?.let {
App.db.bookDao().delete(it.bookUrl)
}
}.onSuccess {
@ -318,7 +322,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
fun upBookSource() {
execute {
bookData.value?.let { book ->
book?.let { book ->
App.db.bookSourceDao().getBookSource(book.origin)?.let {
webBook = WebBook(it)
}
@ -330,7 +334,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
execute {
App.db.bookChapterDao().getChapter(book.bookUrl, durChapterIndex)?.let { chapter ->
BookHelp.delContent(book, chapter)
loadContent(book, durChapterIndex)
loadContent(durChapterIndex)
}
}
}

@ -153,7 +153,7 @@ class BgTextConfigDialog : DialogFragment() {
with(holder.itemView) {
ImageLoader.load(context, context.assets.open("bg/$item").readBytes())
.centerCrop()
.setAsBitmap(iv_bg)
.into(iv_bg)
tv_name.text = item.substringBeforeLast(".")
this.onClick {
ReadBookConfig.getConfig().setBg(1, item)

@ -248,7 +248,7 @@ class ReadStyleDialog : DialogFragment() {
}
ReadBookConfig.getConfig(i).apply {
when (bgType()) {
2 -> ImageLoader.load(requireContext(), bgStr()).centerCrop().setAsDrawable(iv)
2 -> ImageLoader.load(requireContext(), bgStr()).centerCrop().into(iv)
else -> iv.setImageDrawable(bgDrawable(100, 150))
}
}

@ -72,7 +72,7 @@ class SearchAdapter(context: Context, val callBack: CallBack) :
.placeholder(R.drawable.image_cover_default)
.error(R.drawable.image_cover_default)
.centerCrop()
.setAsDrawable(iv_cover)
.into(iv_cover)
}
onClick {
callBack.showBookInfo(searchBook.name, searchBook.author)
@ -89,7 +89,7 @@ class SearchAdapter(context: Context, val callBack: CallBack) :
.placeholder(R.drawable.image_cover_default)
.error(R.drawable.image_cover_default)
.centerCrop()
.setAsDrawable(iv_cover)
.into(iv_cover)
}
3 -> {
val kinds = searchBook.getKindList()
@ -136,6 +136,8 @@ class SearchAdapter(context: Context, val callBack: CallBack) :
}
5 -> tv_introduce.text =
context.getString(R.string.intro_show, searchBook.intro)
else -> {
}
}
}
}

@ -27,9 +27,10 @@ class ChapterListActivity : VMBaseActivity<ChapterListViewModel>(R.layout.activi
override fun onActivityCreated(savedInstanceState: Bundle?) {
setSupportActionBar(toolbar)
viewModel.bookUrl = intent.getStringExtra("bookUrl")
viewModel.loadBook()
view_pager.adapter = TabFragmentPageAdapter(supportFragmentManager)
tab_layout.setupWithViewPager(view_pager)
viewModel.loadBook {
view_pager.adapter = TabFragmentPageAdapter(supportFragmentManager)
tab_layout.setupWithViewPager(view_pager)
}
}
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {

@ -1,5 +1,7 @@
package io.legado.app.ui.chapterlist
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.LinearLayout
@ -9,11 +11,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.App
import io.legado.app.R
import io.legado.app.base.VMBaseFragment
import io.legado.app.constant.Bus
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.utils.getViewModelOfActivity
import io.legado.app.utils.postEvent
import kotlinx.android.synthetic.main.fragment_chapter_list.*
import org.jetbrains.anko.sdk27.listeners.onClick
@ -45,14 +45,13 @@ class ChapterListFragment : VMBaseFragment<ChapterListViewModel>(R.layout.fragme
}
private fun initData() {
viewModel.bookDate.observe(viewLifecycleOwner, Observer {
loadBookFinish(it)
})
viewModel.bookUrl?.let { bookUrl ->
App.db.bookChapterDao().observeByBook(bookUrl).observe(viewLifecycleOwner, Observer {
adapter.setItems(it)
viewModel.bookDate.value?.let { book ->
loadBookFinish(book)
viewModel.book?.let {
durChapterIndex = it.durChapterIndex
tv_current_chapter_info.text = it.durChapterTitle
recycler_view.scrollToPosition(durChapterIndex)
}
})
}
@ -66,28 +65,22 @@ class ChapterListFragment : VMBaseFragment<ChapterListViewModel>(R.layout.fragme
}
}
tv_current_chapter_info.onClick {
viewModel.bookDate.value?.let {
viewModel.book?.let {
recycler_view.scrollToPosition(it.durChapterIndex)
}
}
}
private fun loadBookFinish(book: Book) {
durChapterIndex = book.durChapterIndex
tv_current_chapter_info.text = book.durChapterTitle
recycler_view.scrollToPosition(durChapterIndex)
}
override fun durChapterIndex(): Int {
return durChapterIndex
}
override fun openChapter(bookChapter: BookChapter) {
postEvent(Bus.OPEN_CHAPTER, bookChapter)
activity?.setResult(RESULT_OK, Intent().putExtra("index", bookChapter.index))
activity?.finish()
}
override fun book(): Book? {
return viewModel.bookDate.value
return viewModel.book
}
}

@ -2,23 +2,21 @@ package io.legado.app.ui.chapterlist
import android.app.Application
import androidx.lifecycle.MutableLiveData
import io.legado.app.App
import io.legado.app.base.BaseViewModel
import io.legado.app.data.entities.Book
class ChapterListViewModel(application: Application) : BaseViewModel(application) {
var bookDate = MutableLiveData<Book>()
var bookUrl: String? = null
var book: Book? = null
fun loadBook() {
fun loadBook(success: () -> Unit) {
execute {
bookUrl?.let {
App.db.bookDao().getBook(it)?.let { book ->
bookDate.postValue(book)
}
book = App.db.bookDao().getBook(it)
}
}.onSuccess {
success()
}
}
}

@ -63,7 +63,7 @@ class ExploreShowAdapter(context: Context, val callBack: CallBack) :
.placeholder(R.drawable.image_cover_default)
.error(R.drawable.image_cover_default)
.centerCrop()
.setAsDrawable(iv_cover)
.into(iv_cover)
}
onClick {
callBack.showBookInfo(item.toBook())

@ -30,7 +30,7 @@ class BooksAdapter(context: Context, private val callBack: CallBack) :
.placeholder(R.drawable.image_cover_default)
.error(R.drawable.image_cover_default)
.centerCrop()
.setAsDrawable(iv_cover)
.into(iv_cover)
}
onClick { callBack.open(item) }
onLongClick {

@ -73,6 +73,7 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca
kindList.map { kind ->
val tv = LayoutInflater.from(context)
.inflate(R.layout.item_text, gl_child, false)
gl_child.addView(tv)
tv.text_view.text = kind.title
tv.text_view.onClick {
kind.url?.let { kindUrl ->
@ -83,7 +84,6 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca
)
}
}
gl_child.addView(tv)
}
}
}.onFinally {

@ -19,7 +19,7 @@ class RssAdapter(context: Context, val callBack: CallBack) :
.centerCrop()
.placeholder(R.drawable.image_rss)
.error(R.drawable.image_rss)
.setAsBitmap(iv_icon)
.into(iv_icon)
onClick { callBack.openRss(item) }
}
}

@ -28,7 +28,7 @@ class RssArticlesAdapter(context: Context, val callBack: CallBack) :
} else {
image_view.visible()
ImageLoader.load(context, item.image)
.setAsBitmap(image_view)
.into(image_view)
}
if (item.read) {
tv_title.textColorResource = R.color.tv_text_summary

@ -33,10 +33,8 @@
android:id="@+id/iv_cover"
android:layout_width="260dp"
android:layout_height="260dp"
android:layout_gravity="center"
android:contentDescription="@string/img_cover"
android:scaleType="centerCrop"
android:src="@drawable/image_cover_default"
app:civ_border_width="2dp"
app:civ_border_color="@color/colorAccent"
app:layout_constraintBottom_toTopOf="@+id/ll_player_progress"
@ -50,27 +48,33 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
app:layout_constraintBottom_toTopOf="@+id/ll_play_menu">
<TextView
android:id="@+id/tv_dur_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="RtlSymmetry" />
android:text="00:00"
android:textColor="@color/md_white_1000"
tools:ignore="HardcodedText,RtlSymmetry" />
<io.legado.app.lib.theme.view.ATESeekBar
android:id="@+id/player_progress"
android:layout_width="0dp"
android:layout_height="25dp"
android:layout_gravity="center_vertical"
android:layout_weight="1" />
android:layout_weight="1"
android:progressBackgroundTint="@color/md_dark_secondary" />
<TextView
android:id="@+id/tv_all_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
android:text="00:00"
android:textColor="@color/md_white_1000"
tools:ignore="HardcodedText" />
</LinearLayout>
@ -78,8 +82,8 @@
android:id="@+id/ll_play_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent">

@ -6,12 +6,10 @@
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:background="@drawable/selector_fillet_btn_bg"
android:clickable="true"
android:ellipsize="end"
android:focusable="true"
android:gravity="center"
android:padding="5dp"
android:singleLine="true"
android:maxLines="1"
android:textColor="@color/tv_text_default"
android:textSize="14sp"
tools:ignore="UnusedAttribute" />

@ -556,5 +556,6 @@
<string name="book_type">类型:</string>
<string name="book_type_text">文本</string>
<string name="book_type_audio">音频</string>
<string name="to_backstage">转到后台</string>
</resources>

@ -9,7 +9,7 @@ buildscript {
maven { url 'https://plugins.gradle.org/m2/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3'
classpath 'com.google.gms:google-services:4.3.2'

Loading…
Cancel
Save