diff --git a/.idea/dictionaries/ganfra.xml b/.idea/dictionaries/ganfra.xml
index 7e1fdcddbb..c3f99f8d70 100644
--- a/.idea/dictionaries/ganfra.xml
+++ b/.idea/dictionaries/ganfra.xml
@@ -6,6 +6,8 @@
       <w>merlins</w>
       <w>moshi</w>
       <w>persistor</w>
+      <w>restorable</w>
+      <w>restorables</w>
       <w>synchronizer</w>
       <w>untimelined</w>
     </words>
diff --git a/app/src/main/java/im/vector/riotredesign/Riot.kt b/app/src/main/java/im/vector/riotredesign/Riot.kt
index 8385443ce8..acc59cdee1 100644
--- a/app/src/main/java/im/vector/riotredesign/Riot.kt
+++ b/app/src/main/java/im/vector/riotredesign/Riot.kt
@@ -23,6 +23,7 @@ import com.facebook.stetho.Stetho
 import com.jakewharton.threetenabp.AndroidThreeTen
 import im.vector.matrix.android.BuildConfig
 import im.vector.riotredesign.core.di.AppModule
+import im.vector.riotredesign.features.home.HomeModule
 import org.koin.log.EmptyLogger
 import org.koin.standalone.StandAloneContext.startKoin
 import timber.log.Timber
@@ -32,12 +33,15 @@ class Riot : Application() {
 
     override fun onCreate() {
         super.onCreate()
+        applicationContext.setTheme(R.style.Theme_Riot)
         if (BuildConfig.DEBUG) {
             Timber.plant(Timber.DebugTree())
             Stetho.initializeWithDefaults(this)
         }
         AndroidThreeTen.init(this)
-        startKoin(listOf(AppModule(this).definition), logger = EmptyLogger())
+        val appModule = AppModule(applicationContext).definition
+        val homeModule = HomeModule(applicationContext).definition
+        startKoin(listOf(appModule, homeModule), logger = EmptyLogger())
     }
 
     override fun attachBaseContext(base: Context) {
diff --git a/app/src/main/java/im/vector/riotredesign/core/di/AppModule.kt b/app/src/main/java/im/vector/riotredesign/core/di/AppModule.kt
index bbc973152c..f67c9c11d8 100644
--- a/app/src/main/java/im/vector/riotredesign/core/di/AppModule.kt
+++ b/app/src/main/java/im/vector/riotredesign/core/di/AppModule.kt
@@ -18,10 +18,14 @@ package im.vector.riotredesign.core.di
 
 import android.content.Context
 import android.content.Context.MODE_PRIVATE
+import im.vector.matrix.android.api.Matrix
 import im.vector.riotredesign.core.resources.ColorProvider
 import im.vector.riotredesign.core.resources.LocaleProvider
 import im.vector.riotredesign.core.resources.StringProvider
+import im.vector.riotredesign.features.home.group.SelectedGroupStore
+import im.vector.riotredesign.features.home.room.VisibleRoomStore
 import im.vector.riotredesign.features.home.room.list.RoomSelectionRepository
+import im.vector.riotredesign.features.home.room.list.RoomSummaryComparator
 import org.koin.dsl.module.module
 
 class AppModule(private val context: Context) {
@@ -48,5 +52,22 @@ class AppModule(private val context: Context) {
             RoomSelectionRepository(get())
         }
 
+        single {
+            SelectedGroupStore()
+        }
+
+        single {
+            VisibleRoomStore()
+        }
+
+        single {
+            RoomSummaryComparator()
+        }
+
+        factory {
+            Matrix.getInstance().currentSession
+        }
+
+
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/core/epoxy/LayoutManagerStateRestorer.kt b/app/src/main/java/im/vector/riotredesign/core/epoxy/LayoutManagerStateRestorer.kt
new file mode 100644
index 0000000000..b4b9f181af
--- /dev/null
+++ b/app/src/main/java/im/vector/riotredesign/core/epoxy/LayoutManagerStateRestorer.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.riotredesign.core.epoxy
+
+import android.os.Bundle
+import android.os.Parcelable
+import androidx.recyclerview.widget.RecyclerView
+import im.vector.riotredesign.core.platform.DefaultListUpdateCallback
+import im.vector.riotredesign.core.platform.Restorable
+import java.util.concurrent.atomic.AtomicReference
+
+private const val LAYOUT_MANAGER_STATE = "LAYOUT_MANAGER_STATE"
+
+class LayoutManagerStateRestorer(private val layoutManager: RecyclerView.LayoutManager) : Restorable, DefaultListUpdateCallback {
+
+    private var layoutManagerState = AtomicReference<Parcelable?>()
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        val layoutManagerState = layoutManager.onSaveInstanceState()
+        outState.putParcelable(LAYOUT_MANAGER_STATE, layoutManagerState)
+    }
+
+    override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
+        val parcelable = savedInstanceState?.getParcelable<Parcelable>(LAYOUT_MANAGER_STATE)
+        layoutManagerState.set(parcelable)
+    }
+
+    override fun onInserted(position: Int, count: Int) {
+        layoutManagerState.getAndSet(null)?.also {
+            layoutManager.onRestoreInstanceState(it)
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/core/platform/Restorable.kt b/app/src/main/java/im/vector/riotredesign/core/platform/Restorable.kt
new file mode 100644
index 0000000000..683fed732f
--- /dev/null
+++ b/app/src/main/java/im/vector/riotredesign/core/platform/Restorable.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.riotredesign.core.platform
+
+import android.os.Bundle
+
+interface Restorable {
+
+    fun onSaveInstanceState(outState: Bundle)
+
+    fun onRestoreInstanceState(savedInstanceState: Bundle?)
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/core/platform/RiotActivity.kt b/app/src/main/java/im/vector/riotredesign/core/platform/RiotActivity.kt
index 2465399d2f..db1aa476fb 100644
--- a/app/src/main/java/im/vector/riotredesign/core/platform/RiotActivity.kt
+++ b/app/src/main/java/im/vector/riotredesign/core/platform/RiotActivity.kt
@@ -16,13 +16,34 @@
 
 package im.vector.riotredesign.core.platform
 
+import android.os.Bundle
+import androidx.annotation.MainThread
 import com.airbnb.mvrx.BaseMvRxActivity
+import com.bumptech.glide.util.Util
 import io.reactivex.disposables.CompositeDisposable
 import io.reactivex.disposables.Disposable
 
 abstract class RiotActivity : BaseMvRxActivity() {
 
     private val uiDisposables = CompositeDisposable()
+    private val restorables = ArrayList<Restorable>()
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        super.onSaveInstanceState(outState)
+        restorables.forEach { it.onSaveInstanceState(outState) }
+    }
+
+    override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
+        restorables.forEach { it.onRestoreInstanceState(savedInstanceState) }
+        super.onRestoreInstanceState(savedInstanceState)
+    }
+
+    @MainThread
+    protected fun <T : Restorable> T.register(): T {
+        Util.assertMainThread()
+        restorables.add(this)
+        return this
+    }
 
     protected fun Disposable.disposeOnDestroy(): Disposable {
         uiDisposables.add(this)
diff --git a/app/src/main/java/im/vector/riotredesign/core/platform/RiotFragment.kt b/app/src/main/java/im/vector/riotredesign/core/platform/RiotFragment.kt
index 72a7f4b291..0b7996fa29 100644
--- a/app/src/main/java/im/vector/riotredesign/core/platform/RiotFragment.kt
+++ b/app/src/main/java/im/vector/riotredesign/core/platform/RiotFragment.kt
@@ -18,8 +18,10 @@ package im.vector.riotredesign.core.platform
 
 import android.os.Bundle
 import android.os.Parcelable
+import androidx.annotation.MainThread
 import com.airbnb.mvrx.BaseMvRxFragment
 import com.airbnb.mvrx.MvRx
+import com.bumptech.glide.util.Util.assertMainThread
 
 abstract class RiotFragment : BaseMvRxFragment(), OnBackPressed {
 
@@ -27,6 +29,18 @@ abstract class RiotFragment : BaseMvRxFragment(), OnBackPressed {
         activity as RiotActivity
     }
 
+    private val restorables = ArrayList<Restorable>()
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        super.onSaveInstanceState(outState)
+        restorables.forEach { it.onSaveInstanceState(outState) }
+    }
+
+    override fun onViewStateRestored(savedInstanceState: Bundle?) {
+        restorables.forEach { it.onRestoreInstanceState(savedInstanceState) }
+        super.onViewStateRestored(savedInstanceState)
+    }
+
     override fun onBackPressed(): Boolean {
         return false
     }
@@ -39,4 +53,11 @@ abstract class RiotFragment : BaseMvRxFragment(), OnBackPressed {
         arguments = args?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
     }
 
+    @MainThread
+    protected fun <T : Restorable> T.register(): T {
+        assertMainThread()
+        restorables.add(this)
+        return this
+    }
+
 }
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt b/app/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt
index 12842034f8..db37dfc03f 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt
@@ -37,12 +37,12 @@ import im.vector.riotredesign.core.platform.ToolbarConfigurable
 import im.vector.riotredesign.features.home.room.detail.LoadingRoomDetailFragment
 import kotlinx.android.synthetic.main.activity_home.*
 import org.koin.android.ext.android.inject
-import org.koin.standalone.StandAloneContext.loadKoinModules
+import org.koin.android.scope.ext.android.bindScope
+import org.koin.android.scope.ext.android.getOrCreateScope
 
 
 class HomeActivity : RiotActivity(), ToolbarConfigurable {
 
-
     private val homeActivityViewModel: HomeActivityViewModel by viewModel()
     private val homeNavigator by inject<HomeNavigator>()
 
@@ -53,10 +53,10 @@ class HomeActivity : RiotActivity(), ToolbarConfigurable {
     }
 
     override fun onCreate(savedInstanceState: Bundle?) {
-        loadKoinModules(listOf(HomeModule(this).definition))
-        homeNavigator.activity = this
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_home)
+        bindScope(getOrCreateScope(HomeModule.HOME_SCOPE))
+        homeNavigator.activity = this
         drawerLayout.addDrawerListener(drawerListener)
         if (savedInstanceState == null) {
             val homeDrawerFragment = HomeDrawerFragment.newInstance()
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt b/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt
index 2862765708..71d9f94c21 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt
@@ -16,7 +16,8 @@
 
 package im.vector.riotredesign.features.home
 
-import im.vector.matrix.android.api.Matrix
+import android.content.Context
+import im.vector.riotredesign.features.home.group.GroupSummaryController
 import im.vector.riotredesign.features.home.group.SelectedGroupStore
 import im.vector.riotredesign.features.home.room.VisibleRoomStore
 import im.vector.riotredesign.features.home.room.detail.timeline.CallItemFactory
@@ -35,84 +36,83 @@ import im.vector.riotredesign.features.home.room.list.RoomSummaryController
 import im.vector.riotredesign.features.html.EventHtmlRenderer
 import org.koin.dsl.module.module
 
-class HomeModule(homeActivity: HomeActivity) {
+class HomeModule(context: Context) {
 
-    val definition = module(override = true) {
+    companion object {
+        const val HOME_SCOPE = "HOME_SCOPE"
+        const val ROOM_DETAIL_SCOPE = "ROOM_DETAIL_SCOPE"
+        const val ROOM_LIST_SCOPE = "ROOM_LIST_SCOPE"
+        const val GROUP_LIST_SCOPE = "GROUP_LIST_SCOPE"
+    }
 
-        single {
-            Matrix.getInstance().currentSession
-        }
+    val definition = module {
 
-        single {
+        // Activity scope
+
+        scope(HOME_SCOPE) {
             TimelineDateFormatter(get())
         }
 
-        single {
-            EventHtmlRenderer(homeActivity, get())
-        }
-
-        single {
-            MessageItemFactory(get(), get(), get(), get())
-        }
-
-        single {
-            RoomNameItemFactory(get())
-        }
-
-        single {
-            RoomTopicItemFactory(get())
-        }
-
-        single {
-            RoomMemberItemFactory(get())
-        }
-
-        single {
-            CallItemFactory(get())
-        }
-
-        single {
-            RoomHistoryVisibilityItemFactory(get())
-        }
-
-        single {
-            DefaultItemFactory()
-        }
-
-        single {
-            TimelineItemFactory(get(), get(), get(), get(), get(), get(), get())
-        }
-
-        single {
+        scope(HOME_SCOPE) {
             HomeNavigator()
         }
 
-        factory {
-            RoomSummaryController(get())
-        }
-
-        factory { (roomId: String) ->
-            TimelineEventController(roomId, get(), get(), get())
-        }
-
-        single {
-            TimelineMediaSizeProvider()
-        }
-
-        single {
-            SelectedGroupStore()
-        }
-
-        single {
-            VisibleRoomStore()
-        }
-
-        single {
+        scope(HOME_SCOPE) {
             HomePermalinkHandler(get())
         }
 
-        single {
-            RoomSummaryComparator()
+        scope(HOME_SCOPE) {
+            RoomNameItemFactory(get())
+        }
+
+        scope(HOME_SCOPE) {
+            RoomTopicItemFactory(get())
+        }
+
+        scope(HOME_SCOPE) {
+            RoomMemberItemFactory(get())
+        }
+
+        scope(HOME_SCOPE) {
+            CallItemFactory(get())
+        }
+
+        scope(HOME_SCOPE) {
+            RoomHistoryVisibilityItemFactory(get())
+        }
+
+        scope(HOME_SCOPE) {
+            DefaultItemFactory()
+        }
+
+        scope(HOME_SCOPE) {
+            TimelineMediaSizeProvider()
+        }
+
+        scope(HOME_SCOPE) {
+            EventHtmlRenderer(context, get())
+        }
+
+        scope(HOME_SCOPE) {
+            MessageItemFactory(get(), get(), get(), get())
+        }
+
+        scope(HOME_SCOPE) {
+            TimelineItemFactory(get(), get(), get(), get(), get(), get(), get())
+        }
+
+        // Fragment scopes
+
+        scope(ROOM_DETAIL_SCOPE) {
+            TimelineEventController(get(), get(), get())
+        }
+
+        scope(ROOM_LIST_SCOPE) {
+            RoomSummaryController(get())
+        }
+
+        scope(GROUP_LIST_SCOPE) {
+            GroupSummaryController()
         }
 
 
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/HomeNavigator.kt b/app/src/main/java/im/vector/riotredesign/features/home/HomeNavigator.kt
index 4fb84ea10d..f6583b97a4 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/HomeNavigator.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/HomeNavigator.kt
@@ -36,9 +36,6 @@ class HomeNavigator {
                        eventId: String?,
                        addToBackstack: Boolean = false) {
         Timber.v("Open room detail $roomId - $eventId - $addToBackstack")
-        if (!addToBackstack && isRoot(roomId)) {
-            return
-        }
         activity?.let {
             val args = RoomDetailArgs(roomId, eventId)
             val roomDetailFragment = RoomDetailFragment.newInstance(args)
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/group/GroupListFragment.kt b/app/src/main/java/im/vector/riotredesign/features/home/group/GroupListFragment.kt
index 30b6a6d08a..fb99e839ed 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/group/GroupListFragment.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/group/GroupListFragment.kt
@@ -27,7 +27,11 @@ import im.vector.matrix.android.api.session.group.model.GroupSummary
 import im.vector.riotredesign.R
 import im.vector.riotredesign.core.platform.RiotFragment
 import im.vector.riotredesign.core.platform.StateView
+import im.vector.riotredesign.features.home.HomeModule
 import kotlinx.android.synthetic.main.fragment_group_list.*
+import org.koin.android.ext.android.inject
+import org.koin.android.scope.ext.android.bindScope
+import org.koin.android.scope.ext.android.getOrCreateScope
 
 class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
 
@@ -38,8 +42,7 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
     }
 
     private val viewModel: GroupListViewModel by fragmentViewModel()
-
-    private lateinit var groupController: GroupSummaryController
+    private val groupController by inject<GroupSummaryController>()
 
     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
         return inflater.inflate(R.layout.fragment_group_list, container, false)
@@ -47,7 +50,8 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         super.onActivityCreated(savedInstanceState)
-        groupController = GroupSummaryController(this)
+        bindScope(getOrCreateScope(HomeModule.GROUP_LIST_SCOPE))
+        groupController.callback = this
         stateView.contentView = epoxyRecyclerView
         epoxyRecyclerView.setController(groupController)
         viewModel.subscribe { renderState(it) }
@@ -56,7 +60,7 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
     private fun renderState(state: GroupListViewState) {
         when (state.asyncGroups) {
             is Incomplete -> renderLoading()
-            is Success -> renderSuccess(state)
+            is Success    -> renderSuccess(state)
         }
     }
 
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt b/app/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt
index f35c46fc10..1ab01369df 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt
@@ -19,7 +19,6 @@ package im.vector.riotredesign.features.home.group
 import arrow.core.Option
 import com.airbnb.mvrx.MvRxViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
-import im.vector.matrix.android.api.Matrix
 import im.vector.matrix.android.api.session.Session
 import im.vector.matrix.rx.rx
 import im.vector.riotredesign.core.platform.RiotViewModel
@@ -34,7 +33,7 @@ class GroupListViewModel(initialState: GroupListViewState,
 
         @JvmStatic
         override fun create(viewModelContext: ViewModelContext, state: GroupListViewState): GroupListViewModel? {
-            val currentSession = Matrix.getInstance().currentSession
+            val currentSession = viewModelContext.activity.get<Session>()
             val selectedGroupHolder = viewModelContext.activity.get<SelectedGroupStore>()
             return GroupListViewModel(state, selectedGroupHolder, currentSession)
         }
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt b/app/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt
index 3f24f9e0f4..0fc0c9d4d5 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt
@@ -19,8 +19,9 @@ package im.vector.riotredesign.features.home.group
 import com.airbnb.epoxy.TypedEpoxyController
 import im.vector.matrix.android.api.session.group.model.GroupSummary
 
-class GroupSummaryController(private val callback: Callback? = null
-) : TypedEpoxyController<GroupListViewState>() {
+class GroupSummaryController : TypedEpoxyController<GroupListViewState>() {
+
+    var callback: Callback? = null
 
     override fun buildModels(viewState: GroupListViewState) {
         buildGroupModels(viewState.asyncGroups(), viewState.selectedGroup)
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
index 76f91c7b28..1e1511344c 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt
@@ -25,19 +25,21 @@ import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.airbnb.epoxy.EpoxyVisibilityTracker
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.args
 import com.airbnb.mvrx.fragmentViewModel
 import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
 import im.vector.riotredesign.R
+import im.vector.riotredesign.core.epoxy.LayoutManagerStateRestorer
 import im.vector.riotredesign.core.platform.RiotFragment
 import im.vector.riotredesign.core.platform.ToolbarConfigurable
 import im.vector.riotredesign.features.home.AvatarRenderer
+import im.vector.riotredesign.features.home.HomeModule
 import im.vector.riotredesign.features.home.HomePermalinkHandler
 import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
 import kotlinx.android.parcel.Parcelize
 import kotlinx.android.synthetic.main.fragment_room_detail.*
 import org.koin.android.ext.android.inject
-import org.koin.core.parameter.parametersOf
+import org.koin.android.scope.ext.android.bindScope
+import org.koin.android.scope.ext.android.getOrCreateScope
 
 @Parcelize
 data class RoomDetailArgs(
@@ -45,6 +47,7 @@ data class RoomDetailArgs(
         val eventId: String? = null
 ) : Parcelable
 
+
 class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
 
     companion object {
@@ -57,10 +60,9 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
     }
 
     private val roomDetailViewModel: RoomDetailViewModel by fragmentViewModel()
-    private val roomDetailArgs: RoomDetailArgs by args()
-
-    private val timelineEventController by inject<TimelineEventController> { parametersOf(roomDetailArgs.roomId) }
+    private val timelineEventController by inject<TimelineEventController>()
     private val homePermalinkHandler by inject<HomePermalinkHandler>()
+
     private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
 
     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@@ -69,6 +71,7 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         super.onActivityCreated(savedInstanceState)
+        bindScope(getOrCreateScope(HomeModule.ROOM_DETAIL_SCOPE))
         setupRecyclerView()
         setupToolbar()
         setupSendButton()
@@ -80,6 +83,8 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
         roomDetailViewModel.process(RoomDetailActions.IsDisplayed)
     }
 
+    // PRIVATE METHODS *****************************************************************************
+
     private fun setupToolbar() {
         val parentActivity = riotActivity
         if (parentActivity is ToolbarConfigurable) {
@@ -91,10 +96,14 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
         val epoxyVisibilityTracker = EpoxyVisibilityTracker()
         epoxyVisibilityTracker.attach(recyclerView)
         val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
+        val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
         scrollOnNewMessageCallback = ScrollOnNewMessageCallback(layoutManager)
         recyclerView.layoutManager = layoutManager
         recyclerView.setHasFixedSize(true)
-        timelineEventController.addModelBuildListener { it.dispatchTo(scrollOnNewMessageCallback) }
+        timelineEventController.addModelBuildListener {
+            it.dispatchTo(stateRestorer)
+            it.dispatchTo(scrollOnNewMessageCallback)
+        }
         recyclerView.setController(timelineEventController)
         timelineEventController.callback = this
     }
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt
index 3ce30c0e59..4ca21b94ec 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt
@@ -19,7 +19,6 @@ package im.vector.riotredesign.features.home.room.detail
 import com.airbnb.mvrx.MvRxViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
 import com.jakewharton.rxrelay2.BehaviorRelay
-import im.vector.matrix.android.api.Matrix
 import im.vector.matrix.android.api.MatrixCallback
 import im.vector.matrix.android.api.session.Session
 import im.vector.matrix.android.api.session.events.model.Event
@@ -46,7 +45,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
 
         @JvmStatic
         override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? {
-            val currentSession = Matrix.getInstance().currentSession
+            val currentSession = viewModelContext.activity.get<Session>()
             val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomStore>()
             return RoomDetailViewModel(state, currentSession, visibleRoomHolder)
         }
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt
index ec865e4b8b..883476de78 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt
@@ -29,8 +29,7 @@ import im.vector.riotredesign.core.extensions.localDateTime
 import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
 import im.vector.riotredesign.features.home.room.detail.timeline.paging.PagedListEpoxyController
 
-class TimelineEventController(private val roomId: String,
-                              private val dateFormatter: TimelineDateFormatter,
+class TimelineEventController(private val dateFormatter: TimelineDateFormatter,
                               private val timelineItemFactory: TimelineItemFactory,
                               private val timelineMediaSizeProvider: TimelineMediaSizeProvider
 ) : PagedListEpoxyController<TimelineEvent>(
@@ -82,7 +81,7 @@ class TimelineEventController(private val roomId: String,
         }
         if (addDaySeparator) {
             val formattedDay = dateFormatter.formatMessageDay(date)
-            val daySeparatorItem = DaySeparatorItem_().formattedDay(formattedDay).id(roomId + formattedDay)
+            val daySeparatorItem = DaySeparatorItem_().formattedDay(formattedDay).id(formattedDay)
             epoxyModels.add(daySeparatorItem)
         }
         return epoxyModels
@@ -90,13 +89,13 @@ class TimelineEventController(private val roomId: String,
 
     override fun addModels(models: List<EpoxyModel<*>>) {
         LoadingItemModel_()
-                .id(roomId + "forward_loading_item")
+                .id("forward_loading_item")
                 .addIf(isLoadingForward, this)
 
         super.add(models)
 
         LoadingItemModel_()
-                .id(roomId + "backward_loading_item")
+                .id("backward_loading_item")
                 .addIf(!hasReachedEnd, this)
     }
 
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListActions.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListActions.kt
index efc8b6641f..dc9c393b37 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListActions.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListActions.kt
@@ -22,8 +22,8 @@ sealed class RoomListActions {
 
     data class SelectRoom(val roomSummary: RoomSummary) : RoomListActions()
 
-    object RoomDisplayed : RoomListActions()
-
     data class FilterRooms(val roomName: CharSequence? = null) : RoomListActions()
 
+    data class ToggleCategory(val category: RoomCategory) : RoomListActions()
+
 }
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt
index 904cf66ca1..deeba711b6 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt
@@ -22,19 +22,25 @@ import android.text.TextWatcher
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
 import com.airbnb.mvrx.Fail
 import com.airbnb.mvrx.Incomplete
 import com.airbnb.mvrx.Success
-import com.airbnb.mvrx.activityViewModel
+import com.airbnb.mvrx.fragmentViewModel
 import im.vector.matrix.android.api.failure.Failure
 import im.vector.matrix.android.api.session.room.model.RoomSummary
 import im.vector.riotredesign.R
+import im.vector.riotredesign.core.epoxy.LayoutManagerStateRestorer
+import im.vector.riotredesign.core.extensions.observeEvent
 import im.vector.riotredesign.core.extensions.setupAsSearch
 import im.vector.riotredesign.core.platform.RiotFragment
 import im.vector.riotredesign.core.platform.StateView
+import im.vector.riotredesign.features.home.HomeModule
 import im.vector.riotredesign.features.home.HomeNavigator
 import kotlinx.android.synthetic.main.fragment_room_list.*
 import org.koin.android.ext.android.inject
+import org.koin.android.scope.ext.android.bindScope
+import org.koin.android.scope.ext.android.getOrCreateScope
 
 class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
 
@@ -44,9 +50,9 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
         }
     }
 
-    private val homeNavigator by inject<HomeNavigator>()
     private val roomController by inject<RoomSummaryController>()
-    private val homeViewModel: RoomListViewModel by activityViewModel()
+    private val homeNavigator by inject<HomeNavigator>()
+    private val roomListViewModel: RoomListViewModel by fragmentViewModel()
 
     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
         return inflater.inflate(R.layout.fragment_room_list, container, false)
@@ -54,11 +60,36 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
 
     override fun onActivityCreated(savedInstanceState: Bundle?) {
         super.onActivityCreated(savedInstanceState)
+        bindScope(getOrCreateScope(HomeModule.ROOM_LIST_SCOPE))
+        setupRecyclerView()
+        setupFilterView()
+        roomListViewModel.subscribe { renderState(it) }
+        roomListViewModel.openRoomLiveData.observeEvent(this) {
+            homeNavigator.openRoomDetail(it, null)
+        }
+    }
+
+    private fun setupRecyclerView() {
+        val layoutManager = LinearLayoutManager(context)
+        val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
+        epoxyRecyclerView.layoutManager = layoutManager
         roomController.callback = this
+        roomController.addModelBuildListener { it.dispatchTo(stateRestorer) }
         stateView.contentView = epoxyRecyclerView
         epoxyRecyclerView.setController(roomController)
-        setupFilterView()
-        homeViewModel.subscribe { renderState(it) }
+    }
+
+    private fun setupFilterView() {
+        filterRoomView.setupAsSearch()
+        filterRoomView.addTextChangedListener(object : TextWatcher {
+            override fun afterTextChanged(s: Editable?) = Unit
+
+            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
+
+            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
+                roomListViewModel.accept(RoomListActions.FilterRooms(s))
+            }
+        })
     }
 
     private fun renderState(state: RoomListViewState) {
@@ -90,24 +121,13 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
         stateView.state = StateView.State.Error(message)
     }
 
-    private fun setupFilterView() {
-        filterRoomView.setupAsSearch()
-        filterRoomView.addTextChangedListener(object : TextWatcher {
-            override fun afterTextChanged(s: Editable?) = Unit
-
-            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
-
-            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
-                homeViewModel.accept(RoomListActions.FilterRooms(s))
-            }
-        })
-    }
-
     // RoomSummaryController.Callback **************************************************************
 
     override fun onRoomSelected(room: RoomSummary) {
-        homeViewModel.accept(RoomListActions.SelectRoom(room))
-        homeNavigator.openRoomDetail(room.roomId, null)
+        roomListViewModel.accept(RoomListActions.SelectRoom(room))
     }
 
+    override fun onToggleRoomCategory(roomCategory: RoomCategory) {
+        roomListViewModel.accept(RoomListActions.ToggleCategory(roomCategory))
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt
index 0612016c06..f52134323d 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt
@@ -16,22 +16,23 @@
 
 package im.vector.riotredesign.features.home.room.list
 
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
 import arrow.core.Option
 import com.airbnb.mvrx.MvRxViewModelFactory
 import com.airbnb.mvrx.ViewModelContext
 import com.jakewharton.rxrelay2.BehaviorRelay
-import im.vector.matrix.android.api.Matrix
 import im.vector.matrix.android.api.session.Session
 import im.vector.matrix.android.api.session.group.model.GroupSummary
 import im.vector.matrix.android.api.session.room.model.RoomSummary
 import im.vector.matrix.android.api.session.room.model.tag.RoomTag
 import im.vector.matrix.rx.rx
 import im.vector.riotredesign.core.platform.RiotViewModel
+import im.vector.riotredesign.core.utils.LiveEvent
 import im.vector.riotredesign.features.home.group.SelectedGroupStore
 import im.vector.riotredesign.features.home.room.VisibleRoomStore
 import io.reactivex.Observable
 import io.reactivex.functions.Function3
-import io.reactivex.rxkotlin.subscribeBy
 import org.koin.android.ext.android.get
 import java.util.concurrent.TimeUnit
 
@@ -49,7 +50,7 @@ class RoomListViewModel(initialState: RoomListViewState,
 
         @JvmStatic
         override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? {
-            val currentSession = Matrix.getInstance().currentSession
+            val currentSession = viewModelContext.activity.get<Session>()
             val roomSelectionRepository = viewModelContext.activity.get<RoomSelectionRepository>()
             val selectedGroupHolder = viewModelContext.activity.get<SelectedGroupStore>()
             val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomStore>()
@@ -61,6 +62,10 @@ class RoomListViewModel(initialState: RoomListViewState,
 
     private val roomListFilter = BehaviorRelay.createDefault<Option<RoomListFilterName>>(Option.empty())
 
+    private val _openRoomLiveData = MutableLiveData<LiveEvent<String>>()
+    val openRoomLiveData: LiveData<LiveEvent<String>>
+        get() = _openRoomLiveData
+
     init {
         observeRoomSummaries()
         observeVisibleRoom()
@@ -68,16 +73,18 @@ class RoomListViewModel(initialState: RoomListViewState,
 
     fun accept(action: RoomListActions) {
         when (action) {
-            is RoomListActions.SelectRoom  -> handleSelectRoom(action)
-            is RoomListActions.FilterRooms -> handleFilterRooms(action)
+            is RoomListActions.SelectRoom     -> handleSelectRoom(action)
+            is RoomListActions.FilterRooms    -> handleFilterRooms(action)
+            is RoomListActions.ToggleCategory -> handleToggleCategory(action)
         }
     }
 
     // PRIVATE METHODS *****************************************************************************
 
     private fun handleSelectRoom(action: RoomListActions.SelectRoom) = withState { state ->
-        if (state.selectedRoomId != action.roomSummary.roomId) {
+        if (state.visibleRoomId != action.roomSummary.roomId) {
             roomSelectionRepository.saveLastSelectedRoom(action.roomSummary.roomId)
+            _openRoomLiveData.postValue(LiveEvent(action.roomSummary.roomId))
         }
     }
 
@@ -86,10 +93,14 @@ class RoomListViewModel(initialState: RoomListViewState,
         roomListFilter.accept(optionalFilter)
     }
 
+    private fun handleToggleCategory(action: RoomListActions.ToggleCategory) = setState {
+        this.toggle(action.category)
+    }
+
     private fun observeVisibleRoom() {
         visibleRoomHolder.observe()
                 .doOnNext {
-                    setState { copy(selectedRoomId = it) }
+                    setState { copy(visibleRoomId = it) }
                 }
                 .subscribe()
                 .disposeOnClear()
@@ -159,13 +170,13 @@ class RoomListViewModel(initialState: RoomListViewState,
             }
         }
 
-        return RoomSummaries(
-                favourites = favourites.sortedWith(roomSummaryComparator),
-                directRooms = directChats.sortedWith(roomSummaryComparator),
-                groupRooms = groupRooms.sortedWith(roomSummaryComparator),
-                lowPriorities = lowPriorities.sortedWith(roomSummaryComparator),
-                serverNotices = serverNotices.sortedWith(roomSummaryComparator)
-        )
+        return RoomSummaries().apply {
+            put(RoomCategory.FAVOURITE, favourites.sortedWith(roomSummaryComparator))
+            put(RoomCategory.DIRECT, directChats.sortedWith(roomSummaryComparator))
+            put(RoomCategory.GROUP, groupRooms.sortedWith(roomSummaryComparator))
+            put(RoomCategory.LOW_PRIORITY, lowPriorities.sortedWith(roomSummaryComparator))
+            put(RoomCategory.SERVER_NOTICE, serverNotices.sortedWith(roomSummaryComparator))
+        }
     }
 
 
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt
index 57d0be76e0..7466618e8a 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt
@@ -16,24 +16,54 @@
 
 package im.vector.riotredesign.features.home.room.list
 
+import androidx.annotation.StringRes
 import com.airbnb.mvrx.Async
 import com.airbnb.mvrx.MvRxState
 import com.airbnb.mvrx.Uninitialized
 import im.vector.matrix.android.api.session.room.model.RoomSummary
+import im.vector.riotredesign.R
 
 data class RoomListViewState(
         val asyncRooms: Async<RoomSummaries> = Uninitialized,
-        val selectedRoomId: String? = null
-) : MvRxState
+        val visibleRoomId: String? = null,
+        val isFavouriteRoomsExpanded: Boolean = true,
+        val isDirectRoomsExpanded: Boolean = false,
+        val isGroupRoomsExpanded: Boolean = false,
+        val isLowPriorityRoomsExpanded: Boolean = false,
+        val isServerNoticeRoomsExpanded: Boolean = false
+) : MvRxState {
 
-data class RoomSummaries(
-        val favourites: List<RoomSummary>,
-        val directRooms: List<RoomSummary>,
-        val groupRooms: List<RoomSummary>,
-        val lowPriorities: List<RoomSummary>,
-        val serverNotices: List<RoomSummary>
-)
+    fun isCategoryExpanded(roomCategory: RoomCategory): Boolean {
+        return when (roomCategory) {
+            RoomCategory.FAVOURITE     -> isFavouriteRoomsExpanded
+            RoomCategory.DIRECT        -> isDirectRoomsExpanded
+            RoomCategory.GROUP         -> isGroupRoomsExpanded
+            RoomCategory.LOW_PRIORITY  -> isLowPriorityRoomsExpanded
+            RoomCategory.SERVER_NOTICE -> isServerNoticeRoomsExpanded
+        }
+    }
+
+    fun toggle(roomCategory: RoomCategory): RoomListViewState {
+        return when (roomCategory) {
+            RoomCategory.FAVOURITE     -> copy(isFavouriteRoomsExpanded = !isFavouriteRoomsExpanded)
+            RoomCategory.DIRECT        -> copy(isDirectRoomsExpanded = !isDirectRoomsExpanded)
+            RoomCategory.GROUP         -> copy(isGroupRoomsExpanded = !isGroupRoomsExpanded)
+            RoomCategory.LOW_PRIORITY  -> copy(isLowPriorityRoomsExpanded = !isLowPriorityRoomsExpanded)
+            RoomCategory.SERVER_NOTICE -> copy(isServerNoticeRoomsExpanded = !isServerNoticeRoomsExpanded)
+        }
+    }
+}
+
+typealias RoomSummaries = LinkedHashMap<RoomCategory, List<RoomSummary>>
+
+enum class RoomCategory(@StringRes val titleRes: Int) {
+    FAVOURITE(R.string.room_list_favourites),
+    DIRECT(R.string.room_list_direct),
+    GROUP(R.string.room_list_group),
+    LOW_PRIORITY(R.string.room_list_low_priority),
+    SERVER_NOTICE(R.string.room_list_system_alert)
+}
 
 fun RoomSummaries?.isNullOrEmpty(): Boolean {
-    return this == null || (directRooms.isEmpty() && groupRooms.isEmpty() && favourites.isEmpty() && lowPriorities.isEmpty() && serverNotices.isEmpty())
+    return this == null || isEmpty()
 }
\ No newline at end of file
diff --git a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt
index 8178e2b862..de850df54b 100644
--- a/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt
+++ b/app/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt
@@ -19,65 +19,34 @@ package im.vector.riotredesign.features.home.room.list
 import androidx.annotation.StringRes
 import com.airbnb.epoxy.TypedEpoxyController
 import im.vector.matrix.android.api.session.room.model.RoomSummary
-import im.vector.riotredesign.R
 import im.vector.riotredesign.core.resources.StringProvider
 
 class RoomSummaryController(private val stringProvider: StringProvider
 ) : TypedEpoxyController<RoomListViewState>() {
 
-    private var isFavoriteRoomsExpanded = true
-    private var isDirectRoomsExpanded = false
-    private var isGroupRoomsExpanded = false
-    private var isLowPriorityRoomsExpanded = false
-    private var isServerNoticeRoomsExpanded = false
-
     var callback: Callback? = null
 
     override fun buildModels(viewState: RoomListViewState) {
         val roomSummaries = viewState.asyncRooms()
-        val favourites = roomSummaries?.favourites ?: emptyList()
-        buildRoomCategory(viewState, favourites, R.string.room_list_favourites, isFavoriteRoomsExpanded) {
-            isFavoriteRoomsExpanded = !isFavoriteRoomsExpanded
+        roomSummaries?.forEach { (category, summaries) ->
+            if (summaries.isEmpty()) {
+                return@forEach
+            } else {
+                val isExpanded = viewState.isCategoryExpanded(category)
+                buildRoomCategory(viewState, summaries, category.titleRes, viewState.isCategoryExpanded(category)) {
+                    callback?.onToggleRoomCategory(category)
+                }
+                if (isExpanded) {
+                    buildRoomModels(summaries, viewState.visibleRoomId)
+                }
+            }
         }
-        if (isFavoriteRoomsExpanded) {
-            buildRoomModels(favourites, viewState.selectedRoomId)
-        }
-
-        val directRooms = roomSummaries?.directRooms ?: emptyList()
-        buildRoomCategory(viewState, directRooms, R.string.room_list_direct, isDirectRoomsExpanded) {
-            isDirectRoomsExpanded = !isDirectRoomsExpanded
-        }
-        if (isDirectRoomsExpanded) {
-            buildRoomModels(directRooms, viewState.selectedRoomId)
-        }
-
-        val groupRooms = roomSummaries?.groupRooms ?: emptyList()
-        buildRoomCategory(viewState, groupRooms, R.string.room_list_group, isGroupRoomsExpanded) {
-            isGroupRoomsExpanded = !isGroupRoomsExpanded
-        }
-        if (isGroupRoomsExpanded) {
-            buildRoomModels(groupRooms, viewState.selectedRoomId)
-        }
-
-        val lowPriorities = roomSummaries?.lowPriorities ?: emptyList()
-        buildRoomCategory(viewState, lowPriorities, R.string.room_list_low_priority, isLowPriorityRoomsExpanded) {
-            isLowPriorityRoomsExpanded = !isLowPriorityRoomsExpanded
-        }
-        if (isLowPriorityRoomsExpanded) {
-            buildRoomModels(lowPriorities, viewState.selectedRoomId)
-        }
-
-        val serverNotices = roomSummaries?.serverNotices ?: emptyList()
-        buildRoomCategory(viewState, serverNotices, R.string.room_list_system_alert, isServerNoticeRoomsExpanded) {
-            isServerNoticeRoomsExpanded = !isServerNoticeRoomsExpanded
-        }
-        if (isServerNoticeRoomsExpanded) {
-            buildRoomModels(serverNotices, viewState.selectedRoomId)
-        }
-
     }
 
     private fun buildRoomCategory(viewState: RoomListViewState, summaries: List<RoomSummary>, @StringRes titleRes: Int, isExpanded: Boolean, mutateExpandedState: () -> Unit) {
+        if (summaries.isEmpty()) {
+            return
+        }
         //TODO should add some business logic later
         val unreadCount = if (summaries.isEmpty()) {
             0
@@ -117,6 +86,7 @@ class RoomSummaryController(private val stringProvider: StringProvider
     }
 
     interface Callback {
+        fun onToggleRoomCategory(roomCategory: RoomCategory)
         fun onRoomSelected(room: RoomSummary)
     }