diff --git a/core/src/main/java/org/futo/circles/core/feature/circles/filter/FilterTimelinesDataSource.kt b/core/src/main/java/org/futo/circles/core/feature/circles/filter/FilterTimelinesDataSource.kt index 4eed7fb305848fc7dad10cb89a20488b5e9ebce1..df94f0842c0ebfe548d16bc5d38fb560dfcc1018 100644 --- a/core/src/main/java/org/futo/circles/core/feature/circles/filter/FilterTimelinesDataSource.kt +++ b/core/src/main/java/org/futo/circles/core/feature/circles/filter/FilterTimelinesDataSource.kt @@ -1,8 +1,18 @@ package org.futo.circles.core.feature.circles.filter import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.asFlow +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.update +import org.futo.circles.core.extensions.createResult import org.futo.circles.core.extensions.getOrThrow +import org.futo.circles.core.model.toCircleFilterListItem import org.futo.circles.core.provider.MatrixSessionProvider +import org.futo.circles.core.utils.getTimelineRoomFor +import org.matrix.android.sdk.api.session.getRoom import javax.inject.Inject class FilterTimelinesDataSource @Inject constructor( @@ -11,7 +21,53 @@ class FilterTimelinesDataSource @Inject constructor( private val circleId: String = savedStateHandle.getOrThrow("circleId") - val circleSummaryLiveData = - MatrixSessionProvider.getSessionOrThrow().roomService().getRoomSummaryLive(circleId) + private val session = MatrixSessionProvider.getSessionOrThrow() + val circleSummaryLiveData = session.roomService().getRoomSummaryLive(circleId) + private val selectedTimelinesIds = MutableStateFlow(getCircleFilter()) + val timelinesLiveData = combine( + circleSummaryLiveData.asFlow(), + selectedTimelinesIds + ) { circle, selectedIds -> + val children = circle.getOrNull()?.spaceChildren ?: emptyList() + val myTimelineId = getTimelineRoomFor(circleId)?.roomId + children.mapNotNull { + session.getRoom(it.childRoomId)?.roomSummary()?.takeIf { summary -> + summary.membership.isActive() && summary.roomId != myTimelineId + }?.toCircleFilterListItem(isTimelineSelected(selectedIds, it.childRoomId)) + } + }.flowOn(Dispatchers.IO) + + suspend fun applyFilter() = createResult { + session.getRoom(circleId)?.roomAccountDataService() + ?.updateAccountData( + CIRCLE_FILTER_EVENT_TYPE, + mapOf(TIMELINES_KEY to selectedTimelinesIds.value) + ) + } + + fun toggleItemSelected(roomId: String) { + val isItemSelected = isTimelineSelected(selectedTimelinesIds.value, roomId) + selectedTimelinesIds.update { value -> + val newSet = value.toMutableSet() + if (isItemSelected) newSet.remove(roomId) + else newSet.add(roomId) + newSet + } + } + + private fun isTimelineSelected(selectedIds: Set<String>, roomId: String): Boolean = + if (selectedIds.isEmpty()) true + else selectedIds.contains(roomId) + + private fun getCircleFilter(): Set<String> { + val content = session.getRoom(circleId)?.roomAccountDataService() + ?.getAccountDataEvent(CIRCLE_FILTER_EVENT_TYPE)?.content ?: return emptySet() + return (content[TIMELINES_KEY] as? List<*>)?.map { it.toString() }?.toSet() ?: emptySet() + } + + companion object { + private const val CIRCLE_FILTER_EVENT_TYPE = "m.circle.filter" + private const val TIMELINES_KEY = "timelines" + } } \ No newline at end of file diff --git a/core/src/main/java/org/futo/circles/core/model/CircleFilterListItem.kt b/core/src/main/java/org/futo/circles/core/model/CircleFilterListItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..637ef8fa1bb688b16103abe5b8df306b295b04b1 --- /dev/null +++ b/core/src/main/java/org/futo/circles/core/model/CircleFilterListItem.kt @@ -0,0 +1,22 @@ +package org.futo.circles.core.model + +import org.futo.circles.core.base.list.IdEntity +import org.futo.circles.core.extensions.getRoomOwner +import org.futo.circles.core.mapping.nameOrId +import org.matrix.android.sdk.api.session.room.model.RoomSummary + +data class CircleFilterListItem( + override val id: String, + val name: String, + val ownerName: String, + val avatarUrl: String, + val isSelected: Boolean +) : IdEntity<String> + +fun RoomSummary.toCircleFilterListItem(isSelected: Boolean = true) = CircleFilterListItem( + id = roomId, + name = nameOrId(), + ownerName = getRoomOwner(roomId)?.displayName ?: "", + avatarUrl = avatarUrl, + isSelected = isSelected +) \ No newline at end of file