Skip to content
Snippets Groups Projects
Commit 83777ad8 authored by Taras's avatar Taras
Browse files

Observe all knocks logic WIP

parent e17f4b32
No related branches found
No related tags found
No related merge requests found
Showing
with 122 additions and 82 deletions
......@@ -54,10 +54,9 @@ class TimelineViewModel @Inject constructor(
val saveToDeviceLiveData = SingleEventLiveData<Unit>()
val ignoreUserLiveData = SingleEventLiveData<Response<Unit?>>()
val unSendReactionLiveData = SingleEventLiveData<Response<Cancelable?>>()
val knockRequestCountLiveData =
knockRequestsDataSource.getKnockRequestCountLiveDataForCurrentUserInRoom(
timelineId ?: roomId
)
val knockRequestCountLiveData = knockRequestsDataSource.getKnockRequestCountFlow(
timelineId ?: roomId
).asLiveData()
fun sharePostContent(content: PostContent, view: View) {
......
package org.futo.circles.core.feature.room.requests
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asFlow
import androidx.lifecycle.asLiveData
import androidx.lifecycle.map
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import org.futo.circles.core.extensions.isCurrentUserAbleToInvite
import org.futo.circles.core.mapping.toKnockRequestListItem
import org.futo.circles.core.model.KnockRequestListItem
import org.futo.circles.core.provider.MatrixSessionProvider
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.EventType
......@@ -22,31 +21,41 @@ import javax.inject.Inject
class KnockRequestsDataSource @Inject constructor() {
fun getKnockRequestsListItemsLiveData(roomId: String) = getKnockRequestLiveData(roomId)?.map {
it.map { user -> user.toKnockRequestListItem(roomId) }
} ?: MutableLiveData(emptyList())
fun getKnockRequestCountLiveDataForCurrentUserInRoom(roomId: String): LiveData<Int> {
fun getKnockRequestsListItemsFlow(roomId: String): Flow<List<KnockRequestListItem>> {
val powerLevelsFlow = getRoomPowerLevelsFlow(roomId)
val knockRequestsFlow = getKnockRequestFlow(roomId)
return combine(powerLevelsFlow, knockRequestsFlow) { powerLevels, knockRequest ->
if (powerLevels.isCurrentUserAbleToInvite()) {
knockRequest.map {
it.toKnockRequestListItem(roomId)
}
} else {
emptyList()
}
}
}
fun getKnockRequestCountFlow(roomId: String): Flow<Int> =
getKnockRequestsListItemsFlow(roomId).map { it.size }
private fun getRoomPowerLevelsFlow(roomId: String): Flow<PowerLevelsContent> {
val session = MatrixSessionProvider.getSessionOrThrow()
val powerLevelsFlow = session.getRoom(roomId)?.stateService()
return session.getRoom(roomId)?.stateService()
?.getStateEventLive(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.IsEmpty)
?.asFlow()
?.mapNotNull { it.getOrNull()?.content.toModel<PowerLevelsContent>() } ?: flowOf()
val knockRequestsFlow = getKnockRequestLiveData(roomId)?.asFlow() ?: flowOf()
return combine(powerLevelsFlow, knockRequestsFlow) { powerLevels, knockRequest ->
if (powerLevels.isCurrentUserAbleToInvite()) knockRequest.size
else 0
}.asLiveData()
}
private fun getKnockRequestLiveData(roomId: String) =
private fun getKnockRequestFlow(roomId: String) =
MatrixSessionProvider.currentSession?.getRoom(roomId)?.membershipService()
?.getRoomMembersLive(
roomMemberQueryParams {
excludeSelf = true
memberships = listOf(Membership.KNOCK)
}
)
)?.asFlow() ?: flowOf()
}
\ No newline at end of file
......@@ -6,36 +6,77 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.withContext
import org.futo.circles.core.extensions.getKnownUsersFlow
import org.futo.circles.core.mapping.toRoomInviteListItem
import org.futo.circles.core.model.CircleRoomTypeArg
import org.futo.circles.core.model.RoomInviteListItem
import org.futo.circles.core.model.RoomRequestHeaderItem
import org.futo.circles.core.model.RoomRequestListItem
import org.futo.circles.core.model.convertToCircleRoomType
import org.futo.circles.core.model.convertToStringRoomType
import org.futo.circles.core.provider.MatrixSessionProvider
import org.futo.circles.core.utils.getAllRoomsLiveData
import org.futo.circles.core.utils.getRoomsLiveDataWithType
import org.futo.circles.core.utils.getRoomsWithType
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import javax.inject.Inject
class RoomRequestsDataSource @Inject constructor() {
class RoomRequestsDataSource @Inject constructor(
private val knockRequestsDataSource: KnockRequestsDataSource
) {
private val loadingItemsIdsList = MutableStateFlow<Set<String>>(emptySet())
private val roomIdsToUnblurProfile = MutableStateFlow<Set<String>>(emptySet())
fun getRoomInvitesFlow(
fun getRequestsFlow(inviteType: CircleRoomTypeArg, roomId: String?) = roomId?.let {
knockRequestsDataSource.getKnockRequestsListItemsFlow(it)
} ?: run {
combine(
getRoomInvitesFlow(inviteType),
getKnockRequestFlow(inviteType)
) { invites, knocks ->
mutableListOf<RoomRequestListItem>().apply {
addSection(
RoomRequestHeaderItem.invitesHeader,
invites
)
addSection(
RoomRequestHeaderItem.requestForInviteHeader,
knocks
)
}
}
}
fun unblurProfileImageFor(id: String) {
roomIdsToUnblurProfile.update { set -> set.toMutableSet().apply { add(id) } }
}
fun toggleItemLoading(id: String) {
loadingItemsIdsList.update { set ->
set.toMutableSet().apply {
if (this.contains(id)) remove(id)
else add(id)
}
}
}
private fun getRoomInvitesFlow(
inviteType: CircleRoomTypeArg
): Flow<List<RoomInviteListItem>> = combine(
getAllRoomsLiveData(listOf(Membership.INVITE)).asFlow(),
getRoomsLiveDataWithType(convertToStringRoomType(inviteType), listOf(Membership.INVITE))
.asFlow(),
MatrixSessionProvider.getSessionOrThrow().getKnownUsersFlow(),
roomIdsToUnblurProfile
) { roomSummaries, knownUsers, roomIdsToUnblur ->
withContext(Dispatchers.IO) {
val knownUsersIds = knownUsers.map { it.userId }.toSet()
roomSummaries.filter {
it.roomType == convertToStringRoomType(inviteType)
}.map {
roomSummaries.map {
it.toRoomInviteListItem(
convertToCircleRoomType(it.roomType),
shouldBlurIconFor(it, knownUsersIds, roomIdsToUnblur)
......@@ -45,9 +86,10 @@ class RoomRequestsDataSource @Inject constructor() {
}.distinctUntilChanged()
fun getKnockRequestFlow() {
}
private fun getKnockRequestFlow(inviteType: CircleRoomTypeArg) = getRoomsWithType(
convertToStringRoomType(inviteType), listOf(Membership.JOIN)
).map { knockRequestsDataSource.getKnockRequestsListItemsFlow(it.roomId) }.merge()
.distinctUntilChanged()
private fun shouldBlurIconFor(
roomSummary: RoomSummary,
......@@ -60,7 +102,13 @@ class RoomRequestsDataSource @Inject constructor() {
return !isKnownUser && !isRoomUnbluredByUser && hasIcon
}
fun unblurProfileImageFor(id: String) {
roomIdsToUnblurProfile.update { set -> set.toMutableSet().apply { add(id) } }
private fun MutableList<RoomRequestListItem>.addSection(
title: RoomRequestHeaderItem,
items: List<RoomRequestListItem>
) {
if (items.isNotEmpty()) {
add(title)
addAll(items)
}
}
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DividerItemDecoration
import dagger.hilt.android.AndroidEntryPoint
import org.futo.circles.core.R
......@@ -25,6 +26,7 @@ class RoomRequestsDialogFragment :
DialogFragmentRoomRequestsBinding::inflate
) {
private val args: RoomRequestsDialogFragmentArgs by navArgs()
private val viewModel by viewModels<RoomRequestsViewModel>()
private val roomRequestsAdapter by lazy {
......@@ -57,12 +59,12 @@ class RoomRequestsDialogFragment :
}
private fun setupObservers() {
viewModel.invitesLiveData.observeData(this) { roomRequestsAdapter.submitList(it) }
viewModel.inviteResultLiveData.observeResponse(this)
viewModel.requestsLiveData.observeData(this) { roomRequestsAdapter.submitList(it) }
viewModel.requestResultLiveData.observeResponse(this)
}
private fun getTitle(): String = getString(
when (viewModel.getInviteType()) {
when (args.type) {
CircleRoomTypeArg.Circle -> R.string.circle_invitations
CircleRoomTypeArg.Group -> R.string.group_invitations
CircleRoomTypeArg.Photo -> R.string.gallery_invitations
......
package org.futo.circles.core.feature.room.requests
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
......@@ -13,38 +11,24 @@ import org.futo.circles.core.extensions.launchBg
import org.futo.circles.core.feature.room.invite.ManageInviteRequestsDataSource
import org.futo.circles.core.model.CircleRoomTypeArg
import org.futo.circles.core.model.KnockRequestListItem
import org.futo.circles.core.model.RoomInviteListItem
import javax.inject.Inject
@HiltViewModel
class RoomRequestsViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val dataSource: RoomRequestsDataSource,
private val requestsDataSource: RoomRequestsDataSource,
private val manageInviteRequestsDataSource: ManageInviteRequestsDataSource
) : ViewModel() {
private val inviteType: CircleRoomTypeArg = savedStateHandle.getOrThrow("type")
private val roomId: String? = savedStateHandle["roomId"]
val inviteResultLiveData = SingleEventLiveData<Response<Unit?>>()
private val loadingItemsIdsList = MutableLiveData<Set<String>>(emptySet())
val invitesLiveData = MediatorLiveData<List<RoomInviteListItem>>().also {
it.addSource(loadingItemsIdsList) { loadingItemsValue ->
val currentList = it.value ?: emptyList()
it.postValue(currentList.map { item ->
item.copy(isLoading = loadingItemsValue.contains(item.id))
})
}
it.addSource(dataSource.getRoomInvitesFlow(inviteType).asLiveData()) { value ->
it.postValue(value)
}
}
fun getInviteType() = inviteType
val requestResultLiveData = SingleEventLiveData<Response<Unit?>>()
val requestsLiveData = requestsDataSource.getRequestsFlow(inviteType, roomId).asLiveData()
fun rejectRoomInvite(roomId: String) {
launchBg {
toggleItemLoading(roomId)
requestsDataSource.toggleItemLoading(roomId)
val result = manageInviteRequestsDataSource.rejectInvite(roomId)
postInviteResult(result, roomId)
}
......@@ -52,7 +36,7 @@ class RoomRequestsViewModel @Inject constructor(
fun acceptRoomInvite(roomId: String, roomType: CircleRoomTypeArg) {
launchBg {
toggleItemLoading(roomId)
requestsDataSource.toggleItemLoading(roomId)
val result = manageInviteRequestsDataSource.acceptInvite(roomId, roomType)
postInviteResult(result, roomId)
}
......@@ -61,38 +45,28 @@ class RoomRequestsViewModel @Inject constructor(
fun inviteUser(knockRequest: KnockRequestListItem) {
roomId ?: return
launchBg {
toggleItemLoading(knockRequest.id)
requestsDataSource.toggleItemLoading(knockRequest.id)
val result = manageInviteRequestsDataSource.inviteUser(roomId, knockRequest.requesterId)
inviteResultLiveData.postValue(result)
toggleItemLoading(knockRequest.id)
postInviteResult(result, knockRequest.id)
}
}
fun kickUser(knockRequest: KnockRequestListItem) {
roomId ?: return
launchBg {
toggleItemLoading(knockRequest.id)
manageInviteRequestsDataSource.kickUser(roomId, knockRequest.requesterId)
toggleItemLoading(knockRequest.id)
requestsDataSource.toggleItemLoading(knockRequest.id)
val result = manageInviteRequestsDataSource.kickUser(roomId, knockRequest.requesterId)
postInviteResult(result, knockRequest.id)
}
}
fun unblurProfileIcon(roomId: String) {
dataSource.unblurProfileImageFor(roomId)
requestsDataSource.unblurProfileImageFor(roomId)
}
private fun postInviteResult(result: Response<Unit?>, id: String) {
inviteResultLiveData.postValue(result)
toggleItemLoading(id)
}
private fun toggleItemLoading(id: String) {
val currentSet = loadingItemsIdsList.value?.toMutableSet() ?: return
val newLoadingSet = currentSet.apply {
if (this.contains(id)) remove(id)
else add(id)
}
loadingItemsIdsList.postValue(newLoadingSet)
requestResultLiveData.postValue(result)
requestsDataSource.toggleItemLoading(id)
}
}
\ No newline at end of file
......@@ -9,8 +9,8 @@ import org.futo.circles.core.extensions.Response
import org.futo.circles.core.extensions.getOrThrow
import org.futo.circles.core.extensions.launchBg
import org.futo.circles.core.feature.room.RoomNotificationsDataSource
import org.futo.circles.core.feature.room.requests.KnockRequestsDataSource
import org.futo.circles.core.feature.room.leave.LeaveRoomDataSource
import org.futo.circles.core.feature.room.requests.KnockRequestsDataSource
import org.futo.circles.core.feature.timeline.data_source.AccessLevelDataSource
import org.futo.circles.core.model.CircleRoomTypeArg
import org.futo.circles.core.provider.MatrixSessionProvider
......@@ -32,10 +32,9 @@ class TimelineOptionsViewModel @Inject constructor(
val leaveDeleteEventLiveData = SingleEventLiveData<Response<Unit?>>()
val accessLevelLiveData = accessLevelDataSource.accessLevelFlow.asLiveData()
val notificationsStateLiveData = roomNotificationsDataSource.notificationsStateLiveData
val knockRequestCountLiveData =
knockRequestsDataSource.getKnockRequestCountLiveDataForCurrentUserInRoom(
timelineId ?: roomId
)
val knockRequestCountLiveData = knockRequestsDataSource.getKnockRequestCountFlow(
timelineId ?: roomId
).asLiveData()
val roomSummaryLiveData =
MatrixSessionProvider.getSessionOrThrow().getRoom(roomId)?.getRoomSummaryLive()
......
package org.futo.circles.core.model
import org.futo.circles.core.R
import org.futo.circles.core.base.list.IdEntity
sealed class RoomRequestListItem : IdEntity<String>
......@@ -8,6 +9,11 @@ data class RoomRequestHeaderItem(
val titleRes: Int
) : RoomRequestListItem() {
override val id: String = titleRes.toString()
companion object {
val invitesHeader = RoomRequestHeaderItem(R.string.invites)
val requestForInviteHeader = RoomRequestHeaderItem(R.string.requests_for_invitation)
}
}
data class RoomInviteListItem(
......
......@@ -32,13 +32,13 @@ val circlesRoomsTypes = listOf(
GROUP_TYPE
)
private fun getRoomsLiveDataWithType(
fun getRoomsLiveDataWithType(
type: String,
membershipFilter: List<Membership> = Membership.activeMemberships()
) = MatrixSessionProvider.getSessionOrThrow().roomService()
.getRoomSummariesLive(getCirclesRoomTypeFilter(type, membershipFilter))
private fun getRoomsWithType(
fun getRoomsWithType(
type: String,
membershipFilter: List<Membership> = Membership.activeMemberships()
) = MatrixSessionProvider.getSessionOrThrow().roomService()
......
......@@ -16,6 +16,7 @@
<argument
android:name="roomId"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
......
......@@ -2,6 +2,7 @@ package org.futo.circles.gallery.feature.gallery
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.map
import dagger.hilt.android.lifecycle.HiltViewModel
import org.futo.circles.core.base.SingleEventLiveData
......@@ -26,5 +27,6 @@ class GalleryDialogFragmentViewModel @Inject constructor(
val deleteGalleryLiveData = SingleEventLiveData<Response<Unit?>>()
val knockRequestCountLiveData = knockRequestsDataSource.getKnockRequestCountLiveDataForCurrentUserInRoom(roomId)
val knockRequestCountLiveData =
knockRequestsDataSource.getKnockRequestCountFlow(roomId).asLiveData()
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment