account's info on profile screen; storing users into cache
This commit is contained in:
@@ -135,11 +135,26 @@ class LoginViewModelImpl(
|
||||
UserConfig.trustedHash = account.trustedHash
|
||||
}
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
accountsRepository.storeAccounts(listOf(currentAccount))
|
||||
usersUseCase.get(
|
||||
userIds = null,
|
||||
fields = VkConstants.USER_FIELDS,
|
||||
nomCase = null
|
||||
).listenValue { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
|
||||
delay(350)
|
||||
screenState.setValue { old -> old.copy(isNeedToNavigateToMain = true) }
|
||||
},
|
||||
success = { response ->
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
accountsRepository.storeAccounts(listOf(currentAccount))
|
||||
|
||||
delay(350)
|
||||
screenState.setValue { old -> old.copy(isNeedToNavigateToMain = true) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
screenState.setValue { old -> old.copy(isLoading = state.isLoading()) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,16 +192,11 @@ class LoginViewModelImpl(
|
||||
return@processState
|
||||
}
|
||||
|
||||
usersUseCase.getUserById(
|
||||
userId = userId,
|
||||
usersUseCase.get(
|
||||
userIds = listOf(userId),
|
||||
fields = VkConstants.USER_FIELDS,
|
||||
nomCase = null
|
||||
).listenValue { state ->
|
||||
state.processState(
|
||||
error = {},
|
||||
success = { user -> user?.let { usersUseCase.storeUser(user) } }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val currentAccount = AccountEntity(
|
||||
userId = userId,
|
||||
|
||||
@@ -1,12 +1,78 @@
|
||||
package com.meloda.app.fast.profile
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.meloda.app.fast.common.UserConfig
|
||||
import com.meloda.app.fast.common.VkConstants
|
||||
import com.meloda.app.fast.common.extensions.listenValue
|
||||
import com.meloda.app.fast.common.extensions.setValue
|
||||
import com.meloda.app.fast.data.api.users.UsersUseCase
|
||||
import com.meloda.app.fast.data.processState
|
||||
import com.meloda.app.fast.profile.model.ProfileScreenState
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
interface ProfileViewModel {
|
||||
val screenState: StateFlow<ProfileScreenState>
|
||||
}
|
||||
|
||||
class ProfileViewModelImpl(
|
||||
|
||||
private val usersUseCase: UsersUseCase
|
||||
) : ViewModel(), ProfileViewModel {
|
||||
|
||||
override val screenState = MutableStateFlow(ProfileScreenState.EMPTY)
|
||||
|
||||
init {
|
||||
getLocalAccountInfo()
|
||||
}
|
||||
|
||||
private fun getLocalAccountInfo() {
|
||||
usersUseCase.getLocalUser(UserConfig.userId)
|
||||
.listenValue { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
screenState.setValue { old ->
|
||||
old.copy(
|
||||
avatarUrl = null,
|
||||
fullName = null
|
||||
)
|
||||
}
|
||||
},
|
||||
success = { user ->
|
||||
screenState.setValue { old ->
|
||||
old.copy(
|
||||
avatarUrl = user?.photo200,
|
||||
fullName = user?.fullName
|
||||
)
|
||||
}
|
||||
},
|
||||
any = ::loadAccountInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadAccountInfo() {
|
||||
usersUseCase.get(
|
||||
userIds = null,
|
||||
fields = VkConstants.USER_FIELDS,
|
||||
nomCase = null
|
||||
).listenValue { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
// TODO: 12/07/2024, Danil Nikolaev: if local info is null then show error view
|
||||
},
|
||||
success = { response ->
|
||||
val user = response.single()
|
||||
|
||||
screenState.setValue { old ->
|
||||
old.copy(
|
||||
avatarUrl = user.photo200,
|
||||
fullName = user.fullName
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
screenState.setValue { old -> old.copy(isLoading = state.isLoading()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.meloda.app.fast.profile.model
|
||||
|
||||
data class ProfileScreenState(
|
||||
val isLoading: Boolean,
|
||||
val avatarUrl: String?,
|
||||
val fullName: String?
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val EMPTY: ProfileScreenState = ProfileScreenState(
|
||||
isLoading = false,
|
||||
avatarUrl = null,
|
||||
fullName = null
|
||||
)
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.meloda.app.fast.profile.navigation
|
||||
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.compose.composable
|
||||
import com.meloda.app.fast.common.extensions.navigation.sharedViewModel
|
||||
import com.meloda.app.fast.model.BaseError
|
||||
import com.meloda.app.fast.profile.ProfileViewModel
|
||||
import com.meloda.app.fast.profile.ProfileViewModelImpl
|
||||
import com.meloda.app.fast.profile.presentation.ProfileScreen
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
object Profile
|
||||
|
||||
fun NavGraphBuilder.profileRoute(
|
||||
onError: (BaseError) -> Unit,
|
||||
onNavigateToSettings: () -> Unit,
|
||||
navController: NavController
|
||||
) {
|
||||
composable<Profile> {
|
||||
val viewModel: ProfileViewModel =
|
||||
it.sharedViewModel<ProfileViewModelImpl>(navController = navController)
|
||||
|
||||
ProfileScreen(
|
||||
onError = onError,
|
||||
onNavigateToSettings = onNavigateToSettings,
|
||||
viewModel = viewModel
|
||||
)
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.meloda.app.fast.profile.presentation
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.calculateEndPadding
|
||||
import androidx.compose.foundation.layout.calculateStartPadding
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Settings
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import coil.compose.AsyncImage
|
||||
import com.meloda.app.fast.model.BaseError
|
||||
import com.meloda.app.fast.profile.ProfileViewModel
|
||||
import com.meloda.app.fast.profile.ProfileViewModelImpl
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
import com.meloda.app.fast.designsystem.R as UiR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ProfileScreen(
|
||||
onError: (BaseError) -> Unit,
|
||||
onNavigateToSettings: () -> Unit,
|
||||
viewModel: ProfileViewModel = koinViewModel<ProfileViewModelImpl>()
|
||||
) {
|
||||
val screenState by viewModel.screenState.collectAsStateWithLifecycle()
|
||||
|
||||
Log.d("ProfileScreen", "isLoading: ${screenState.isLoading}")
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {},
|
||||
actions = {
|
||||
IconButton(onClick = onNavigateToSettings) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Settings,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
},
|
||||
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent)
|
||||
)
|
||||
}
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(start = padding.calculateStartPadding(LayoutDirection.Ltr))
|
||||
.padding(end = padding.calculateEndPadding(LayoutDirection.Ltr))
|
||||
.padding(bottom = padding.calculateBottomPadding()),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
if (screenState.fullName == null && screenState.isLoading) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
} else {
|
||||
Spacer(modifier = Modifier.statusBarsPadding())
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
AsyncImage(
|
||||
modifier = Modifier
|
||||
.size(120.dp)
|
||||
.clip(CircleShape),
|
||||
model = screenState.avatarUrl,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
placeholder = painterResource(id = UiR.drawable.ic_account_circle_cut)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
|
||||
Text(
|
||||
text = screenState.fullName.orEmpty(),
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user