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