forked from melod1n/fast-messenger
account's info on profile screen; storing users into cache
This commit is contained in:
@@ -7,21 +7,14 @@ import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideIn
|
||||
import androidx.compose.animation.slideOut
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Settings
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarDefaults
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
@@ -31,7 +24,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
@@ -47,6 +39,8 @@ import com.meloda.app.fast.designsystem.LocalTheme
|
||||
import com.meloda.app.fast.friends.navigation.Friends
|
||||
import com.meloda.app.fast.friends.navigation.friendsRoute
|
||||
import com.meloda.app.fast.model.BaseError
|
||||
import com.meloda.app.fast.profile.navigation.Profile
|
||||
import com.meloda.app.fast.profile.navigation.profileRoute
|
||||
import dev.chrisbanes.haze.HazeState
|
||||
import dev.chrisbanes.haze.hazeChild
|
||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||
@@ -60,9 +54,6 @@ object MainGraph
|
||||
@Serializable
|
||||
object Main
|
||||
|
||||
@Serializable
|
||||
object Profile
|
||||
|
||||
data class BottomNavigationItem(
|
||||
val titleResId: Int,
|
||||
val selectedIconResId: Int,
|
||||
@@ -70,7 +61,7 @@ data class BottomNavigationItem(
|
||||
val route: Any,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalHazeMaterialsApi::class)
|
||||
@OptIn(ExperimentalHazeMaterialsApi::class)
|
||||
fun NavGraphBuilder.mainScreen(
|
||||
onError: (BaseError) -> Unit,
|
||||
onNavigateToSettings: () -> Unit,
|
||||
@@ -192,36 +183,13 @@ fun NavGraphBuilder.mainScreen(
|
||||
// isBottomBarVisible = isScrolling
|
||||
}
|
||||
)
|
||||
|
||||
composable<Profile> {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(text = stringResource(id = UiR.string.title_profile))
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = onNavigateToSettings) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Settings,
|
||||
contentDescription = null
|
||||
profileRoute(
|
||||
onError = onError,
|
||||
onNavigateToSettings = onNavigateToSettings,
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,22 @@ inline fun <T> State<T>.processState(
|
||||
success: (data: T) -> (Unit),
|
||||
idle: (() -> (Unit)) = {},
|
||||
loading: (() -> (Unit)) = {},
|
||||
any: () -> Unit = {}
|
||||
) {
|
||||
when (this) {
|
||||
is State.Error -> error(this)
|
||||
is State.Error -> {
|
||||
error(this)
|
||||
any()
|
||||
}
|
||||
|
||||
State.Idle -> idle()
|
||||
|
||||
State.Loading -> loading()
|
||||
is State.Success -> success(data)
|
||||
|
||||
is State.Success -> {
|
||||
success(data)
|
||||
any()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
package com.meloda.app.fast.data.api.users
|
||||
|
||||
import com.meloda.app.fast.model.api.data.VkUserData
|
||||
import com.meloda.app.fast.model.api.requests.UsersGetRequest
|
||||
import com.meloda.app.fast.model.api.domain.VkUser
|
||||
import com.meloda.app.fast.network.RestApiErrorDomain
|
||||
import com.slack.eithernet.ApiResult
|
||||
|
||||
interface UsersRepository {
|
||||
suspend fun getById(params: UsersGetRequest): List<VkUserData>
|
||||
|
||||
suspend fun get(
|
||||
userIds: List<Int>?,
|
||||
fields: String?,
|
||||
nomCase: String?
|
||||
): ApiResult<List<VkUser>, RestApiErrorDomain>
|
||||
|
||||
suspend fun getLocalUsers(userIds: List<Int>): List<VkUser>
|
||||
|
||||
suspend fun storeUsers(users: List<VkUser>)
|
||||
}
|
||||
|
||||
+50
-4
@@ -1,16 +1,62 @@
|
||||
package com.meloda.app.fast.data.api.users
|
||||
|
||||
import com.meloda.app.fast.data.VkMemoryCache
|
||||
import com.meloda.app.fast.database.dao.UsersDao
|
||||
import com.meloda.app.fast.model.api.data.VkUserData
|
||||
import com.meloda.app.fast.model.api.domain.VkUser
|
||||
import com.meloda.app.fast.model.api.domain.asEntity
|
||||
import com.meloda.app.fast.model.api.requests.UsersGetRequest
|
||||
import com.meloda.app.fast.model.database.VkUserEntity
|
||||
import com.meloda.app.fast.model.database.asExternalModel
|
||||
import com.meloda.app.fast.network.RestApiErrorDomain
|
||||
import com.meloda.app.fast.network.mapApiResult
|
||||
import com.meloda.app.fast.network.service.users.UsersService
|
||||
import com.slack.eithernet.ApiResult
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class UsersRepositoryImpl(
|
||||
private val usersService: UsersService
|
||||
private val service: UsersService,
|
||||
private val dao: UsersDao
|
||||
) : UsersRepository {
|
||||
|
||||
override suspend fun getById(params: UsersGetRequest): List<VkUserData> {
|
||||
// TODO: 05/05/2024, Danil Nikolaev: implement
|
||||
override suspend fun get(
|
||||
userIds: List<Int>?,
|
||||
fields: String?,
|
||||
nomCase: String?
|
||||
): ApiResult<List<VkUser>, RestApiErrorDomain> = withContext(Dispatchers.IO) {
|
||||
val requestModel = UsersGetRequest(
|
||||
userIds = userIds,
|
||||
fields = fields,
|
||||
nomCase = nomCase
|
||||
)
|
||||
|
||||
return emptyList()
|
||||
service.get(requestModel.map).mapApiResult(
|
||||
successMapper = { apiResponse ->
|
||||
val response = apiResponse.requireResponse()
|
||||
|
||||
val users = response.map(VkUserData::mapToDomain)
|
||||
|
||||
launch { storeUsers(users) }
|
||||
|
||||
VkMemoryCache.appendUsers(users)
|
||||
|
||||
users
|
||||
},
|
||||
errorMapper = { error ->
|
||||
error?.toDomain()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getLocalUsers(
|
||||
userIds: List<Int>
|
||||
): List<VkUser> = withContext(Dispatchers.IO) {
|
||||
dao.getAllByIds(userIds).map(VkUserEntity::asExternalModel)
|
||||
}
|
||||
|
||||
override suspend fun storeUsers(users: List<VkUser>) {
|
||||
dao.insertAll(users.map(VkUser::asEntity))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,14 @@ import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface UsersUseCase {
|
||||
|
||||
fun getUserById(
|
||||
userId: Int,
|
||||
fields: String?,
|
||||
nomCase: String?
|
||||
): Flow<State<VkUser?>>
|
||||
|
||||
fun getUsersByIds(
|
||||
userIds: List<Int>,
|
||||
fun get(
|
||||
userIds: List<Int>?,
|
||||
fields: String?,
|
||||
nomCase: String?
|
||||
): Flow<State<List<VkUser>>>
|
||||
|
||||
fun getLocalUser(userId: Int): Flow<State<VkUser?>>
|
||||
|
||||
suspend fun storeUser(user: VkUser)
|
||||
suspend fun storeUsers(users: List<VkUser>)
|
||||
}
|
||||
|
||||
@@ -1,67 +1,39 @@
|
||||
package com.meloda.app.fast.data.api.users
|
||||
|
||||
import com.meloda.app.fast.data.State
|
||||
import com.meloda.app.fast.data.mapToState
|
||||
import com.meloda.app.fast.model.api.domain.VkUser
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
|
||||
// TODO: 05/05/2024, Danil Nikolaev: implement
|
||||
class UsersUseCaseImpl(
|
||||
private val usersRepository: UsersRepository,
|
||||
private val repository: UsersRepository,
|
||||
) : UsersUseCase {
|
||||
|
||||
override fun getUserById(
|
||||
userId: Int,
|
||||
fields: String?,
|
||||
nomCase: String?
|
||||
): Flow<State<VkUser?>> = flow {
|
||||
// emit(State.Loading)
|
||||
//
|
||||
// val newState = usersRepository.getById(
|
||||
// UsersGetRequest(
|
||||
// userIds = listOf(userId),
|
||||
// fields = fields,
|
||||
// nomCase = nomCase
|
||||
// )
|
||||
// ).fold(
|
||||
// onSuccess = { response -> State.Success(response.singleOrNull()?.mapToDomain()) },
|
||||
// onNetworkFailure = { State.Error.ConnectionError },
|
||||
// onUnknownFailure = { State.UNKNOWN_ERROR },
|
||||
// onHttpFailure = { result -> result.error.toStateApiError() },
|
||||
// onApiFailure = { result -> result.error.toStateApiError() }
|
||||
// )
|
||||
// emit(newState)
|
||||
}
|
||||
|
||||
override fun getUsersByIds(
|
||||
userIds: List<Int>,
|
||||
override fun get(
|
||||
userIds: List<Int>?,
|
||||
fields: String?,
|
||||
nomCase: String?
|
||||
): Flow<State<List<VkUser>>> = flow {
|
||||
// emit(State.Loading)
|
||||
//
|
||||
// val newState = usersRepository.getById(
|
||||
// UsersGetRequest(
|
||||
// userIds = userIds,
|
||||
// fields = fields,
|
||||
// nomCase = nomCase
|
||||
// )
|
||||
// ).fold(
|
||||
// onSuccess = { response -> State.Success(response.map(VkUserData::mapToDomain)) },
|
||||
// onNetworkFailure = { State.Error.ConnectionError },
|
||||
// onUnknownFailure = { State.UNKNOWN_ERROR },
|
||||
// onHttpFailure = { result -> result.error.toStateApiError() },
|
||||
// onApiFailure = { result -> result.error.toStateApiError() }
|
||||
// )
|
||||
// emit(newState)
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = repository.get(userIds, fields, nomCase).mapToState()
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override suspend fun storeUser(user: VkUser) {
|
||||
override fun getLocalUser(userId: Int): Flow<State<VkUser?>> = flow {
|
||||
emit(State.Loading)
|
||||
|
||||
val newState = kotlin.runCatching {
|
||||
repository.getLocalUsers(listOf(userId)).singleOrNull()
|
||||
}.fold(
|
||||
onSuccess = { user -> State.Success(user) },
|
||||
onFailure = { State.Error.InternalError }
|
||||
)
|
||||
|
||||
emit(newState)
|
||||
}
|
||||
|
||||
override suspend fun storeUsers(users: List<VkUser>) {
|
||||
|
||||
}
|
||||
override suspend fun storeUser(user: VkUser) = repository.storeUsers(listOf(user))
|
||||
override suspend fun storeUsers(users: List<VkUser>) = repository.storeUsers(users)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ data class UsersGetRequest(
|
||||
val map
|
||||
get() = mutableMapOf<String, String>()
|
||||
.apply {
|
||||
userIds?.let { this["user_ids"] = it.joinToString() }
|
||||
userIds?.let { this["user_ids"] = it.joinToString(",") }
|
||||
fields?.let { this["fields"] = it }
|
||||
nomCase?.let { this["nom_case"] = it }
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.meloda.app.fast.model.database
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.meloda.app.fast.model.api.domain.OnlineStatus
|
||||
import com.meloda.app.fast.model.api.domain.VkUser
|
||||
|
||||
@Entity(tableName = "users")
|
||||
data class VkUserEntity(
|
||||
@@ -18,3 +20,20 @@ data class VkUserEntity(
|
||||
val photo100: String?,
|
||||
val photo200: String?
|
||||
)
|
||||
|
||||
fun VkUserEntity.asExternalModel(): VkUser = VkUser(
|
||||
id = id,
|
||||
firstName = firstName,
|
||||
lastName = lastName,
|
||||
onlineStatus = when {
|
||||
!isOnline -> OnlineStatus.Offline
|
||||
!isOnlineMobile -> OnlineStatus.Online(onlineAppId)
|
||||
else -> OnlineStatus.OnlineMobile(onlineAppId)
|
||||
},
|
||||
photo50 = photo50,
|
||||
photo100 = photo100,
|
||||
photo200 = photo200,
|
||||
lastSeen = lastSeen,
|
||||
lastSeenStatus = lastSeenStatus,
|
||||
birthday = birthday
|
||||
)
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ interface UsersService {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(UsersUrls.GET_BY_ID)
|
||||
suspend fun getById(
|
||||
suspend fun get(
|
||||
@FieldMap params: Map<String, String>?
|
||||
): ApiResult<ApiResponse<List<VkUserData>>, RestApiError>
|
||||
}
|
||||
|
||||
@@ -135,6 +135,16 @@ class LoginViewModelImpl(
|
||||
UserConfig.trustedHash = account.trustedHash
|
||||
}
|
||||
|
||||
usersUseCase.get(
|
||||
userIds = null,
|
||||
fields = VkConstants.USER_FIELDS,
|
||||
nomCase = null
|
||||
).listenValue { state ->
|
||||
state.processState(
|
||||
error = { error ->
|
||||
|
||||
},
|
||||
success = { response ->
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
accountsRepository.storeAccounts(listOf(currentAccount))
|
||||
|
||||
@@ -142,6 +152,11 @@ class LoginViewModelImpl(
|
||||
screenState.setValue { old -> old.copy(isNeedToNavigateToMain = true) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
screenState.setValue { old -> old.copy(isLoading = state.isLoading()) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun login(forceSms: Boolean = false) {
|
||||
val currentState = screenState.value.copy()
|
||||
@@ -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