Reduce stutter when entering Browse screen (#6435)
* More coil * ExtensionController: Drop first text change event * Browse-Source: Remove unnecessary load * ExtensionPresenter: Increase debounce timeout To avoid heavy list reload during first enter animation
This commit is contained in:
parent
b8f7653fb2
commit
78a261f5d3
10 changed files with 28 additions and 21 deletions
|
@ -1,5 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.extension.model
|
package eu.kanade.tachiyomi.extension.model
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
|
||||||
sealed class Extension {
|
sealed class Extension {
|
||||||
|
@ -20,6 +21,7 @@ sealed class Extension {
|
||||||
override val isNsfw: Boolean,
|
override val isNsfw: Boolean,
|
||||||
val pkgFactory: String?,
|
val pkgFactory: String?,
|
||||||
val sources: List<Source>,
|
val sources: List<Source>,
|
||||||
|
val icon: Drawable?,
|
||||||
val hasUpdate: Boolean = false,
|
val hasUpdate: Boolean = false,
|
||||||
val isObsolete: Boolean = false,
|
val isObsolete: Boolean = false,
|
||||||
val isUnofficial: Boolean = false
|
val isUnofficial: Boolean = false
|
||||||
|
|
|
@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
import eu.kanade.tachiyomi.util.lang.Hash
|
import eu.kanade.tachiyomi.util.lang.Hash
|
||||||
|
import eu.kanade.tachiyomi.util.system.getApplicationIcon
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -181,7 +182,8 @@ internal object ExtensionLoader {
|
||||||
isNsfw,
|
isNsfw,
|
||||||
sources = sources,
|
sources = sources,
|
||||||
pkgFactory = appInfo.metaData.getString(METADATA_SOURCE_FACTORY),
|
pkgFactory = appInfo.metaData.getString(METADATA_SOURCE_FACTORY),
|
||||||
isUnofficial = signatureHash != officialSignature
|
isUnofficial = signatureHash != officialSignature,
|
||||||
|
icon = context.getApplicationIcon(pkgName)
|
||||||
)
|
)
|
||||||
return LoadResult.Success(extension)
|
return LoadResult.Success(extension)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.browse.BrowseController
|
import eu.kanade.tachiyomi.ui.browse.BrowseController
|
||||||
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsController
|
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsController
|
||||||
|
import kotlinx.coroutines.flow.drop
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
@ -143,6 +144,7 @@ open class ExtensionController :
|
||||||
}
|
}
|
||||||
|
|
||||||
searchView.queryTextChanges()
|
searchView.queryTextChanges()
|
||||||
|
.drop(1) // Drop first event after subscribed
|
||||||
.filter { router.backstack.lastOrNull()?.controller == this }
|
.filter { router.backstack.lastOrNull()?.controller == this }
|
||||||
.onEach {
|
.onEach {
|
||||||
query = it.toString()
|
query = it.toString()
|
||||||
|
|
|
@ -42,8 +42,8 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
|
||||||
binding.icon.clear()
|
binding.icon.clear()
|
||||||
if (extension is Extension.Available) {
|
if (extension is Extension.Available) {
|
||||||
binding.icon.load(extension.iconUrl)
|
binding.icon.load(extension.iconUrl)
|
||||||
} else {
|
} else if (extension is Extension.Installed) {
|
||||||
extension.getApplicationIcon(itemView.context)?.let { binding.icon.setImageDrawable(it) }
|
binding.icon.load(extension.icon)
|
||||||
}
|
}
|
||||||
bindButtons(item)
|
bindButtons(item)
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ open class ExtensionPresenter(
|
||||||
.startWith(emptyList<Extension.Available>())
|
.startWith(emptyList<Extension.Available>())
|
||||||
|
|
||||||
return Observable.combineLatest(installedObservable, untrustedObservable, availableObservable) { installed, untrusted, available -> Triple(installed, untrusted, available) }
|
return Observable.combineLatest(installedObservable, untrustedObservable, availableObservable) { installed, untrusted, available -> Triple(installed, untrusted, available) }
|
||||||
.debounce(100, TimeUnit.MILLISECONDS)
|
.debounce(500, TimeUnit.MILLISECONDS)
|
||||||
.map(::toItems)
|
.map(::toItems)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeLatestCache({ view, _ -> view.setExtensions(extensions) })
|
.subscribeLatestCache({ view, _ -> view.setExtensions(extensions) })
|
||||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.migration.sources
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import coil.load
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.databinding.SourceMainControllerItemBinding
|
import eu.kanade.tachiyomi.databinding.SourceMainControllerItemBinding
|
||||||
import eu.kanade.tachiyomi.source.icon
|
import eu.kanade.tachiyomi.source.icon
|
||||||
|
@ -20,7 +21,7 @@ class SourceHolder(view: View, val adapter: SourceAdapter) :
|
||||||
binding.subtitle.text = LocaleHelper.getDisplayName(source.lang)
|
binding.subtitle.text = LocaleHelper.getDisplayName(source.lang)
|
||||||
|
|
||||||
itemView.post {
|
itemView.post {
|
||||||
binding.image.setImageDrawable(source.icon())
|
binding.image.load(source.icon())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ class SourceController :
|
||||||
|
|
||||||
// Update list on extension changes (e.g. new installation)
|
// Update list on extension changes (e.g. new installation)
|
||||||
(parentController as BrowseController).extensionListUpdateRelay
|
(parentController as BrowseController).extensionListUpdateRelay
|
||||||
|
.skip(1) // Skip first update when ExtensionController created
|
||||||
.subscribeUntilDestroy {
|
.subscribeUntilDestroy {
|
||||||
presenter.updateSources()
|
presenter.updateSources()
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.browse.source
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import coil.load
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.databinding.SourceMainControllerItemBinding
|
import eu.kanade.tachiyomi.databinding.SourceMainControllerItemBinding
|
||||||
|
@ -10,7 +11,7 @@ import eu.kanade.tachiyomi.source.icon
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import eu.kanade.tachiyomi.util.view.setVectorCompat
|
import eu.kanade.tachiyomi.util.view.setVectorCompat
|
||||||
|
|
||||||
class SourceHolder(private val view: View, val adapter: SourceAdapter) :
|
class SourceHolder(view: View, val adapter: SourceAdapter) :
|
||||||
FlexibleViewHolder(view, adapter) {
|
FlexibleViewHolder(view, adapter) {
|
||||||
|
|
||||||
private val binding = SourceMainControllerItemBinding.bind(view)
|
private val binding = SourceMainControllerItemBinding.bind(view)
|
||||||
|
@ -33,12 +34,10 @@ class SourceHolder(private val view: View, val adapter: SourceAdapter) :
|
||||||
binding.subtitle.text = LocaleHelper.getDisplayName(source.lang)
|
binding.subtitle.text = LocaleHelper.getDisplayName(source.lang)
|
||||||
|
|
||||||
// Set source icon
|
// Set source icon
|
||||||
itemView.post {
|
|
||||||
val icon = source.icon()
|
val icon = source.icon()
|
||||||
when {
|
when {
|
||||||
icon != null -> binding.image.setImageDrawable(icon)
|
icon != null -> binding.image.load(icon)
|
||||||
item.source.id == LocalSource.ID -> binding.image.setImageResource(R.mipmap.ic_local_source)
|
item.source.id == LocalSource.ID -> binding.image.load(R.mipmap.ic_local_source)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.sourceLatest.isVisible = source.supportsLatest
|
binding.sourceLatest.isVisible = source.supportsLatest
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package eu.kanade.tachiyomi.ui.browse.source
|
package eu.kanade.tachiyomi.ui.browse.source
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
|
@ -37,14 +36,6 @@ class SourcePresenter(
|
||||||
*/
|
*/
|
||||||
private var sourceSubscription: Subscription? = null
|
private var sourceSubscription: Subscription? = null
|
||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
|
||||||
super.onCreate(savedState)
|
|
||||||
|
|
||||||
// Load enabled and last used sources
|
|
||||||
loadSources()
|
|
||||||
loadLastUsedSource()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsubscribe and create a new subscription to fetch enabled sources.
|
* Unsubscribe and create a new subscription to fetch enabled sources.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.content.pm.PackageManager
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -418,3 +419,11 @@ fun Context.isPackageInstalled(packageName: String): Boolean {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.getApplicationIcon(pkgName: String): Drawable? {
|
||||||
|
return try {
|
||||||
|
packageManager.getApplicationIcon(pkgName)
|
||||||
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in a new issue