refactor: simplify Profile feature state management and update ViewModel
This commit is contained in:
@@ -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
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-13
@@ -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 = {}
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user