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