mirror of
https://github.com/mihonapp/mihon.git
synced 2026-10-16 13:48:09 -07:00
Improve performance across screens (#4071)
* Keep screens loaded while they're hidden and rebuild the library faster * Count chapters in SQL for the migration list * Show the extension list sooner and check trust against loaded stores * Cancel the previous tracker search when searching again * Write reader progress less often and keep its work off the main thread * Stop rebuilding the settings search index on every key * Watch updates for widgets only while one is placed The query re-ran on every chapter or manga write even with no widget on the home screen. * Observe download pages and limit how often their progress updates * Throttle the library update notification and write fetch data together
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package tachiyomi.core.common.util.lang
|
||||
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingCommand
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.conflate
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlin.coroutines.AbstractCoroutineContextElement
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.time.Duration
|
||||
|
||||
/**
|
||||
* Keeps a view model's flows running while its screen is hidden, but holds back database and other frequent
|
||||
* updates until the screen is visible again, so returning to it shows the last state instead of re-running
|
||||
* everything. Flows collected without a gate in their context are unaffected.
|
||||
*/
|
||||
class SubscriberGate : AbstractCoroutineContextElement(SubscriberGate) {
|
||||
|
||||
companion object Key : CoroutineContext.Key<SubscriberGate>
|
||||
|
||||
private val open = MutableStateFlow(true)
|
||||
|
||||
fun whileSubscribed(stopTimeout: Duration): SharingStarted = object : SharingStarted {
|
||||
override fun command(subscriptionCount: StateFlow<Int>): Flow<SharingCommand> = flow {
|
||||
emit(SharingCommand.START)
|
||||
subscriptionCount
|
||||
.map { it > 0 }
|
||||
.distinctUntilChanged()
|
||||
.collectLatest { subscribed ->
|
||||
if (!subscribed) delay(stopTimeout)
|
||||
open.value = subscribed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal suspend fun awaitOpen() {
|
||||
open.first { it }
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Flow<T>.pausedWhileUnsubscribed(): Flow<T> = flow {
|
||||
val gate = currentCoroutineContext()[SubscriberGate]
|
||||
if (gate == null) {
|
||||
emitAll(this@pausedWhileUnsubscribed)
|
||||
} else {
|
||||
this@pausedWhileUnsubscribed.conflate().collect {
|
||||
gate.awaitOpen()
|
||||
emit(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -318,8 +318,16 @@ object ImageUtil {
|
||||
null
|
||||
}
|
||||
|
||||
if (image == null) return Color.WHITE.toDrawable()
|
||||
return try {
|
||||
chooseBackground(context, image)
|
||||
} finally {
|
||||
image.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
private fun chooseBackground(context: Context, image: Bitmap): Drawable {
|
||||
val whiteColor = Color.WHITE
|
||||
if (image == null) return whiteColor.toDrawable()
|
||||
if (image.width < 50 || image.height < 50) {
|
||||
return whiteColor.toDrawable()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user