refactor: Extract operation counter to a class (#977)
This commit is contained in:
parent
0d5d118267
commit
cdbd0efe11
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Pachli Association
|
||||||
|
*
|
||||||
|
* This file is a part of Pachli.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package app.pachli.core.ui
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.getAndUpdate
|
||||||
|
|
||||||
|
class OperationCounter {
|
||||||
|
private val _count: MutableStateFlow<Int> = MutableStateFlow(0)
|
||||||
|
|
||||||
|
/** Count of outstanding operations. */
|
||||||
|
val count = _count.asStateFlow()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs [block] incrementing the operation count before [block]
|
||||||
|
* starts, decrementing it when [block] ends.
|
||||||
|
*
|
||||||
|
* ```kotlin
|
||||||
|
* private val operationCounter: OperationCounter()
|
||||||
|
* val operationCount = operationCounter.count
|
||||||
|
*
|
||||||
|
* suspend fun foo(): SomeType = operationCounter {
|
||||||
|
* some_network_operation()
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @return Whatever [block] returned
|
||||||
|
*/
|
||||||
|
suspend operator fun <R> invoke(block: suspend () -> R): R {
|
||||||
|
_count.getAndUpdate { it + 1 }
|
||||||
|
val result = block.invoke()
|
||||||
|
_count.getAndUpdate { it - 1 }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ import app.pachli.core.data.repository.StatusDisplayOptionsRepository
|
||||||
import app.pachli.core.data.repository.SuggestionsError.DeleteSuggestionError
|
import app.pachli.core.data.repository.SuggestionsError.DeleteSuggestionError
|
||||||
import app.pachli.core.data.repository.SuggestionsError.FollowAccountError
|
import app.pachli.core.data.repository.SuggestionsError.FollowAccountError
|
||||||
import app.pachli.core.data.repository.SuggestionsRepository
|
import app.pachli.core.data.repository.SuggestionsRepository
|
||||||
|
import app.pachli.core.ui.OperationCounter
|
||||||
import app.pachli.feature.suggestions.UiAction.GetSuggestions
|
import app.pachli.feature.suggestions.UiAction.GetSuggestions
|
||||||
import app.pachli.feature.suggestions.UiAction.SuggestionAction
|
import app.pachli.feature.suggestions.UiAction.SuggestionAction
|
||||||
import app.pachli.feature.suggestions.UiAction.SuggestionAction.AcceptSuggestion
|
import app.pachli.feature.suggestions.UiAction.SuggestionAction.AcceptSuggestion
|
||||||
|
@ -42,10 +43,8 @@ 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
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
import kotlinx.coroutines.flow.getAndUpdate
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
|
@ -128,8 +127,8 @@ internal class SuggestionsViewModel @Inject constructor(
|
||||||
private val _uiResult = Channel<Result<UiSuccess, UiError>>()
|
private val _uiResult = Channel<Result<UiSuccess, UiError>>()
|
||||||
override val uiResult = _uiResult.receiveAsFlow()
|
override val uiResult = _uiResult.receiveAsFlow()
|
||||||
|
|
||||||
private val _operationCount = MutableStateFlow(0)
|
private val operationCounter = OperationCounter()
|
||||||
override val operationCount = _operationCount.asStateFlow()
|
override val operationCount = operationCounter.count
|
||||||
|
|
||||||
private val reload = MutableSharedFlow<Unit>(replay = 1)
|
private val reload = MutableSharedFlow<Unit>(replay = 1)
|
||||||
|
|
||||||
|
@ -212,44 +211,28 @@ internal class SuggestionsViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get fresh suggestions from the repository. */
|
/** Get fresh suggestions from the repository. */
|
||||||
private suspend fun getSuggestions(): Result<Suggestions.Loaded, GetSuggestionsError> = operation {
|
private suspend fun getSuggestions(): Result<Suggestions.Loaded, GetSuggestionsError> =
|
||||||
// Note: disabledSuggestions is *not* cleared here. Suppose the user has
|
operationCounter {
|
||||||
// dismissed a suggestion and the network operation has not completed yet.
|
// Note: disabledSuggestions is *not* cleared here. Suppose the user has
|
||||||
// They reload, and get a list of suggestions that includes the suggestion
|
// dismissed a suggestion and the network operation has not completed yet.
|
||||||
// they have just dismissed. In that case the suggestion should still be
|
// They reload, and get a list of suggestions that includes the suggestion
|
||||||
// disabled.
|
// they have just dismissed. In that case the suggestion should still be
|
||||||
suggestionsRepository.getSuggestions().mapEither(
|
// disabled.
|
||||||
{ Suggestions.Loaded(it.map { SuggestionViewData(suggestion = it) }) },
|
suggestionsRepository.getSuggestions().mapEither(
|
||||||
{ GetSuggestionsError(it) },
|
{ Suggestions.Loaded(it.map { SuggestionViewData(suggestion = it) }) },
|
||||||
)
|
{ GetSuggestionsError(it) },
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/** Delete a suggestion from the repository. */
|
/** Delete a suggestion from the repository. */
|
||||||
private suspend fun deleteSuggestion(suggestion: Suggestion): Result<Unit, DeleteSuggestionError> = operation {
|
private suspend fun deleteSuggestion(suggestion: Suggestion): Result<Unit, DeleteSuggestionError> =
|
||||||
suggestionsRepository.deleteSuggestion(suggestion.account.id)
|
operationCounter {
|
||||||
}
|
suggestionsRepository.deleteSuggestion(suggestion.account.id)
|
||||||
|
}
|
||||||
|
|
||||||
/** Accept the suggestion and follow the account. */
|
/** Accept the suggestion and follow the account. */
|
||||||
private suspend fun acceptSuggestion(suggestion: Suggestion): Result<Unit, FollowAccountError> = operation {
|
private suspend fun acceptSuggestion(suggestion: Suggestion): Result<Unit, FollowAccountError> =
|
||||||
suggestionsRepository.followAccount(suggestion.account.id)
|
operationCounter {
|
||||||
}
|
suggestionsRepository.followAccount(suggestion.account.id)
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Runs [block] incrementing the network operation count before [block]
|
|
||||||
* starts, decrementing it when [block] ends.
|
|
||||||
*
|
|
||||||
* ```kotlin
|
|
||||||
* suspend fun foo(): SomeType = operation {
|
|
||||||
* some_network_operation()
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @return Whatever [block] returned
|
|
||||||
*/
|
|
||||||
private suspend fun <R> operation(block: suspend () -> R): R {
|
|
||||||
_operationCount.getAndUpdate { it + 1 }
|
|
||||||
val result = block.invoke()
|
|
||||||
_operationCount.getAndUpdate { it - 1 }
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue