refactor: Move throttleFirst to core.common (#733)

This commit is contained in:
Nik Clayton 2024-06-10 19:57:47 +02:00 committed by GitHub
parent 46c7307c0d
commit 7cf7476c49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 15 additions and 24 deletions

View File

@ -33,6 +33,7 @@ import app.pachli.appstore.MuteEvent
import app.pachli.components.timeline.FilterKind import app.pachli.components.timeline.FilterKind
import app.pachli.components.timeline.FiltersRepository import app.pachli.components.timeline.FiltersRepository
import app.pachli.core.accounts.AccountManager import app.pachli.core.accounts.AccountManager
import app.pachli.core.common.extensions.throttleFirst
import app.pachli.core.data.repository.StatusDisplayOptionsRepository import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.network.model.Filter import app.pachli.core.network.model.Filter
import app.pachli.core.network.model.FilterContext import app.pachli.core.network.model.FilterContext
@ -44,13 +45,11 @@ import app.pachli.network.FilterModel
import app.pachli.usecase.TimelineCases import app.pachli.usecase.TimelineCases
import app.pachli.util.deserialize import app.pachli.util.deserialize
import app.pachli.util.serialize import app.pachli.util.serialize
import app.pachli.util.throttleFirst
import app.pachli.viewdata.NotificationViewData import app.pachli.viewdata.NotificationViewData
import app.pachli.viewdata.StatusViewData import app.pachli.viewdata.StatusViewData
import at.connyduck.calladapter.networkresult.getOrThrow import at.connyduck.calladapter.networkresult.getOrThrow
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -416,7 +415,7 @@ class NotificationsViewModel @Inject constructor(
// Handle NotificationAction.* // Handle NotificationAction.*
viewModelScope.launch { viewModelScope.launch {
uiAction.filterIsInstance<NotificationAction>() uiAction.filterIsInstance<NotificationAction>()
.throttleFirst(THROTTLE_TIMEOUT) .throttleFirst()
.collect { action -> .collect { action ->
try { try {
when (action) { when (action) {
@ -435,7 +434,7 @@ class NotificationsViewModel @Inject constructor(
// Handle StatusAction.* // Handle StatusAction.*
viewModelScope.launch { viewModelScope.launch {
uiAction.filterIsInstance<StatusAction>() uiAction.filterIsInstance<StatusAction>()
.throttleFirst(THROTTLE_TIMEOUT) // avoid double-taps .throttleFirst() // avoid double-taps
.collect { action -> .collect { action ->
try { try {
when (action) { when (action) {
@ -568,8 +567,4 @@ class NotificationsViewModel @Inject constructor(
private fun toPrefs() = UiPrefs( private fun toPrefs() = UiPrefs(
showFabWhileScrolling = !sharedPreferencesRepository.getBoolean(PrefKeys.FAB_HIDE, false), showFabWhileScrolling = !sharedPreferencesRepository.getBoolean(PrefKeys.FAB_HIDE, false),
) )
companion object {
private val THROTTLE_TIMEOUT = 500.milliseconds
}
} }

View File

@ -44,6 +44,7 @@ import app.pachli.appstore.UnfollowEvent
import app.pachli.components.timeline.FilterKind import app.pachli.components.timeline.FilterKind
import app.pachli.components.timeline.FiltersRepository import app.pachli.components.timeline.FiltersRepository
import app.pachli.core.accounts.AccountManager import app.pachli.core.accounts.AccountManager
import app.pachli.core.common.extensions.throttleFirst
import app.pachli.core.data.repository.StatusDisplayOptionsRepository import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.model.Timeline import app.pachli.core.model.Timeline
import app.pachli.core.network.model.Filter import app.pachli.core.network.model.Filter
@ -54,10 +55,8 @@ import app.pachli.core.preferences.PrefKeys
import app.pachli.core.preferences.SharedPreferencesRepository import app.pachli.core.preferences.SharedPreferencesRepository
import app.pachli.network.FilterModel import app.pachli.network.FilterModel
import app.pachli.usecase.TimelineCases import app.pachli.usecase.TimelineCases
import app.pachli.util.throttleFirst
import app.pachli.viewdata.StatusViewData import app.pachli.viewdata.StatusViewData
import at.connyduck.calladapter.networkresult.getOrThrow import at.connyduck.calladapter.networkresult.getOrThrow
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
@ -329,7 +328,7 @@ abstract class TimelineViewModel(
// Handle StatusAction.* // Handle StatusAction.*
viewModelScope.launch { viewModelScope.launch {
uiAction.filterIsInstance<StatusAction>() uiAction.filterIsInstance<StatusAction>()
.throttleFirst(THROTTLE_TIMEOUT) // avoid double-taps .throttleFirst() // avoid double-taps
.collect { action -> .collect { action ->
try { try {
when (action) { when (action) {
@ -623,8 +622,6 @@ abstract class TimelineViewModel(
} }
companion object { companion object {
private val THROTTLE_TIMEOUT = 500.milliseconds
/** Tag for the timelineKind in `savedStateHandle` */ /** Tag for the timelineKind in `savedStateHandle` */
@VisibleForTesting(VisibleForTesting.PRIVATE) @VisibleForTesting(VisibleForTesting.PRIVATE)
const val TIMELINE_TAG = "timeline" const val TIMELINE_TAG = "timeline"

View File

@ -21,15 +21,14 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import app.pachli.components.trending.TrendingLinksRepository import app.pachli.components.trending.TrendingLinksRepository
import app.pachli.core.accounts.AccountManager import app.pachli.core.accounts.AccountManager
import app.pachli.core.common.extensions.throttleFirst
import app.pachli.core.data.repository.StatusDisplayOptionsRepository import app.pachli.core.data.repository.StatusDisplayOptionsRepository
import app.pachli.core.network.model.TrendsLink import app.pachli.core.network.model.TrendsLink
import app.pachli.core.preferences.PrefKeys import app.pachli.core.preferences.PrefKeys
import app.pachli.core.preferences.SharedPreferencesRepository import app.pachli.core.preferences.SharedPreferencesRepository
import app.pachli.util.throttleFirst
import at.connyduck.calladapter.networkresult.fold import at.connyduck.calladapter.networkresult.fold
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
@ -84,7 +83,7 @@ class TrendingLinksViewModel @Inject constructor(
init { init {
viewModelScope.launch { viewModelScope.launch {
uiAction uiAction
.throttleFirst(THROTTLE_TIMEOUT) .throttleFirst()
.filterIsInstance<InfallibleUiAction.Reload>() .filterIsInstance<InfallibleUiAction.Reload>()
.onEach { invalidate() } .onEach { invalidate() }
.collect() .collect()
@ -99,8 +98,4 @@ class TrendingLinksViewModel @Inject constructor(
{ throwable -> _loadState.update { LoadState.Error(throwable) } }, { throwable -> _loadState.update { LoadState.Error(throwable) } },
) )
} }
companion object {
private val THROTTLE_TIMEOUT = 500.milliseconds
}
} }

View File

@ -15,9 +15,10 @@
* see <http://www.gnu.org/licenses>. * see <http://www.gnu.org/licenses>.
*/ */
package app.pachli.util package app.pachli.core.common.extensions
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.TimeMark import kotlin.time.TimeMark
import kotlin.time.TimeSource import kotlin.time.TimeSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -50,11 +51,12 @@ import kotlinx.coroutines.flow.flow
* ``` * ```
* *
* @see kotlinx.coroutines.flow.debounce(Duration) * @see kotlinx.coroutines.flow.debounce(Duration)
* @param timeout Emissions within this duration of the last emission are filtered * @param timeout Emissions within this duration of the last emission are filtered.
* Defaults to [DEFAULT_THROTTLE_FIRST_TIMEOUT] if omitted.
* @param timeSource Used to measure elapsed time. Normally only overridden in tests * @param timeSource Used to measure elapsed time. Normally only overridden in tests
*/ */
fun <T> Flow<T>.throttleFirst( fun <T> Flow<T>.throttleFirst(
timeout: Duration, timeout: Duration = DEFAULT_THROTTLE_FIRST_TIMEOUT,
timeSource: TimeSource = TimeSource.Monotonic, timeSource: TimeSource = TimeSource.Monotonic,
) = flow { ) = flow {
var marker: TimeMark? = null var marker: TimeMark? = null
@ -65,3 +67,5 @@ fun <T> Flow<T>.throttleFirst(
} }
} }
} }
private val DEFAULT_THROTTLE_FIRST_TIMEOUT = 500.milliseconds

View File

@ -15,7 +15,7 @@
* see <http://www.gnu.org/licenses>. * see <http://www.gnu.org/licenses>.
*/ */
package app.pachli.util package app.pachli.core.common.extensions
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat