refactor: simplify Profile feature state management and update ViewModel

This commit is contained in:
2026-05-30 11:46:14 +03:00
parent 63bae014c5
commit d428af4ac4
5 changed files with 17 additions and 47 deletions
@@ -210,7 +210,6 @@ fun MainScreen(
) )
profileScreen( profileScreen(
activity = activity, activity = activity,
onError = onError,
onSettingsButtonClicked = onSettingsButtonClicked, onSettingsButtonClicked = onSettingsButtonClicked,
onPhotoClicked = onPhotoClicked onPhotoClicked = onPhotoClicked
) )
@@ -5,49 +5,33 @@ 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
import dev.meloda.fast.data.State
import dev.meloda.fast.data.UserConfig import dev.meloda.fast.data.UserConfig
import dev.meloda.fast.data.processState import dev.meloda.fast.data.processState
import dev.meloda.fast.domain.GetLocalUserByIdUseCase import dev.meloda.fast.domain.GetLocalUserByIdUseCase
import dev.meloda.fast.domain.LoadUserByIdUseCase import dev.meloda.fast.domain.LoadUserByIdUseCase
import dev.meloda.fast.model.BaseError
import dev.meloda.fast.network.VkErrorCode
import dev.meloda.fast.profile.model.ProfileScreenState import dev.meloda.fast.profile.model.ProfileScreenState
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
interface ProfileViewModel { class ProfileViewModel(
val screenState: StateFlow<ProfileScreenState>
val baseError: StateFlow<BaseError?>
}
class ProfileViewModelImpl(
private val getLocalUserByIdUseCase: GetLocalUserByIdUseCase, private val getLocalUserByIdUseCase: GetLocalUserByIdUseCase,
private val loadUserByIdUseCase: LoadUserByIdUseCase private val loadUserByIdUseCase: LoadUserByIdUseCase
) : ViewModel(), ProfileViewModel { ) : ViewModel() {
override val screenState = MutableStateFlow(ProfileScreenState.EMPTY) private val screenState = MutableStateFlow(ProfileScreenState.EMPTY)
override val baseError = MutableStateFlow<BaseError?>(null)
init { init {
getLocalAccountInfo() getLocalAccountInfo()
} }
fun screenStateFlow(): StateFlow<ProfileScreenState> = screenState.asStateFlow()
private fun getLocalAccountInfo() { private fun getLocalAccountInfo() {
getLocalUserByIdUseCase(UserConfig.userId) getLocalUserByIdUseCase(UserConfig.userId)
.listenValue(viewModelScope) { state -> .listenValue(viewModelScope) { state ->
state.processState( state.processState(
error = { error -> error = {
if (error is State.Error.ApiError) {
when (error.errorCode) {
VkErrorCode.USER_AUTHORIZATION_FAILED -> {
baseError.setValue { BaseError.SessionExpired }
}
else -> Unit
}
}
screenState.setValue { old -> screenState.setValue { old ->
old.copy( old.copy(
avatarUrl = null, avatarUrl = null,
@@ -1,9 +1,9 @@
package dev.meloda.fast.profile.di package dev.meloda.fast.profile.di
import dev.meloda.fast.profile.ProfileViewModelImpl import dev.meloda.fast.profile.ProfileViewModel
import org.koin.core.module.dsl.viewModelOf import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.module import org.koin.dsl.module
val profileModule = module { val profileModule = module {
viewModelOf(::ProfileViewModelImpl) viewModelOf(::ProfileViewModel)
} }
@@ -1,11 +1,11 @@
package dev.meloda.fast.profile.navigation package dev.meloda.fast.profile.navigation
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import dev.meloda.fast.model.BaseError
import dev.meloda.fast.profile.ProfileViewModel import dev.meloda.fast.profile.ProfileViewModel
import dev.meloda.fast.profile.ProfileViewModelImpl
import dev.meloda.fast.profile.presentation.ProfileRoute import dev.meloda.fast.profile.presentation.ProfileRoute
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.koin.androidx.viewmodel.ext.android.getViewModel import org.koin.androidx.viewmodel.ext.android.getViewModel
@@ -15,19 +15,18 @@ object Profile
fun NavGraphBuilder.profileScreen( fun NavGraphBuilder.profileScreen(
activity: AppCompatActivity, activity: AppCompatActivity,
onError: (BaseError) -> Unit,
onSettingsButtonClicked: () -> Unit, onSettingsButtonClicked: () -> Unit,
onPhotoClicked: (url: String) -> Unit onPhotoClicked: (url: String) -> Unit
) { ) {
val viewModel: ProfileViewModel = with(activity) { val viewModel: ProfileViewModel = with(activity) { getViewModel() }
getViewModel<ProfileViewModelImpl>()
}
composable<Profile> { composable<Profile> {
val screenState by viewModel.screenStateFlow().collectAsStateWithLifecycle()
ProfileRoute( ProfileRoute(
onError = onError, screenState = screenState,
onSettingsButtonClicked = onSettingsButtonClicked, onSettingsButtonClicked = onSettingsButtonClicked,
onPhotoClicked = onPhotoClicked, onPhotoClicked = onPhotoClicked,
viewModel = viewModel
) )
} }
} }
@@ -20,7 +20,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@@ -29,31 +28,21 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.compose.AsyncImage import coil.compose.AsyncImage
import dev.meloda.fast.model.BaseError
import dev.meloda.fast.profile.ProfileViewModel
import dev.meloda.fast.profile.ProfileViewModelImpl
import dev.meloda.fast.profile.model.ProfileScreenState import dev.meloda.fast.profile.model.ProfileScreenState
import dev.meloda.fast.ui.R import dev.meloda.fast.ui.R
import dev.meloda.fast.ui.components.SegmentedButtonItem import dev.meloda.fast.ui.components.SegmentedButtonItem
import dev.meloda.fast.ui.components.SegmentedButtonsRow import dev.meloda.fast.ui.components.SegmentedButtonsRow
import dev.meloda.fast.ui.util.buildImmutableList import dev.meloda.fast.ui.util.buildImmutableList
import org.koin.androidx.compose.koinViewModel
@Composable @Composable
fun ProfileRoute( fun ProfileRoute(
onError: (BaseError) -> Unit, screenState: ProfileScreenState,
onSettingsButtonClicked: () -> Unit, onSettingsButtonClicked: () -> Unit,
onPhotoClicked: (url: String) -> Unit, onPhotoClicked: (url: String) -> Unit,
viewModel: ProfileViewModel = koinViewModel<ProfileViewModelImpl>()
) { ) {
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
val baseError by viewModel.baseError.collectAsStateWithLifecycle()
ProfileScreen( ProfileScreen(
screenState = screenState, screenState = screenState,
baseError = baseError,
onSettingsButtonClicked = onSettingsButtonClicked, onSettingsButtonClicked = onSettingsButtonClicked,
onPhotoClicked = onPhotoClicked onPhotoClicked = onPhotoClicked
) )
@@ -64,7 +53,6 @@ fun ProfileRoute(
@Composable @Composable
fun ProfileScreen( fun ProfileScreen(
screenState: ProfileScreenState = ProfileScreenState.EMPTY, screenState: ProfileScreenState = ProfileScreenState.EMPTY,
baseError: BaseError? = null,
onSettingsButtonClicked: () -> Unit = {}, onSettingsButtonClicked: () -> Unit = {},
onPhotoClicked: (url: String) -> Unit = {} onPhotoClicked: (url: String) -> Unit = {}
) { ) {