remove usage of context-receivers

This commit is contained in:
2024-08-14 12:04:04 +03:00
parent 0500969d81
commit ee8cf619f8
11 changed files with 98 additions and 112 deletions
@@ -152,7 +152,7 @@ class MainViewModelImpl(
} }
private fun listenLongPollState() { private fun listenLongPollState() {
longPollController.stateToApply.listenValue { newState -> longPollController.stateToApply.listenValue(viewModelScope) { newState ->
if (newState == LongPollState.Background) { if (newState == LongPollState.Background) {
isNeedToCheckNotificationsPermission.update { true } isNeedToCheckNotificationsPermission.update { true }
} }
@@ -55,8 +55,7 @@ private inline fun <reified T : KotlinTopLevelExtension> Project.configureKotlin
"-opt-in=kotlin.RequiresOptIn", "-opt-in=kotlin.RequiresOptIn",
// Enable experimental coroutines APIs, including Flow // Enable experimental coroutines APIs, including Flow
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlinx.coroutines.FlowPreview", "-opt-in=kotlinx.coroutines.FlowPreview"
"-Xcontext-receivers"
) )
} }
} }
@@ -25,9 +25,6 @@ fun <T> MutableList<T>.addIf(element: T, condition: () -> Boolean) {
if (condition.invoke()) add(element) if (condition.invoke()) add(element)
} }
context(ViewModel)
fun <T> Flow<T>.listenValue(action: suspend (T) -> Unit) = listenValue(viewModelScope, action)
fun <T> Flow<T>.listenValue( fun <T> Flow<T>.listenValue(
coroutineScope: CoroutineScope, coroutineScope: CoroutineScope,
action: suspend (T) -> Unit action: suspend (T) -> Unit
@@ -75,9 +72,6 @@ fun createTimerFlow(
} }
} }
context(ViewModel)
fun <T> MutableStateFlow<T>.updateValue(newValue: T) = this.update { newValue }
fun <T> MutableStateFlow<T>.setValue(function: (T) -> T) { fun <T> MutableStateFlow<T>.setValue(function: (T) -> T) {
val newValue = function(value) val newValue = function(value)
update { newValue } update { newValue }
@@ -6,7 +6,6 @@ import dev.meloda.fast.auth.captcha.model.CaptchaScreenState
import dev.meloda.fast.auth.captcha.navigation.Captcha import dev.meloda.fast.auth.captcha.navigation.Captcha
import dev.meloda.fast.auth.captcha.validation.CaptchaValidator import dev.meloda.fast.auth.captcha.validation.CaptchaValidator
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.common.extensions.updateValue
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
@@ -58,13 +57,13 @@ class CaptchaViewModelImpl(
} }
override fun onNavigatedToLogin() { override fun onNavigatedToLogin() {
screenState.updateValue(CaptchaScreenState.EMPTY) screenState.update { CaptchaScreenState.EMPTY }
isNeedToOpenLogin.update { false } isNeedToOpenLogin.update { false }
} }
private fun processValidation(): Boolean { private fun processValidation(): Boolean {
val isValid = validator.validate(screenState.value).isValid() val isValid = validator.validate(screenState.value).isValid()
screenState.updateValue(screenState.value.copy(codeError = !isValid)) screenState.setValue { old -> old.copy(codeError = !isValid) }
return isValid return isValid
} }
} }
@@ -14,7 +14,6 @@ import dev.meloda.fast.common.LongPollController
import dev.meloda.fast.common.VkConstants import dev.meloda.fast.common.VkConstants
import dev.meloda.fast.common.extensions.listenValue import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.common.extensions.updateValue
import dev.meloda.fast.common.model.LongPollState import dev.meloda.fast.common.model.LongPollState
import dev.meloda.fast.data.State import dev.meloda.fast.data.State
import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.UserConfig
@@ -102,7 +101,7 @@ class LoginViewModelImpl(
login = newLogin.trim(), login = newLogin.trim(),
loginError = false loginError = false
) )
screenState.updateValue(newState) screenState.setValue { newState }
} }
override fun onPasswordInputChanged(newPassword: String) { override fun onPasswordInputChanged(newPassword: String) {
@@ -110,7 +109,7 @@ class LoginViewModelImpl(
password = newPassword.trim(), password = newPassword.trim(),
passwordError = false passwordError = false
) )
screenState.updateValue(newState) screenState.setValue { newState }
} }
override fun onSignInButtonClicked() { override fun onSignInButtonClicked() {
@@ -176,7 +175,7 @@ class LoginViewModelImpl(
userIds = null, userIds = null,
fields = VkConstants.USER_FIELDS, fields = VkConstants.USER_FIELDS,
nomCase = null nomCase = null
).listenValue { state -> ).listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
UserConfig.currentUserId = -1 UserConfig.currentUserId = -1
@@ -227,7 +226,7 @@ class LoginViewModelImpl(
validationCode = validationCode.value, validationCode = validationCode.value,
captchaSid = captchaArguments.value?.captchaSid, captchaSid = captchaArguments.value?.captchaSid,
captchaKey = captchaCode.value captchaKey = captchaCode.value
).listenValue { state -> ).listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
Log.d("LoginViewModelImpl", "login: error: $error") Log.d("LoginViewModelImpl", "login: error: $error")
@@ -354,11 +353,11 @@ class LoginViewModelImpl(
validationState.value.forEach { result -> validationState.value.forEach { result ->
when (result) { when (result) {
LoginValidationResult.LoginEmpty -> { LoginValidationResult.LoginEmpty -> {
screenState.updateValue(screenState.value.copy(loginError = true)) screenState.setValue { old -> old.copy(loginError = true) }
} }
LoginValidationResult.PasswordEmpty -> { LoginValidationResult.PasswordEmpty -> {
screenState.updateValue(screenState.value.copy(passwordError = true)) screenState.setValue { old -> old.copy(passwordError = true) }
} }
LoginValidationResult.Empty -> Unit LoginValidationResult.Empty -> Unit
@@ -10,7 +10,6 @@ import dev.meloda.fast.auth.validation.validation.ValidationValidator
import dev.meloda.fast.common.extensions.createTimerFlow import dev.meloda.fast.common.extensions.createTimerFlow
import dev.meloda.fast.common.extensions.listenValue import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.common.extensions.updateValue
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.domain.AuthUseCase import dev.meloda.fast.domain.AuthUseCase
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -77,12 +76,12 @@ class ValidationViewModelImpl(
} }
override fun onCodeInputChanged(newCode: String) { override fun onCodeInputChanged(newCode: String) {
screenState.updateValue( screenState.setValue { old ->
screenState.value.copy( old.copy(
code = newCode.trim(), code = newCode.trim(),
codeError = false codeError = false
) )
) }
if (newCode.length == 6) { if (newCode.length == 6) {
viewModelScope.launch { viewModelScope.launch {
@@ -116,7 +115,7 @@ class ValidationViewModelImpl(
} }
override fun onNavigatedToLogin() { override fun onNavigatedToLogin() {
screenState.updateValue(ValidationScreenState.EMPTY) screenState.update { ValidationScreenState.EMPTY }
isNeedToOpenLogin.update { false } isNeedToOpenLogin.update { false }
} }
@@ -132,7 +131,7 @@ class ValidationViewModelImpl(
val sid = validationSid ?: return val sid = validationSid ?: return
authUseCase.validatePhone(sid) authUseCase.validatePhone(sid)
.listenValue { state -> .listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
@@ -164,21 +163,13 @@ class ValidationViewModelImpl(
delayJob = createTimerFlow( delayJob = createTimerFlow(
time = delay, time = delay,
onStartAction = { onStartAction = {
screenState.updateValue( screenState.setValue { old -> old.copy(isSmsButtonVisible = false) }
screenState.value.copy(isSmsButtonVisible = false)
)
}, },
onTickAction = { remainedTime -> onTickAction = { remainedTime ->
screenState.updateValue( screenState.setValue { old -> old.copy(delayTime = remainedTime) }
screenState.value.copy(delayTime = remainedTime)
)
}, },
onTimeoutAction = { onTimeoutAction = {
screenState.updateValue( screenState.setValue { old -> old.copy(isSmsButtonVisible = true) }
screenState.value.copy(
isSmsButtonVisible = true
)
)
}, },
).launchIn(viewModelScope) ).launchIn(viewModelScope)
} }
@@ -2,6 +2,7 @@ package dev.meloda.fast.chatmaterials
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.meloda.fast.chatmaterials.model.ChatMaterialsScreenState import dev.meloda.fast.chatmaterials.model.ChatMaterialsScreenState
import dev.meloda.fast.chatmaterials.navigation.ChatMaterials import dev.meloda.fast.chatmaterials.navigation.ChatMaterials
import dev.meloda.fast.chatmaterials.util.asPresentation import dev.meloda.fast.chatmaterials.util.asPresentation
@@ -83,7 +84,7 @@ class ChatMaterialsViewModelImpl(
offset = offset, offset = offset,
attachmentTypes = listOf(screenState.value.attachmentType), attachmentTypes = listOf(screenState.value.attachmentType),
conversationMessageId = screenState.value.conversationMessageId conversationMessageId = screenState.value.conversationMessageId
).listenValue { state -> ).listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
@@ -88,7 +88,7 @@ class ConversationsViewModelImpl(
}.stateIn(viewModelScope, SharingStarted.Eagerly, 0) }.stateIn(viewModelScope, SharingStarted.Eagerly, 0)
init { init {
userSettings.useContactNames.listenValue(::updateConversationsNames) userSettings.useContactNames.listenValue(viewModelScope, ::updateConversationsNames)
updatesParser.onNewMessage(::handleNewMessage) updatesParser.onNewMessage(::handleNewMessage)
updatesParser.onMessageEdited(::handleEditedMessage) updatesParser.onMessageEdited(::handleEditedMessage)
@@ -227,7 +227,7 @@ class ConversationsViewModelImpl(
offset: Int = currentOffset.value offset: Int = currentOffset.value
) { ) {
conversationsUseCase.getConversations(count = LOAD_COUNT, offset = offset) conversationsUseCase.getConversations(count = LOAD_COUNT, offset = offset)
.listenValue { state -> .listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
if (error is State.Error.ApiError) { if (error is State.Error.ApiError) {
@@ -288,7 +288,7 @@ class ConversationsViewModelImpl(
} }
private fun deleteConversation(peerId: Int) { private fun deleteConversation(peerId: Int) {
conversationsUseCase.delete(peerId).listenValue { state -> conversationsUseCase.delete(peerId).listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
@@ -314,7 +314,7 @@ class ConversationsViewModelImpl(
private fun pinConversation(peerId: Int, pin: Boolean) { private fun pinConversation(peerId: Int, pin: Boolean) {
conversationsUseCase.changePinState(peerId, pin) conversationsUseCase.changePinState(peerId, pin)
.listenValue { state -> .listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
@@ -578,7 +578,7 @@ class ConversationsViewModelImpl(
messagesUseCase.markAsRead( messagesUseCase.markAsRead(
peerId = peerId, peerId = peerId,
startMessageId = startMessageId startMessageId = startMessageId
).listenValue { state -> ).listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
@@ -1,12 +1,13 @@
package dev.meloda.fast.friends package dev.meloda.fast.friends
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.meloda.fast.common.extensions.listenValue import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.data.State import dev.meloda.fast.data.State
import dev.meloda.fast.domain.FriendsUseCase
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.datastore.UserSettings import dev.meloda.fast.datastore.UserSettings
import dev.meloda.fast.domain.FriendsUseCase
import dev.meloda.fast.friends.model.FriendsScreenState import dev.meloda.fast.friends.model.FriendsScreenState
import dev.meloda.fast.friends.util.asPresentation import dev.meloda.fast.friends.util.asPresentation
import dev.meloda.fast.model.BaseError import dev.meloda.fast.model.BaseError
@@ -47,7 +48,7 @@ class FriendsViewModelImpl(
private val friends = MutableStateFlow<List<VkUser>>(emptyList()) private val friends = MutableStateFlow<List<VkUser>>(emptyList())
init { init {
userSettings.useContactNames.listenValue(::updateFriendsNames) userSettings.useContactNames.listenValue(viewModelScope, ::updateFriendsNames)
loadFriends() loadFriends()
} }
@@ -66,7 +67,8 @@ class FriendsViewModelImpl(
} }
private fun loadFriends(offset: Int = currentOffset.value) { private fun loadFriends(offset: Int = currentOffset.value) {
friendsUseCase.getAllFriends(count = LOAD_COUNT, offset = offset).listenValue { state -> friendsUseCase.getAllFriends(count = LOAD_COUNT, offset = offset)
.listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
if (error is State.Error.ApiError) { if (error is State.Error.ApiError) {
@@ -11,7 +11,6 @@ import com.conena.nanokt.collections.indexOfOrNull
import com.conena.nanokt.text.isEmptyOrBlank import com.conena.nanokt.text.isEmptyOrBlank
import dev.meloda.fast.common.extensions.listenValue import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
import dev.meloda.fast.common.extensions.updateValue
import dev.meloda.fast.common.provider.ResourceProvider import dev.meloda.fast.common.provider.ResourceProvider
import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.UserConfig
import dev.meloda.fast.data.VkMemoryCache import dev.meloda.fast.data.VkMemoryCache
@@ -97,7 +96,10 @@ class MessagesHistoryViewModelImpl(
updatesParser.onMessageIncomingRead(::handleReadIncomingEvent) updatesParser.onMessageIncomingRead(::handleReadIncomingEvent)
updatesParser.onMessageOutgoingRead(::handleReadOutgoingEvent) updatesParser.onMessageOutgoingRead(::handleReadOutgoingEvent)
userSettings.showTimeInActionMessages.listenValue(::toggleShowTimeInActionMessages) userSettings.showTimeInActionMessages.listenValue(
viewModelScope,
::toggleShowTimeInActionMessages
)
} }
override fun onRefresh() { override fun onRefresh() {
@@ -117,9 +119,7 @@ class MessagesHistoryViewModelImpl(
) )
} }
screenState.value.copy(message = newText).let { newValue -> screenState.setValue { old -> old.copy(message = newText) }
screenState.updateValue(newValue)
}
} }
override fun onEmojiButtonClicked() { override fun onEmojiButtonClicked() {
@@ -236,7 +236,7 @@ class MessagesHistoryViewModelImpl(
conversationId = screenState.value.conversationId, conversationId = screenState.value.conversationId,
count = MESSAGES_LOAD_COUNT, count = MESSAGES_LOAD_COUNT,
offset = offset, offset = offset,
).listenValue { state -> ).listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
@@ -375,7 +375,7 @@ class MessagesHistoryViewModelImpl(
message = newMessage.text, message = newMessage.text,
replyTo = null, replyTo = null,
attachments = null attachments = null
).listenValue { state -> ).listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
sendingMessages -= newMessage sendingMessages -= newMessage
@@ -1,6 +1,7 @@
package dev.meloda.fast.profile package dev.meloda.fast.profile
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dev.meloda.fast.common.VkConstants import dev.meloda.fast.common.VkConstants
import dev.meloda.fast.common.extensions.listenValue import dev.meloda.fast.common.extensions.listenValue
import dev.meloda.fast.common.extensions.setValue import dev.meloda.fast.common.extensions.setValue
@@ -32,7 +33,7 @@ class ProfileViewModelImpl(
private fun getLocalAccountInfo() { private fun getLocalAccountInfo() {
usersUseCase.getLocalUser(UserConfig.userId) usersUseCase.getLocalUser(UserConfig.userId)
.listenValue { state -> .listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
if (error is State.Error.ApiError) { if (error is State.Error.ApiError) {
@@ -70,7 +71,7 @@ class ProfileViewModelImpl(
userIds = null, userIds = null,
fields = VkConstants.USER_FIELDS, fields = VkConstants.USER_FIELDS,
nomCase = null nomCase = null
).listenValue { state -> ).listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = { error ->
// TODO: 12/07/2024, Danil Nikolaev: if local info is null then show error view // TODO: 12/07/2024, Danil Nikolaev: if local info is null then show error view