mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 01:15:54 +03:00
Remove HomeViewModel and dispatch in multiple view models (one for each fragment)
This commit is contained in:
parent
7f11c141c7
commit
7c0df91a58
22 changed files with 282 additions and 222 deletions
|
@ -47,7 +47,7 @@ configurations.all { strategy ->
|
|||
dependencies {
|
||||
|
||||
def epoxy_version = "2.19.0"
|
||||
|
||||
def arrow_version = "0.8.0"
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation project(":matrix-sdk-android")
|
||||
|
@ -58,22 +58,30 @@ dependencies {
|
|||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
|
||||
implementation 'com.jakewharton.threetenabp:threetenabp:1.1.1'
|
||||
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
|
||||
// rx
|
||||
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
|
||||
|
||||
implementation("com.airbnb.android:epoxy:$epoxy_version")
|
||||
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
|
||||
implementation "com.airbnb.android:epoxy-paging:$epoxy_version"
|
||||
implementation 'com.airbnb.android:mvrx:0.6.0'
|
||||
|
||||
// FP
|
||||
implementation "io.arrow-kt:arrow-core:$arrow_version"
|
||||
|
||||
// UI
|
||||
implementation 'com.github.bumptech.glide:glide:4.8.0'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.8.0'
|
||||
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||
|
||||
|
||||
// DI
|
||||
implementation "org.koin:koin-android:$koin_version"
|
||||
implementation "org.koin:koin-android-scope:$koin_version"
|
||||
|
||||
// TESTS
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package im.vector.riotredesign.core.platform
|
||||
|
||||
import com.airbnb.mvrx.BaseMvRxViewModel
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
|
||||
abstract class RiotViewModel<S : MvRxState>(initialState: S)
|
||||
: BaseMvRxViewModel<S>(initialState, debugMode = false)
|
|
@ -1,17 +0,0 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import im.vector.matrix.android.api.permalinks.PermalinkData
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
sealed class HomeActions {
|
||||
|
||||
data class SelectRoom(val roomSummary: RoomSummary) : HomeActions()
|
||||
|
||||
data class SelectGroup(val groupSummary: GroupSummary) : HomeActions()
|
||||
|
||||
data class PermalinkClicked(val permalinkData: PermalinkData) : HomeActions()
|
||||
|
||||
object RoomDisplayed : HomeActions()
|
||||
|
||||
}
|
|
@ -5,12 +5,10 @@ import android.content.Intent
|
|||
import android.os.Bundle
|
||||
import android.support.v4.app.FragmentManager
|
||||
import android.support.v4.view.GravityCompat
|
||||
import android.support.v4.widget.DrawerLayout
|
||||
import android.support.v7.app.ActionBarDrawerToggle
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.Gravity
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.replaceFragment
|
||||
import im.vector.riotredesign.core.platform.OnBackPressed
|
||||
|
@ -91,12 +89,9 @@ class HomeActivity : RiotActivity(), HomeNavigator, ToolbarConfigurable {
|
|||
override fun openRoomDetail(roomId: String, eventId: String?) {
|
||||
val args = RoomDetailArgs(roomId, eventId)
|
||||
val roomDetailFragment = RoomDetailFragment.newInstance(args)
|
||||
if (drawerLayout.isDrawerOpen(Gravity.LEFT)) {
|
||||
closeDrawerLayout(Gravity.LEFT) { replaceFragment(roomDetailFragment, R.id.homeDetailFragmentContainer) }
|
||||
} else {
|
||||
drawerLayout.closeDrawer(Gravity.LEFT)
|
||||
replaceFragment(roomDetailFragment, R.id.homeDetailFragmentContainer)
|
||||
}
|
||||
}
|
||||
|
||||
override fun openGroupDetail(groupId: String) {
|
||||
Timber.v("Open group detail $groupId")
|
||||
|
@ -106,16 +101,6 @@ class HomeActivity : RiotActivity(), HomeNavigator, ToolbarConfigurable {
|
|||
Timber.v("Open user detail $userId")
|
||||
}
|
||||
|
||||
private fun closeDrawerLayout(gravity: Int, actionOnClose: () -> Unit) {
|
||||
drawerLayout.addDrawerListener(object : DrawerLayout.SimpleDrawerListener() {
|
||||
override fun onDrawerClosed(p0: View) {
|
||||
drawerLayout.removeDrawerListener(this)
|
||||
actionOnClose()
|
||||
}
|
||||
})
|
||||
drawerLayout.closeDrawer(gravity)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newIntent(context: Context): Intent {
|
||||
return Intent(context, HomeActivity::class.java)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import im.vector.riotredesign.features.home.group.SelectedGroupHolder
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.MessageItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TextItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineDateFormatter
|
||||
|
@ -30,5 +31,9 @@ class HomeModule(private val homeActivity: HomeActivity) {
|
|||
TimelineEventController(roomId, get(), get(), get())
|
||||
}
|
||||
|
||||
single {
|
||||
SelectedGroupHolder()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import com.airbnb.mvrx.BaseMvRxViewModel
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.permalinks.PermalinkData
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotredesign.features.home.room.list.RoomSelectionRepository
|
||||
import org.koin.android.ext.android.get
|
||||
|
||||
class HomeViewModel(initialState: HomeViewState,
|
||||
private val session: Session,
|
||||
private val roomSelectionRepository: RoomSelectionRepository) : BaseMvRxViewModel<HomeViewState>(initialState) {
|
||||
|
||||
companion object : MvRxViewModelFactory<HomeViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(activity: FragmentActivity, state: HomeViewState): HomeViewModel {
|
||||
val currentSession = Matrix.getInstance().currentSession
|
||||
val roomSelectionRepository = activity.get<RoomSelectionRepository>()
|
||||
return HomeViewModel(state, currentSession, roomSelectionRepository)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
observeRoomSummaries()
|
||||
observeGroupSummaries()
|
||||
}
|
||||
|
||||
fun accept(action: HomeActions) {
|
||||
when (action) {
|
||||
is HomeActions.SelectRoom -> handleSelectRoom(action)
|
||||
is HomeActions.SelectGroup -> handleSelectGroup(action)
|
||||
is HomeActions.RoomDisplayed -> setState { copy(shouldOpenRoomDetail = false) }
|
||||
is HomeActions.PermalinkClicked -> handlePermalinkClicked(action)
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handlePermalinkClicked(action: HomeActions.PermalinkClicked) = withState { state ->
|
||||
when (action.permalinkData) {
|
||||
is PermalinkData.EventLink -> {
|
||||
|
||||
}
|
||||
is PermalinkData.RoomLink -> {
|
||||
|
||||
}
|
||||
is PermalinkData.GroupLink -> {
|
||||
|
||||
}
|
||||
is PermalinkData.UserLink -> {
|
||||
|
||||
}
|
||||
is PermalinkData.FallbackLink -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectRoom(action: HomeActions.SelectRoom) = withState { state ->
|
||||
if (state.selectedRoomId != action.roomSummary.roomId) {
|
||||
roomSelectionRepository.saveLastSelectedRoom(action.roomSummary.roomId)
|
||||
setState { copy(selectedRoomId = action.roomSummary.roomId, shouldOpenRoomDetail = true) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectGroup(action: HomeActions.SelectGroup) = withState { state ->
|
||||
if (state.selectedGroup?.groupId != action.groupSummary.groupId) {
|
||||
setState { copy(selectedGroup = action.groupSummary) }
|
||||
} else {
|
||||
setState { copy(selectedGroup = null) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummaries() {
|
||||
session
|
||||
.rx().liveRoomSummaries()
|
||||
.execute { async ->
|
||||
val summaries = async()
|
||||
val directRooms = summaries?.filter { it.isDirect } ?: emptyList()
|
||||
val groupRooms = summaries?.filter { !it.isDirect } ?: emptyList()
|
||||
|
||||
val selectedRoomId = selectedRoomId
|
||||
?: roomSelectionRepository.lastSelectedRoom()
|
||||
?: directRooms.firstOrNull()?.roomId
|
||||
?: groupRooms.firstOrNull()?.roomId
|
||||
|
||||
copy(
|
||||
asyncRooms = async,
|
||||
directRooms = directRooms,
|
||||
groupRooms = groupRooms,
|
||||
selectedRoomId = selectedRoomId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeGroupSummaries() {
|
||||
session
|
||||
.rx().liveGroupSummaries()
|
||||
.execute { async ->
|
||||
copy(asyncGroups = async)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
data class HomeViewState(
|
||||
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
||||
val directRooms: List<RoomSummary> = emptyList(),
|
||||
val groupRooms: List<RoomSummary> = emptyList(),
|
||||
val selectedRoomId: String? = null,
|
||||
val selectedEventId: String? = null,
|
||||
val shouldOpenRoomDetail: Boolean = true,
|
||||
val asyncGroups: Async<List<GroupSummary>> = Uninitialized,
|
||||
val selectedGroup: GroupSummary? = null
|
||||
) : MvRxState
|
|
@ -0,0 +1,9 @@
|
|||
package im.vector.riotredesign.features.home.group
|
||||
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
|
||||
sealed class GroupListActions {
|
||||
|
||||
data class SelectGroup(val groupSummary: GroupSummary) : GroupListActions()
|
||||
|
||||
}
|
|
@ -6,14 +6,11 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
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.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.HomeActions
|
||||
import im.vector.riotredesign.features.home.HomeViewModel
|
||||
import im.vector.riotredesign.features.home.HomeViewState
|
||||
import kotlinx.android.synthetic.main.fragment_group_list.*
|
||||
|
||||
class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
|
||||
|
@ -24,7 +21,7 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
private val viewModel: HomeViewModel by activityViewModel()
|
||||
private val viewModel: GroupListViewModel by fragmentViewModel()
|
||||
|
||||
private lateinit var groupController: GroupSummaryController
|
||||
|
||||
|
@ -40,14 +37,14 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
|
|||
viewModel.subscribe { renderState(it) }
|
||||
}
|
||||
|
||||
private fun renderState(state: HomeViewState) {
|
||||
private fun renderState(state: GroupListViewState) {
|
||||
when (state.asyncGroups) {
|
||||
is Incomplete -> renderLoading()
|
||||
is Success -> renderSuccess(state)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderSuccess(state: HomeViewState) {
|
||||
private fun renderSuccess(state: GroupListViewState) {
|
||||
stateView.state = StateView.State.Content
|
||||
groupController.setData(state)
|
||||
}
|
||||
|
@ -57,7 +54,7 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
|
|||
}
|
||||
|
||||
override fun onGroupSelected(groupSummary: GroupSummary) {
|
||||
viewModel.accept(HomeActions.SelectGroup(groupSummary))
|
||||
viewModel.accept(GroupListActions.SelectGroup(groupSummary))
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package im.vector.riotredesign.features.home.group
|
||||
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import com.airbnb.mvrx.BaseMvRxViewModel
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
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
|
||||
import org.koin.android.ext.android.get
|
||||
|
||||
class GroupListViewModel(initialState: GroupListViewState,
|
||||
private val selectedGroupHolder: SelectedGroupHolder,
|
||||
private val session: Session
|
||||
) : RiotViewModel<GroupListViewState>(initialState) {
|
||||
|
||||
companion object : MvRxViewModelFactory<GroupListViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(activity: FragmentActivity, state: GroupListViewState): GroupListViewModel {
|
||||
val currentSession = Matrix.getInstance().currentSession
|
||||
val selectedGroupHolder = activity.get<SelectedGroupHolder>()
|
||||
return GroupListViewModel(state, selectedGroupHolder, currentSession)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
observeGroupSummaries()
|
||||
observeState()
|
||||
}
|
||||
|
||||
private fun observeState() {
|
||||
subscribe {
|
||||
selectedGroupHolder.setSelectedGroup(it.selectedGroup)
|
||||
}
|
||||
}
|
||||
|
||||
fun accept(action: GroupListActions) {
|
||||
when (action) {
|
||||
is GroupListActions.SelectGroup -> handleSelectGroup(action)
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handleSelectGroup(action: GroupListActions.SelectGroup) = withState { state ->
|
||||
if (state.selectedGroup?.groupId != action.groupSummary.groupId) {
|
||||
setState { copy(selectedGroup = action.groupSummary) }
|
||||
} else {
|
||||
setState { copy(selectedGroup = null) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun observeGroupSummaries() {
|
||||
session
|
||||
.rx().liveGroupSummaries()
|
||||
.execute { async ->
|
||||
copy(asyncGroups = async)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package im.vector.riotredesign.features.home.group
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
|
||||
data class GroupListViewState(
|
||||
val asyncGroups: Async<List<GroupSummary>> = Uninitialized,
|
||||
val selectedGroup: GroupSummary? = null
|
||||
) : MvRxState
|
|
@ -2,12 +2,11 @@ package im.vector.riotredesign.features.home.group
|
|||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.riotredesign.features.home.HomeViewState
|
||||
|
||||
class GroupSummaryController(private val callback: Callback? = null
|
||||
) : TypedEpoxyController<HomeViewState>() {
|
||||
) : TypedEpoxyController<GroupListViewState>() {
|
||||
|
||||
override fun buildModels(viewState: HomeViewState) {
|
||||
override fun buildModels(viewState: GroupListViewState) {
|
||||
buildGroupModels(viewState.asyncGroups(), viewState.selectedGroup)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package im.vector.riotredesign.features.home.group
|
||||
|
||||
import arrow.core.Option
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.subjects.BehaviorSubject
|
||||
|
||||
class SelectedGroupHolder {
|
||||
|
||||
private val selectedGroupStream = BehaviorSubject.createDefault<Option<GroupSummary>>(Option.empty())
|
||||
|
||||
fun setSelectedGroup(group: GroupSummary?) {
|
||||
val optionValue = Option.fromNullable(group)
|
||||
selectedGroupStream.onNext(optionValue)
|
||||
}
|
||||
|
||||
fun selectedGroup(): Observable<Option<GroupSummary>> {
|
||||
return selectedGroupStream.hide()
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -6,8 +6,6 @@ import android.support.v7.widget.LinearLayoutManager
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import im.vector.matrix.android.api.permalinks.PermalinkParser
|
||||
|
@ -16,8 +14,6 @@ import im.vector.riotredesign.R
|
|||
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.HomeActions
|
||||
import im.vector.riotredesign.features.home.HomeViewModel
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||
|
@ -41,7 +37,6 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
private val homeViewModel: HomeViewModel by activityViewModel()
|
||||
private val roomDetailViewModel: RoomDetailViewModel by fragmentViewModel()
|
||||
private val roomDetailArgs: RoomDetailArgs by args()
|
||||
|
||||
|
@ -83,12 +78,8 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
|
|||
}
|
||||
|
||||
private fun renderState(state: RoomDetailViewState) {
|
||||
when (state.asyncTimeline) {
|
||||
is Success -> renderTimeline(state.asyncTimeline())
|
||||
}
|
||||
when (state.asyncRoomSummary) {
|
||||
is Success -> renderRoomSummary(state.asyncRoomSummary())
|
||||
}
|
||||
renderTimeline(state.asyncTimeline())
|
||||
renderRoomSummary(state.asyncRoomSummary())
|
||||
}
|
||||
|
||||
private fun renderRoomSummary(roomSummary: RoomSummary?) {
|
||||
|
@ -113,7 +104,7 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
|
|||
|
||||
override fun onUrlClicked(url: String) {
|
||||
val permalinkData = PermalinkParser.parse(url)
|
||||
homeViewModel.accept(HomeActions.PermalinkClicked(permalinkData))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package im.vector.riotredesign.features.home.room.detail
|
||||
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import com.airbnb.mvrx.BaseMvRxViewModel
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
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
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotredesign.core.platform.RiotViewModel
|
||||
|
||||
class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||
session: Session
|
||||
) : BaseMvRxViewModel<RoomDetailViewState>(initialState) {
|
||||
) : RiotViewModel<RoomDetailViewState>(initialState) {
|
||||
|
||||
private val room = session.getRoom(initialState.roomId)!!
|
||||
private val roomId = initialState.roomId
|
||||
|
@ -53,10 +53,9 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||
|
||||
private fun observeTimeline() {
|
||||
room.rx().timeline(eventId)
|
||||
.execute { async ->
|
||||
copy(asyncTimeline = async)
|
||||
.execute { asyncTimeline ->
|
||||
copy(asyncTimeline = asyncTimeline)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package im.vector.riotredesign.features.home.room.list
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
sealed class RoomListActions {
|
||||
|
||||
data class SelectRoom(val roomSummary: RoomSummary) : RoomListActions()
|
||||
|
||||
object RoomDisplayed : RoomListActions()
|
||||
|
||||
}
|
|
@ -13,10 +13,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
|
|||
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.HomeActions
|
||||
import im.vector.riotredesign.features.home.HomeNavigator
|
||||
import im.vector.riotredesign.features.home.HomeViewModel
|
||||
import im.vector.riotredesign.features.home.HomeViewState
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
|
@ -29,7 +26,7 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
|
|||
}
|
||||
|
||||
private val homeNavigator by inject<HomeNavigator>()
|
||||
private val homeViewModel: HomeViewModel by activityViewModel()
|
||||
private val homeViewModel: RoomListViewModel by activityViewModel()
|
||||
private lateinit var roomController: RoomSummaryController
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
|
@ -44,19 +41,15 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
|
|||
homeViewModel.subscribe { renderState(it) }
|
||||
}
|
||||
|
||||
private fun renderState(state: HomeViewState) {
|
||||
private fun renderState(state: RoomListViewState) {
|
||||
when (state.asyncRooms) {
|
||||
is Incomplete -> renderLoading()
|
||||
is Success -> renderSuccess(state)
|
||||
is Fail -> renderFailure(state.asyncRooms.error)
|
||||
}
|
||||
if (state.shouldOpenRoomDetail && state.selectedRoomId != null) {
|
||||
homeNavigator.openRoomDetail(state.selectedRoomId, null)
|
||||
homeViewModel.accept(HomeActions.RoomDisplayed)
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderSuccess(state: HomeViewState) {
|
||||
private fun renderSuccess(state: RoomListViewState) {
|
||||
if (state.asyncRooms().isNullOrEmpty()) {
|
||||
stateView.state = StateView.State.Empty(getString(R.string.room_list_empty))
|
||||
} else {
|
||||
|
@ -78,7 +71,8 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
|
|||
}
|
||||
|
||||
override fun onRoomSelected(room: RoomSummary) {
|
||||
homeViewModel.accept(HomeActions.SelectRoom(room))
|
||||
homeViewModel.accept(RoomListActions.SelectRoom(room))
|
||||
homeNavigator.openRoomDetail(room.roomId, null)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package im.vector.riotredesign.features.home.room.list
|
||||
|
||||
import android.support.v4.app.FragmentActivity
|
||||
import arrow.core.Option
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
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.rx.rx
|
||||
import im.vector.riotredesign.core.platform.RiotViewModel
|
||||
import im.vector.riotredesign.features.home.group.SelectedGroupHolder
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import org.koin.android.ext.android.get
|
||||
|
||||
class RoomListViewModel(initialState: RoomListViewState,
|
||||
private val session: Session,
|
||||
private val selectedGroupHolder: SelectedGroupHolder,
|
||||
private val roomSelectionRepository: RoomSelectionRepository)
|
||||
: RiotViewModel<RoomListViewState>(initialState) {
|
||||
|
||||
companion object : MvRxViewModelFactory<RoomListViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(activity: FragmentActivity, state: RoomListViewState): RoomListViewModel {
|
||||
val currentSession = Matrix.getInstance().currentSession
|
||||
val roomSelectionRepository = activity.get<RoomSelectionRepository>()
|
||||
val selectedGroupHolder = activity.get<SelectedGroupHolder>()
|
||||
return RoomListViewModel(state, currentSession, selectedGroupHolder, roomSelectionRepository)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
observeRoomSummaries()
|
||||
}
|
||||
|
||||
fun accept(action: RoomListActions) {
|
||||
when (action) {
|
||||
is RoomListActions.SelectRoom -> handleSelectRoom(action)
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handleSelectRoom(action: RoomListActions.SelectRoom) = withState { state ->
|
||||
if (state.selectedRoomId != action.roomSummary.roomId) {
|
||||
roomSelectionRepository.saveLastSelectedRoom(action.roomSummary.roomId)
|
||||
setState { copy(selectedRoomId = action.roomSummary.roomId) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummaries() {
|
||||
Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, RoomSummaries>(
|
||||
session.rx().liveRoomSummaries(),
|
||||
selectedGroupHolder.selectedGroup(),
|
||||
BiFunction { rooms, selectedGroupOption ->
|
||||
val selectedGroup = selectedGroupOption.orNull()
|
||||
|
||||
val filteredDirectRooms = rooms
|
||||
.filter { it.isDirect }
|
||||
.filter {
|
||||
if (selectedGroup == null) {
|
||||
true
|
||||
} else {
|
||||
it.otherMemberIds
|
||||
.intersect(selectedGroup.userIds)
|
||||
.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
val filteredGroupRooms = rooms
|
||||
.filter { !it.isDirect }
|
||||
.filter {
|
||||
selectedGroup?.roomIds?.contains(it.roomId) ?: true
|
||||
}
|
||||
RoomSummaries(filteredDirectRooms, filteredGroupRooms)
|
||||
}
|
||||
)
|
||||
.execute { async ->
|
||||
val summaries = async()
|
||||
val selectedRoomId = selectedRoomId
|
||||
?: roomSelectionRepository.lastSelectedRoom()
|
||||
?: summaries?.directRooms?.firstOrNull()?.roomId
|
||||
?: summaries?.groupRooms?.firstOrNull()?.roomId
|
||||
|
||||
copy(
|
||||
asyncRooms = async,
|
||||
selectedRoomId = selectedRoomId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package im.vector.riotredesign.features.home.room.list
|
||||
|
||||
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
|
||||
|
||||
data class RoomListViewState(
|
||||
val asyncRooms: Async<RoomSummaries> = Uninitialized,
|
||||
val selectedRoomId: String? = null
|
||||
) : MvRxState
|
||||
|
||||
data class RoomSummaries(
|
||||
val directRooms: List<RoomSummary>,
|
||||
val groupRooms: List<RoomSummary>
|
||||
)
|
||||
|
||||
fun RoomSummaries?.isNullOrEmpty(): Boolean {
|
||||
return this == null || (directRooms.isEmpty() && groupRooms.isEmpty())
|
||||
}
|
|
@ -2,17 +2,15 @@ package im.vector.riotredesign.features.home.room.list
|
|||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotredesign.features.home.HomeViewState
|
||||
|
||||
class RoomSummaryController(private val callback: Callback? = null
|
||||
) : TypedEpoxyController<HomeViewState>() {
|
||||
|
||||
) : TypedEpoxyController<RoomListViewState>() {
|
||||
|
||||
private var isDirectRoomsExpanded = true
|
||||
private var isGroupRoomsExpanded = true
|
||||
|
||||
override fun buildModels(viewState: HomeViewState) {
|
||||
|
||||
override fun buildModels(viewState: RoomListViewState) {
|
||||
val roomSummaries = viewState.asyncRooms()
|
||||
RoomCategoryItem(
|
||||
title = "DIRECT MESSAGES",
|
||||
isExpanded = isDirectRoomsExpanded,
|
||||
|
@ -25,16 +23,7 @@ class RoomSummaryController(private val callback: Callback? = null
|
|||
.addTo(this)
|
||||
|
||||
if (isDirectRoomsExpanded) {
|
||||
val filteredDirectRooms = viewState.directRooms.filter {
|
||||
if (viewState.selectedGroup == null) {
|
||||
true
|
||||
} else {
|
||||
it.otherMemberIds
|
||||
.intersect(viewState.selectedGroup.userIds)
|
||||
.isNotEmpty()
|
||||
}
|
||||
}
|
||||
buildRoomModels(filteredDirectRooms, viewState.selectedRoomId)
|
||||
buildRoomModels(roomSummaries?.directRooms ?: emptyList(), viewState.selectedRoomId)
|
||||
}
|
||||
|
||||
RoomCategoryItem(
|
||||
|
@ -49,10 +38,7 @@ class RoomSummaryController(private val callback: Callback? = null
|
|||
.addTo(this)
|
||||
|
||||
if (isGroupRoomsExpanded) {
|
||||
val filteredGroupRooms = viewState.groupRooms.filter {
|
||||
viewState.selectedGroup?.roomIds?.contains(it.roomId) ?: true
|
||||
}
|
||||
buildRoomModels(filteredGroupRooms, viewState.selectedRoomId)
|
||||
buildRoomModels(roomSummaries?.groupRooms ?: emptyList(), viewState.selectedRoomId)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ dependencies {
|
|||
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
|
||||
|
||||
// Paging
|
||||
api "android.arch.paging:runtime:1.0.1"
|
||||
implementation "android.arch.paging:runtime:1.0.1"
|
||||
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
|
|
@ -2,10 +2,10 @@ package im.vector.matrix.rx
|
|||
|
||||
import android.arch.paging.PagedList
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
class RxRoom(private val room: Room) {
|
||||
|
||||
|
@ -15,6 +15,7 @@ class RxRoom(private val room: Room) {
|
|||
|
||||
fun timeline(eventId: String? = null): Observable<PagedList<EnrichedEvent>> {
|
||||
return room.timeline(eventId).asObservable()
|
||||
.subscribeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue