Home : use only one ViewModel and one state

This commit is contained in:
ganfra 2018-11-05 21:58:03 +01:00
parent 64759abc9e
commit 5cc617168e
14 changed files with 96 additions and 145 deletions

View File

@ -0,0 +1,14 @@
package im.vector.riotredesign.features.home

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()

object RoomDisplayed : HomeActions()

}

View File

@ -1,4 +1,4 @@
package im.vector.riotredesign.features.home.room.list
package im.vector.riotredesign.features.home

import android.support.v4.app.FragmentActivity
import com.airbnb.mvrx.BaseMvRxViewModel
@ -6,39 +6,36 @@ 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.features.home.group.GroupListActions
import im.vector.riotredesign.features.home.group.GroupListViewModel
import im.vector.riotredesign.features.home.group.GroupListViewState
import org.koin.android.ext.android.get

class RoomListViewModel(initialState: RoomListViewState,
private val session: Session
) : BaseMvRxViewModel<RoomListViewState>(initialState) {
class HomeViewModel(initialState: HomeViewState, private val session: Session) : BaseMvRxViewModel<HomeViewState>(initialState) {

companion object : MvRxViewModelFactory<RoomListViewState> {
companion object : MvRxViewModelFactory<HomeViewState> {

@JvmStatic
override fun create(activity: FragmentActivity, state: RoomListViewState): RoomListViewModel {
override fun create(activity: FragmentActivity, state: HomeViewState): HomeViewModel {
val matrix = activity.get<Matrix>()
val currentSession = matrix.currentSession
return RoomListViewModel(state, currentSession)
return HomeViewModel(state, currentSession)
}
}

init {
observeRoomSummaries()
observeGroupSummaries()
}

fun accept(action: RoomListActions) {
fun accept(action: HomeActions) {
when (action) {
is RoomListActions.SelectRoom -> handleSelectRoom(action)
is RoomListActions.RoomDisplayed -> setState { copy(shouldOpenRoomDetail = false) }
is HomeActions.SelectRoom -> handleSelectRoom(action)
is HomeActions.SelectGroup -> handleSelectGroup(action)
is HomeActions.RoomDisplayed -> setState { copy(shouldOpenRoomDetail = false) }
}
}

// PRIVATE METHODS *****************************************************************************

private fun handleSelectRoom(action: RoomListActions.SelectRoom) {
private fun handleSelectRoom(action: HomeActions.SelectRoom) {
withState { state ->
if (state.selectedRoom?.roomId != action.roomSummary.roomId) {
session.saveLastSelectedRoom(action.roomSummary)
@ -47,6 +44,14 @@ class RoomListViewModel(initialState: RoomListViewState,
}
}

private fun handleSelectGroup(action: HomeActions.SelectGroup) {
withState { state ->
if (state.selectedGroup?.groupId != action.groupSummary.groupId) {
setState { copy(selectedGroup = action.groupSummary) }
}
}
}

private fun observeRoomSummaries() {
session
.rx().liveRoomSummaries()
@ -61,7 +66,7 @@ class RoomListViewModel(initialState: RoomListViewState,
?: groupRooms.firstOrNull()

copy(
async = async,
asyncRooms = async,
directRooms = directRooms,
groupRooms = groupRooms,
selectedRoom = selectedRoom
@ -69,4 +74,11 @@ class RoomListViewModel(initialState: RoomListViewState,
}
}

private fun observeGroupSummaries() {
session
.rx().liveGroupSummaries()
.execute { async ->
copy(asyncGroups = async)
}
}
}

View File

@ -0,0 +1,17 @@
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 selectedRoom: RoomSummary? = null,
val shouldOpenRoomDetail: Boolean = true,
val asyncGroups: Async<List<GroupSummary>> = Uninitialized,
val selectedGroup: GroupSummary? = null
) : MvRxState

View File

@ -1,9 +0,0 @@
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()

}

View File

@ -6,12 +6,15 @@ import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.activityViewModel
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 kotlinx.android.synthetic.main.fragment_room_list.*
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 {

@ -21,8 +24,9 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
}
}

private val viewModel: GroupListViewModel by fragmentViewModel()
private lateinit var roomController: GroupSummaryController
private val viewModel: HomeViewModel by activityViewModel()

private lateinit var groupController: GroupSummaryController

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_group_list, container, false)
@ -30,22 +34,22 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
roomController = GroupSummaryController(this)
groupController = GroupSummaryController(this)
stateView.contentView = epoxyRecyclerView
epoxyRecyclerView.setController(roomController)
epoxyRecyclerView.setController(groupController)
viewModel.subscribe { renderState(it) }
}

private fun renderState(state: GroupListViewState) {
when (state.async) {
private fun renderState(state: HomeViewState) {
when (state.asyncGroups) {
is Incomplete -> renderLoading()
is Success -> renderSuccess(state)
is Success -> renderSuccess(state)
}
}

private fun renderSuccess(state: GroupListViewState) {
private fun renderSuccess(state: HomeViewState) {
stateView.state = StateView.State.Content
roomController.setData(state)
groupController.setData(state)
}

private fun renderLoading() {
@ -53,7 +57,7 @@ class GroupListFragment : RiotFragment(), GroupSummaryController.Callback {
}

override fun onGroupSelected(groupSummary: GroupSummary) {
viewModel.accept(GroupListActions.SelectGroup(groupSummary))
viewModel.accept(HomeActions.SelectGroup(groupSummary))
}

}

View File

@ -1,53 +0,0 @@
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 org.koin.android.ext.android.get

class GroupListViewModel(initialState: GroupListViewState,
private val session: Session
) : BaseMvRxViewModel<GroupListViewState>(initialState) {

companion object : MvRxViewModelFactory<GroupListViewState> {

@JvmStatic
override fun create(activity: FragmentActivity, state: GroupListViewState): GroupListViewModel {
val matrix = activity.get<Matrix>()
val currentSession = matrix.currentSession
return GroupListViewModel(state, currentSession)
}
}

init {
observeGroupSummaries()
}

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) }
}
}
}

private fun observeGroupSummaries() {
session
.rx().liveGroupSummaries()
.execute { async ->
copy(async = async)
}
}

}

View File

@ -1,12 +0,0 @@
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
import im.vector.matrix.android.api.session.room.model.RoomSummary

data class GroupListViewState(
val async: Async<List<GroupSummary>> = Uninitialized,
val selectedGroup: GroupSummary? = null
) : MvRxState

View File

@ -2,12 +2,13 @@ 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<GroupListViewState>() {
) : TypedEpoxyController<HomeViewState>() {

override fun buildModels(viewState: GroupListViewState) {
buildGroupModels(viewState.async(), viewState.selectedGroup)
override fun buildModels(viewState: HomeViewState) {
buildGroupModels(viewState.asyncGroups(), viewState.selectedGroup)
}

private fun buildGroupModels(summaries: List<GroupSummary>?, selected: GroupSummary?) {

View File

@ -16,6 +16,7 @@ data class GroupSummaryItem(
private val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)

override fun bind() {
avatarImageView.setOnClickListener { listener?.invoke() }
AvatarRenderer.render(avatarUrl, groupName.toString(), avatarImageView)
}
}

View File

@ -1,12 +0,0 @@
package im.vector.riotredesign.features.home.room.list

import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotredesign.features.home.group.GroupListActions

sealed class RoomListActions {

data class SelectRoom(val roomSummary: RoomSummary) : RoomListActions()

object RoomDisplayed : RoomListActions()

}

View File

@ -7,13 +7,16 @@ import android.view.ViewGroup
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Success
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.activityViewModel
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.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

@ -26,7 +29,7 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
}

private val homeNavigator by inject<HomeNavigator>()
private val viewModel: RoomListViewModel by fragmentViewModel()
private val viewModel: HomeViewModel by activityViewModel()
private lateinit var roomController: RoomSummaryController

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -41,20 +44,20 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
viewModel.subscribe { renderState(it) }
}

private fun renderState(state: RoomListViewState) {
when (state.async) {
private fun renderState(state: HomeViewState) {
when (state.asyncRooms) {
is Incomplete -> renderLoading()
is Success -> renderSuccess(state)
is Fail -> renderFailure(state.async.error)
is Success -> renderSuccess(state)
is Fail -> renderFailure(state.asyncRooms.error)
}
if (state.shouldOpenRoomDetail && state.selectedRoom != null) {
homeNavigator.openRoomDetail(state.selectedRoom.roomId)
viewModel.accept(RoomListActions.RoomDisplayed)
viewModel.accept(HomeActions.RoomDisplayed)
}
}

private fun renderSuccess(state: RoomListViewState) {
if (state.async().isNullOrEmpty()) {
private fun renderSuccess(state: HomeViewState) {
if (state.asyncRooms().isNullOrEmpty()) {
stateView.state = StateView.State.Empty(getString(R.string.room_list_empty))
} else {
stateView.state = StateView.State.Content
@ -69,13 +72,13 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
private fun renderFailure(error: Throwable) {
val message = when (error) {
is Failure.NetworkConnection -> getString(R.string.error_no_network)
else -> getString(R.string.error_common)
else -> getString(R.string.error_common)
}
stateView.state = StateView.State.Error(message)
}

override fun onRoomSelected(room: RoomSummary) {
viewModel.accept(RoomListActions.SelectRoom(room))
viewModel.accept(HomeActions.SelectRoom(room))
}

}

View File

@ -1,14 +0,0 @@
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 async: Async<List<RoomSummary>> = Uninitialized,
val directRooms: List<RoomSummary> = emptyList(),
val groupRooms: List<RoomSummary> = emptyList(),
val selectedRoom: RoomSummary? = null,
val shouldOpenRoomDetail: Boolean = true
) : MvRxState

View File

@ -2,17 +2,16 @@ 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.group.GroupListViewState
import im.vector.riotredesign.features.home.group.GroupSummaryItem
import im.vector.riotredesign.features.home.HomeViewState

class RoomSummaryController(private val callback: Callback? = null
) : TypedEpoxyController<RoomListViewState>() {
) : TypedEpoxyController<HomeViewState>() {


private var isDirectRoomsExpanded = true
private var isGroupRoomsExpanded = true

override fun buildModels(viewState: RoomListViewState) {
override fun buildModels(viewState: HomeViewState) {

RoomCategoryItem(
title = "DIRECT MESSAGES",