forked from melod1n/fast-messenger
feat: extend friends data support and refactor profile state management
This commit is contained in:
@@ -2,6 +2,8 @@ package dev.meloda.fast.common.extensions
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -40,6 +42,10 @@ fun <T> MutableList<T>.removeIfCompat(condition: (T) -> Boolean): Boolean {
|
||||
return removed
|
||||
}
|
||||
|
||||
context(viewModel: ViewModel)
|
||||
fun <T> Flow<T>.listenValue(action: suspend (T) -> Unit): Job =
|
||||
listenValue(viewModel.viewModelScope, action)
|
||||
|
||||
fun <T> Flow<T>.listenValue(
|
||||
coroutineScope: CoroutineScope,
|
||||
action: suspend (T) -> Unit
|
||||
|
||||
@@ -35,7 +35,7 @@ object VkMemoryCache {
|
||||
}
|
||||
|
||||
fun appendContacts(contacts: List<VkContactDomain>) {
|
||||
contacts.forEach { contact -> VkMemoryCache.contacts[contact.userId] = contact }
|
||||
contacts.forEach { contact -> VkMemoryCache[contact.userId] = contact }
|
||||
}
|
||||
|
||||
operator fun set(userid: Long, user: VkUser) {
|
||||
|
||||
@@ -129,6 +129,10 @@ class ConvosRepositoryImpl(
|
||||
val groupsList = response.groups.orEmpty().map(VkGroupData::mapToDomain)
|
||||
val contactsList = response.contacts.orEmpty().map(VkContactData::mapToDomain)
|
||||
|
||||
VkMemoryCache.appendUsers(profilesList)
|
||||
VkMemoryCache.appendGroups(groupsList)
|
||||
VkMemoryCache.appendContacts(contactsList)
|
||||
|
||||
val usersMap = VkUsersMap.forUsers(profilesList)
|
||||
val groupsMap = VkGroupsMap.forGroups(groupsList)
|
||||
|
||||
@@ -147,10 +151,6 @@ class ConvosRepositoryImpl(
|
||||
groupDao.insertAll(groupsList.map(VkGroupDomain::asEntity))
|
||||
}
|
||||
|
||||
VkMemoryCache.appendUsers(profilesList)
|
||||
VkMemoryCache.appendGroups(groupsList)
|
||||
VkMemoryCache.appendContacts(contactsList)
|
||||
|
||||
convos
|
||||
},
|
||||
errorMapper = { error ->
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package dev.meloda.fast.data.api.friends
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
import com.slack.eithernet.successOrElse
|
||||
import dev.meloda.fast.common.VkConstants
|
||||
import dev.meloda.fast.data.VkMemoryCache
|
||||
import dev.meloda.fast.database.dao.UserDao
|
||||
import dev.meloda.fast.model.FriendsInfo
|
||||
import dev.meloda.fast.model.api.data.VkContactData
|
||||
import dev.meloda.fast.model.api.data.VkUserData
|
||||
import dev.meloda.fast.model.api.domain.VkUser
|
||||
import dev.meloda.fast.model.api.domain.asEntity
|
||||
@@ -13,8 +16,6 @@ import dev.meloda.fast.network.RestApiErrorDomain
|
||||
import dev.meloda.fast.network.mapApiDefault
|
||||
import dev.meloda.fast.network.mapApiResult
|
||||
import dev.meloda.fast.network.service.friends.FriendsService
|
||||
import com.slack.eithernet.ApiResult
|
||||
import com.slack.eithernet.successOrElse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -51,14 +52,18 @@ class FriendsRepositoryImpl(
|
||||
order = order,
|
||||
count = count,
|
||||
offset = offset,
|
||||
fields = VkConstants.USER_FIELDS
|
||||
fields = VkConstants.USER_FIELDS,
|
||||
extended = true
|
||||
)
|
||||
service.getFriends(requestModel.map).mapApiResult(
|
||||
successMapper = { apiResponse ->
|
||||
val response = apiResponse.requireResponse()
|
||||
|
||||
val users = response.items.map(VkUserData::mapToDomain)
|
||||
val contactsList = response.contacts.orEmpty().map(VkContactData::mapToDomain)
|
||||
|
||||
VkMemoryCache.appendUsers(users)
|
||||
VkMemoryCache.appendContacts(contactsList)
|
||||
|
||||
users
|
||||
},
|
||||
|
||||
@@ -4,7 +4,8 @@ data class GetFriendsRequest(
|
||||
val order: String?,
|
||||
val count: Int?,
|
||||
val offset: Int?,
|
||||
val fields: String?
|
||||
val fields: String?,
|
||||
val extended: Boolean?
|
||||
) {
|
||||
|
||||
val map
|
||||
@@ -14,6 +15,7 @@ data class GetFriendsRequest(
|
||||
count?.let { this["count"] = it.toString() }
|
||||
offset?.let { this["offset"] = it.toString() }
|
||||
fields?.let { this["fields"] = it }
|
||||
extended?.let { this["extended"] = it.toString() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package dev.meloda.fast.model.api.responses
|
||||
|
||||
import dev.meloda.fast.model.api.data.VkUserData
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import dev.meloda.fast.model.api.data.VkContactData
|
||||
import dev.meloda.fast.model.api.data.VkUserData
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class GetFriendsResponse(
|
||||
@Json(name = "count") val count: Int,
|
||||
@Json(name = "items") val items: List<VkUserData>
|
||||
@Json(name = "items") val items: List<VkUserData>,
|
||||
@Json(name = "contacts") val contacts: List<VkContactData>?
|
||||
)
|
||||
|
||||
+4
-4
@@ -21,11 +21,11 @@ fun NavGraphBuilder.friendsScreen(
|
||||
onMessageClicked: (userId: Long) -> Unit,
|
||||
onScrolledToTop: () -> Unit
|
||||
) {
|
||||
val friendsViewModel: FriendsViewModel = activity.getViewModel<FriendsViewModelImpl>()
|
||||
val onlineFriendsViewModel =
|
||||
activity.getViewModel<OnlineFriendsViewModelImpl>()
|
||||
|
||||
composable<Friends> {
|
||||
val friendsViewModel: FriendsViewModel = activity.getViewModel<FriendsViewModelImpl>()
|
||||
val onlineFriendsViewModel =
|
||||
activity.getViewModel<OnlineFriendsViewModelImpl>()
|
||||
|
||||
FriendsRoute(
|
||||
friendsViewModel = friendsViewModel,
|
||||
onlineFriendsViewModel = onlineFriendsViewModel,
|
||||
|
||||
@@ -9,47 +9,54 @@ import dev.meloda.fast.data.UserConfig
|
||||
import dev.meloda.fast.data.processState
|
||||
import dev.meloda.fast.domain.GetLocalUserByIdUseCase
|
||||
import dev.meloda.fast.domain.LoadUserByIdUseCase
|
||||
import dev.meloda.fast.logger.FastLogger
|
||||
import dev.meloda.fast.profile.model.ProfileScreenState
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class ProfileViewModel(
|
||||
private val getLocalUserByIdUseCase: GetLocalUserByIdUseCase,
|
||||
private val loadUserByIdUseCase: LoadUserByIdUseCase
|
||||
private val loadUserByIdUseCase: LoadUserByIdUseCase,
|
||||
private val logger: FastLogger
|
||||
) : ViewModel() {
|
||||
|
||||
private val screenState = MutableStateFlow(ProfileScreenState.EMPTY)
|
||||
val screenStateFlow get() = screenState.asStateFlow()
|
||||
|
||||
init {
|
||||
getLocalAccountInfo()
|
||||
}
|
||||
|
||||
fun screenStateFlow(): StateFlow<ProfileScreenState> = screenState.asStateFlow()
|
||||
|
||||
private fun getLocalAccountInfo() {
|
||||
getLocalUserByIdUseCase(UserConfig.userId)
|
||||
.listenValue(viewModelScope) { state ->
|
||||
state.processState(
|
||||
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
|
||||
)
|
||||
}
|
||||
logger.debug(this@ProfileViewModel::class, "START")
|
||||
emit(screenState.value.copy(isLoading = true))
|
||||
|
||||
getLocalUserByIdUseCase(UserConfig.userId).listenValue { state ->
|
||||
logger.debug(this@ProfileViewModel::class, "LOADED: $state")
|
||||
|
||||
emit(screenState.value.copy(isLoading = false))
|
||||
|
||||
state.processState(
|
||||
error = {
|
||||
logger.debug(this@ProfileViewModel::class, "ERROR")
|
||||
emit(screenState.value.copy(avatarUrl = null, fullName = null))
|
||||
},
|
||||
success = { user ->
|
||||
logger.debug(this@ProfileViewModel::class, "SUCCESS")
|
||||
emit(
|
||||
screenState.value.copy(
|
||||
avatarUrl = user?.photo200,
|
||||
fullName = user?.fullName
|
||||
)
|
||||
)
|
||||
},
|
||||
any = ::loadAccountInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun emit(state: ProfileScreenState) {
|
||||
screenState.setValue { state }
|
||||
}
|
||||
|
||||
private fun loadAccountInfo() {
|
||||
|
||||
@@ -18,10 +18,9 @@ fun NavGraphBuilder.profileScreen(
|
||||
onSettingsButtonClicked: () -> Unit,
|
||||
onPhotoClicked: (url: String) -> Unit
|
||||
) {
|
||||
val viewModel: ProfileViewModel = with(activity) { getViewModel() }
|
||||
|
||||
composable<Profile> {
|
||||
val screenState by viewModel.screenStateFlow().collectAsStateWithLifecycle()
|
||||
val viewModel: ProfileViewModel = activity.getViewModel()
|
||||
val screenState by viewModel.screenStateFlow.collectAsStateWithLifecycle()
|
||||
|
||||
ProfileRoute(
|
||||
screenState = screenState,
|
||||
|
||||
Reference in New Issue
Block a user