Compare commits
5 Commits
develop
...
task/eric/
Author | SHA1 | Date | |
---|---|---|---|
|
4205925cf6 | ||
|
c148805db7 | ||
|
b37800a5eb | ||
|
72689c76de | ||
|
184aeaa5c8 |
@ -69,195 +69,26 @@ class SpaceListViewModel @AssistedInject constructor(
|
||||
private val analyticsTracker: AnalyticsTracker,
|
||||
) : VectorViewModel<SpaceListViewState, SpaceListAction, SpaceListViewEvents>(initialState) {
|
||||
|
||||
var preDragExpandedState: Map<String, Boolean>? = null
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MavericksAssistedViewModelFactory<SpaceListViewModel, SpaceListViewState> {
|
||||
override fun create(initialState: SpaceListViewState): SpaceListViewModel
|
||||
}
|
||||
|
||||
companion object : MavericksViewModelFactory<SpaceListViewModel, SpaceListViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
init {
|
||||
observeUser()
|
||||
observeSpaceSummaries()
|
||||
observeSelectedSpace()
|
||||
observeRoomSummaries()
|
||||
}
|
||||
|
||||
private fun observeUser() {
|
||||
session.userService().getUserLive(session.myUserId)
|
||||
.asFlow()
|
||||
.setOnEach {
|
||||
copy(
|
||||
myMxItem = it.getOrNull()?.toMatrixItem()?.let { Success(it) } ?: Loading()
|
||||
)
|
||||
.setOnEach { user ->
|
||||
copy(myMxItem = user.getOrNull()?.toMatrixItem()?.let { Success(it) } ?: Loading())
|
||||
}
|
||||
|
||||
observeSpaceSummaries()
|
||||
spaceStateHandler.getSelectedSpaceFlow()
|
||||
.distinctUntilChanged()
|
||||
.setOnEach { selectedSpaceOption ->
|
||||
copy(selectedSpace = selectedSpaceOption.orNull())
|
||||
}
|
||||
|
||||
// XXX there should be a way to refactor this and share it
|
||||
session.roomService().getPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
this.spaceFilter = roomsInSpaceFilter()
|
||||
}, sortOrder = RoomSortOrder.NONE
|
||||
).asFlow()
|
||||
.sample(300)
|
||||
.onEach {
|
||||
val inviteCount = if (autoAcceptInvites.hideInvites) {
|
||||
0
|
||||
} else {
|
||||
session.roomService().getRoomSummaries(
|
||||
roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) }
|
||||
).size
|
||||
}
|
||||
val totalCount = session.roomService().getNotificationCountForRooms(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
this.spaceFilter = roomsInSpaceFilter()
|
||||
}
|
||||
)
|
||||
val counts = RoomAggregateNotificationCount(
|
||||
totalCount.notificationCount + inviteCount,
|
||||
totalCount.highlightCount + inviteCount
|
||||
)
|
||||
setState {
|
||||
copy(
|
||||
homeAggregateCount = counts
|
||||
)
|
||||
}
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun roomsInSpaceFilter() = when {
|
||||
vectorPreferences.prefSpacesShowAllRoomInHome() -> SpaceFilter.NoFilter
|
||||
else -> SpaceFilter.OrphanRooms
|
||||
}
|
||||
|
||||
override fun handle(action: SpaceListAction) {
|
||||
when (action) {
|
||||
is SpaceListAction.SelectSpace -> handleSelectSpace(action)
|
||||
is SpaceListAction.LeaveSpace -> handleLeaveSpace(action)
|
||||
SpaceListAction.AddSpace -> handleAddSpace()
|
||||
is SpaceListAction.ToggleExpand -> handleToggleExpand(action)
|
||||
is SpaceListAction.OpenSpaceInvite -> handleSelectSpaceInvite(action)
|
||||
is SpaceListAction.MoveSpace -> handleMoveSpace(action)
|
||||
is SpaceListAction.OnEndDragging -> handleEndDragging()
|
||||
is SpaceListAction.OnStartDragging -> handleStartDragging()
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
var preDragExpandedState: Map<String, Boolean>? = null
|
||||
private fun handleStartDragging() = withState { state ->
|
||||
preDragExpandedState = state.expandedStates.toMap()
|
||||
setState {
|
||||
copy(
|
||||
expandedStates = expandedStates.map {
|
||||
it.key to false
|
||||
}.toMap()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleEndDragging() {
|
||||
// restore expanded state
|
||||
setState {
|
||||
copy(
|
||||
expandedStates = preDragExpandedState.orEmpty()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMoveSpace(action: SpaceListAction.MoveSpace) = withState { state ->
|
||||
state.rootSpacesOrdered ?: return@withState
|
||||
val orderCommands = SpaceOrderUtils.orderCommandsForMove(
|
||||
state.rootSpacesOrdered.map {
|
||||
it.roomId to (state.spaceOrderLocalEchos?.get(it.roomId) ?: state.spaceOrderInfo?.get(it.roomId))
|
||||
},
|
||||
action.spaceId,
|
||||
action.delta
|
||||
)
|
||||
|
||||
// local echo
|
||||
val updatedLocalEchos = state.spaceOrderLocalEchos.orEmpty().toMutableMap().apply {
|
||||
orderCommands.forEach {
|
||||
this[it.spaceId] = it.order
|
||||
}
|
||||
}.toMap()
|
||||
|
||||
setState {
|
||||
copy(
|
||||
rootSpacesOrdered = state.rootSpacesOrdered.toMutableList().apply {
|
||||
val index = indexOfFirst { it.roomId == action.spaceId }
|
||||
val moved = removeAt(index)
|
||||
add(index + action.delta, moved)
|
||||
},
|
||||
spaceOrderLocalEchos = updatedLocalEchos,
|
||||
)
|
||||
}
|
||||
session.coroutineScope.launch {
|
||||
orderCommands.forEach {
|
||||
session.getRoom(it.spaceId)?.roomAccountDataService()?.updateAccountData(
|
||||
RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER,
|
||||
SpaceOrderContent(order = it.order).toContent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// restore expanded state
|
||||
setState {
|
||||
copy(
|
||||
expandedStates = preDragExpandedState.orEmpty()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state ->
|
||||
if (state.selectedSpace?.roomId != action.spaceSummary?.roomId) {
|
||||
val interactionName = if (action.isSubSpace) {
|
||||
Interaction.Name.SpacePanelSwitchSubSpace
|
||||
} else {
|
||||
Interaction.Name.SpacePanelSwitchSpace
|
||||
}
|
||||
analyticsTracker.capture(
|
||||
Interaction(
|
||||
index = null,
|
||||
interactionType = null,
|
||||
name = interactionName
|
||||
)
|
||||
)
|
||||
setState { copy(selectedSpace = action.spaceSummary) }
|
||||
spaceStateHandler.setCurrentSpace(action.spaceSummary?.roomId)
|
||||
_viewEvents.post(SpaceListViewEvents.CloseDrawer)
|
||||
} else {
|
||||
analyticsTracker.capture(Interaction(null, null, Interaction.Name.SpacePanelSelectedSpace))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectSpaceInvite(action: SpaceListAction.OpenSpaceInvite) {
|
||||
_viewEvents.post(SpaceListViewEvents.OpenSpaceInvite(action.spaceSummary.roomId))
|
||||
}
|
||||
|
||||
private fun handleToggleExpand(action: SpaceListAction.ToggleExpand) = withState { state ->
|
||||
val updatedToggleStates = state.expandedStates.toMutableMap().apply {
|
||||
this[action.spaceSummary.roomId] = !(this[action.spaceSummary.roomId] ?: false)
|
||||
}
|
||||
setState {
|
||||
copy(expandedStates = updatedToggleStates)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleLeaveSpace(action: SpaceListAction.LeaveSpace) {
|
||||
viewModelScope.launch {
|
||||
tryOrNull("Failed to leave space ${action.spaceSummary.roomId}") {
|
||||
session.spaceService().leaveSpace(action.spaceSummary.roomId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAddSpace() {
|
||||
_viewEvents.post(SpaceListViewEvents.AddSpace)
|
||||
}
|
||||
|
||||
private fun observeSpaceSummaries() {
|
||||
@ -299,9 +130,170 @@ class SpaceListViewModel @AssistedInject constructor(
|
||||
.getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER))
|
||||
.asFlow()
|
||||
.execute {
|
||||
copy(
|
||||
spaceOrderLocalEchos = emptyMap()
|
||||
)
|
||||
copy(spaceOrderLocalEchos = emptyMap())
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeSelectedSpace() {
|
||||
spaceStateHandler.getSelectedSpaceFlow()
|
||||
.distinctUntilChanged()
|
||||
.setOnEach { selectedSpaceOption ->
|
||||
copy(selectedSpace = selectedSpaceOption.orNull())
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeRoomSummaries() {
|
||||
session.roomService().getPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
this.spaceFilter = roomsInSpaceFilter()
|
||||
}, sortOrder = RoomSortOrder.NONE
|
||||
).asFlow()
|
||||
.sample(300)
|
||||
.onEach {
|
||||
val inviteCount = if (autoAcceptInvites.hideInvites) {
|
||||
0
|
||||
} else {
|
||||
session.roomService().getRoomSummaries(
|
||||
roomSummaryQueryParams { this.memberships = listOf(Membership.INVITE) }
|
||||
).size
|
||||
}
|
||||
val totalCount = session.roomService().getNotificationCountForRooms(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
this.spaceFilter = roomsInSpaceFilter()
|
||||
}
|
||||
)
|
||||
val counts = RoomAggregateNotificationCount(
|
||||
totalCount.notificationCount + inviteCount,
|
||||
totalCount.highlightCount + inviteCount
|
||||
)
|
||||
setState {
|
||||
copy(homeAggregateCount = counts)
|
||||
}
|
||||
}
|
||||
.flowOn(Dispatchers.Default)
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
private fun roomsInSpaceFilter() = when {
|
||||
vectorPreferences.prefSpacesShowAllRoomInHome() -> SpaceFilter.NoFilter
|
||||
else -> SpaceFilter.OrphanRooms
|
||||
}
|
||||
|
||||
override fun handle(action: SpaceListAction) {
|
||||
when (action) {
|
||||
is SpaceListAction.SelectSpace -> handleSelectSpace(action)
|
||||
is SpaceListAction.LeaveSpace -> handleLeaveSpace(action)
|
||||
SpaceListAction.AddSpace -> handleAddSpace()
|
||||
is SpaceListAction.ToggleExpand -> handleToggleExpand(action)
|
||||
is SpaceListAction.OpenSpaceInvite -> handleOpenSpaceInvite(action)
|
||||
is SpaceListAction.MoveSpace -> handleMoveSpace(action)
|
||||
is SpaceListAction.OnStartDragging -> handleStartDragging()
|
||||
is SpaceListAction.OnEndDragging -> handleEndDragging()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state ->
|
||||
if (state.selectedSpace?.roomId != action.spaceSummary?.roomId) {
|
||||
val interactionName = if (action.isSubSpace) {
|
||||
Interaction.Name.SpacePanelSwitchSubSpace
|
||||
} else {
|
||||
Interaction.Name.SpacePanelSwitchSpace
|
||||
}
|
||||
analyticsTracker.capture(
|
||||
Interaction(
|
||||
index = null,
|
||||
interactionType = null,
|
||||
name = interactionName
|
||||
)
|
||||
)
|
||||
setState { copy(selectedSpace = action.spaceSummary) }
|
||||
spaceStateHandler.setCurrentSpace(action.spaceSummary?.roomId)
|
||||
_viewEvents.post(SpaceListViewEvents.CloseDrawer)
|
||||
} else {
|
||||
analyticsTracker.capture(Interaction(null, null, Interaction.Name.SpacePanelSelectedSpace))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleLeaveSpace(action: SpaceListAction.LeaveSpace) {
|
||||
viewModelScope.launch {
|
||||
tryOrNull("Failed to leave space ${action.spaceSummary.roomId}") {
|
||||
session.spaceService().leaveSpace(action.spaceSummary.roomId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleAddSpace() {
|
||||
_viewEvents.post(SpaceListViewEvents.AddSpace)
|
||||
}
|
||||
|
||||
private fun handleToggleExpand(action: SpaceListAction.ToggleExpand) = withState { state ->
|
||||
val updatedToggleStates = state.expandedStates.toMutableMap().apply {
|
||||
this[action.spaceSummary.roomId] = !(this[action.spaceSummary.roomId] ?: false)
|
||||
}
|
||||
setState {
|
||||
copy(expandedStates = updatedToggleStates)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleOpenSpaceInvite(action: SpaceListAction.OpenSpaceInvite) {
|
||||
_viewEvents.post(SpaceListViewEvents.OpenSpaceInvite(action.spaceSummary.roomId))
|
||||
}
|
||||
|
||||
private fun handleMoveSpace(action: SpaceListAction.MoveSpace) = withState { state ->
|
||||
state.rootSpacesOrdered ?: return@withState
|
||||
val orderCommands = SpaceOrderUtils.orderCommandsForMove(
|
||||
state.rootSpacesOrdered.map {
|
||||
it.roomId to (state.spaceOrderLocalEchos?.get(it.roomId) ?: state.spaceOrderInfo?.get(it.roomId))
|
||||
},
|
||||
action.spaceId,
|
||||
action.delta
|
||||
)
|
||||
|
||||
// local echo
|
||||
val updatedLocalEchos = state.spaceOrderLocalEchos.orEmpty().toMutableMap().apply {
|
||||
orderCommands.forEach { this[it.spaceId] = it.order }
|
||||
}.toMap()
|
||||
|
||||
setState {
|
||||
copy(
|
||||
rootSpacesOrdered = state.rootSpacesOrdered.toMutableList().apply {
|
||||
val index = indexOfFirst { it.roomId == action.spaceId }
|
||||
val moved = removeAt(index)
|
||||
add(index + action.delta, moved)
|
||||
},
|
||||
spaceOrderLocalEchos = updatedLocalEchos,
|
||||
)
|
||||
}
|
||||
session.coroutineScope.launch {
|
||||
orderCommands.forEach {
|
||||
session.getRoom(it.spaceId)?.roomAccountDataService()?.updateAccountData(
|
||||
RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER,
|
||||
SpaceOrderContent(order = it.order).toContent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// restore expanded state
|
||||
setState {
|
||||
copy(expandedStates = preDragExpandedState.orEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleStartDragging() = withState { state ->
|
||||
preDragExpandedState = state.expandedStates.toMap()
|
||||
setState {
|
||||
copy(expandedStates = expandedStates.map { it.key to false }.toMap())
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleEndDragging() {
|
||||
// restore expanded state
|
||||
setState {
|
||||
copy(expandedStates = preDragExpandedState.orEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
companion object : MavericksViewModelFactory<SpaceListViewModel, SpaceListViewState> by hiltMavericksViewModelFactory()
|
||||
}
|
||||
|
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.app.features.spaces
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.test.MvRxTestRule
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import im.vector.app.test.fakes.FakeAnalyticsTracker
|
||||
import im.vector.app.test.fakes.FakeAutoAcceptInvites
|
||||
import im.vector.app.test.fakes.FakeRoomService
|
||||
import im.vector.app.test.fakes.FakeSession
|
||||
import im.vector.app.test.fakes.FakeSessionAccountDataService
|
||||
import im.vector.app.test.fakes.FakeSpaceService
|
||||
import im.vector.app.test.fakes.FakeSpaceStateHandler
|
||||
import im.vector.app.test.fakes.FakeUserService
|
||||
import im.vector.app.test.fakes.FakeVectorPreferences
|
||||
import im.vector.app.test.fixtures.RoomSummaryFixture.aRoomSummary
|
||||
import im.vector.app.test.fixtures.UserFixture.aUser
|
||||
import im.vector.app.test.test
|
||||
import io.mockk.every
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkAll
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
internal class SpaceListViewModelTest {
|
||||
|
||||
@get:Rule
|
||||
val mvRxTestRule = MvRxTestRule(testDispatcher = UnconfinedTestDispatcher())
|
||||
|
||||
@get:Rule
|
||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||
|
||||
private val spaceStateHandler = FakeSpaceStateHandler()
|
||||
private val userService = FakeUserService()
|
||||
private val accountDataService = FakeSessionAccountDataService()
|
||||
private val roomService = FakeRoomService()
|
||||
private val spaceService = FakeSpaceService()
|
||||
private val session = FakeSession(
|
||||
fakeUserService = userService,
|
||||
fakeAccountDataService = accountDataService,
|
||||
fakeRoomService = roomService,
|
||||
fakeSpaceService = spaceService,
|
||||
)
|
||||
private val vectorPreferences = FakeVectorPreferences()
|
||||
private val autoAcceptInvites = FakeAutoAcceptInvites()
|
||||
private val analyticsTracker = FakeAnalyticsTracker()
|
||||
|
||||
private lateinit var spaceListViewModel: SpaceListViewModel
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockkStatic("org.matrix.android.sdk.flow.FlowSessionKt")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when view model init, then observe user and emit it in state`() = runTest {
|
||||
val user = aUser("@userid")
|
||||
userService.getUserLiveReturns(user)
|
||||
initViewModel()
|
||||
|
||||
val success = spaceListViewModel.awaitState().myMxItem as Success<MatrixItem.UserItem>
|
||||
success.invoke().id shouldBeEqualTo user.userId
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when view model init, then get space summaries and emit them in state`() = runTest {
|
||||
val spaceSummaries = listOf(aRoomSummary("space-1"), aRoomSummary("space-2"))
|
||||
givenSpaceSummaries(spaceSummaries)
|
||||
|
||||
initViewModel()
|
||||
|
||||
spaceListViewModel.awaitState().spaces shouldBeEqualTo spaceSummaries
|
||||
}
|
||||
|
||||
private fun givenSpaceSummaries(spaceSummaries: List<RoomSummary>) {
|
||||
val flowSession = session.givenFlowSession()
|
||||
every { flowSession.liveSpaceSummaries(any()) } returns flowOf(spaceSummaries)
|
||||
session.accountDataService().getLiveRoomAccountDataEventsReturns(emptyList())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when view model init, then get selected space and emit it in state`() = runTest {
|
||||
val currentSpace = aRoomSummary("space-id")
|
||||
spaceStateHandler.getSelectedSpaceFlowReturns(currentSpace)
|
||||
initViewModel()
|
||||
|
||||
spaceListViewModel.awaitState().selectedSpace shouldBeEqualTo currentSpace
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given valid space, when handle SelectSpace, then set and track`() = runTest {
|
||||
val spaceSummary = aRoomSummary("space-id")
|
||||
initViewModel()
|
||||
|
||||
spaceListViewModel.handle(SpaceListAction.SelectSpace(spaceSummary))
|
||||
|
||||
spaceListViewModel.awaitState().selectedSpace shouldBeEqualTo spaceSummary
|
||||
spaceStateHandler.verifySetCurrentSpace(spaceSummary.roomId)
|
||||
val interaction = analyticsTracker.verifyCaptureAndGetInteraction()
|
||||
interaction shouldBeEqualTo Interaction(null, null, Interaction.Name.SpacePanelSwitchSpace)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given null space, when handle SelectSpace, then track`() = runTest {
|
||||
val spaceSummary = null
|
||||
initViewModel()
|
||||
|
||||
spaceListViewModel.handle(SpaceListAction.SelectSpace(spaceSummary))
|
||||
|
||||
val interaction = analyticsTracker.verifyCaptureAndGetInteraction()
|
||||
interaction shouldBeEqualTo Interaction(null, null, Interaction.Name.SpacePanelSelectedSpace)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when handle LeaveSpace, then do SpaceService leaveSpace`() {
|
||||
val spaceSummary = aRoomSummary("space-id")
|
||||
initViewModel()
|
||||
|
||||
spaceListViewModel.handle(SpaceListAction.LeaveSpace(spaceSummary))
|
||||
|
||||
spaceService.verifyLeaveSpace(spaceSummary.roomId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when handle AddSpace, then post AddSpace event`() {
|
||||
initViewModel()
|
||||
val viewModelTest = spaceListViewModel.test()
|
||||
|
||||
spaceListViewModel.handle(SpaceListAction.AddSpace)
|
||||
|
||||
viewModelTest.assertEvents(SpaceListViewEvents.AddSpace)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when handle ToggleExpand, then update expanded states`() = runTest {
|
||||
val spaceSummary = aRoomSummary("space-id")
|
||||
initViewModel()
|
||||
|
||||
spaceListViewModel.handle(SpaceListAction.ToggleExpand(spaceSummary))
|
||||
|
||||
spaceListViewModel.awaitState().expandedStates[spaceSummary.roomId] shouldBeEqualTo true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when handle OpenSpaceInvite, then post OpenSpaceInvite event`() {
|
||||
val spaceSummary = aRoomSummary("space-id")
|
||||
initViewModel()
|
||||
val viewModelTest = spaceListViewModel.test()
|
||||
|
||||
spaceListViewModel.handle(SpaceListAction.OpenSpaceInvite(spaceSummary))
|
||||
|
||||
viewModelTest.assertEvents(SpaceListViewEvents.OpenSpaceInvite(spaceSummary.roomId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when handle StartDragging, then set expanded states to false`() = runTest {
|
||||
val spaceSummaries = listOf(aRoomSummary("room1"), aRoomSummary("room2"), aRoomSummary("room3"))
|
||||
givenSpaceSummaries(spaceSummaries)
|
||||
initViewModel()
|
||||
|
||||
spaceListViewModel.handle(SpaceListAction.ToggleExpand(spaceSummaries[1]))
|
||||
spaceListViewModel.handle(SpaceListAction.OnStartDragging(spaceSummaries[1].roomId, true))
|
||||
|
||||
spaceListViewModel.awaitState().expandedStates[spaceSummaries[1].roomId] shouldBeEqualTo false
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when handle EndDragging, then set expanded states to normal`() = runTest {
|
||||
val spaceSummaries = listOf(aRoomSummary("room1"), aRoomSummary("room2"), aRoomSummary("room3"))
|
||||
givenSpaceSummaries(spaceSummaries)
|
||||
initViewModel()
|
||||
|
||||
spaceListViewModel.handle(SpaceListAction.ToggleExpand(spaceSummaries[1]))
|
||||
spaceListViewModel.handle(SpaceListAction.OnStartDragging(spaceSummaries[1].roomId, true))
|
||||
spaceListViewModel.handle(SpaceListAction.OnEndDragging(spaceSummaries[1].roomId, true))
|
||||
|
||||
spaceListViewModel.awaitState().expandedStates[spaceSummaries[1].roomId] shouldBeEqualTo true
|
||||
}
|
||||
|
||||
private fun initViewModel() {
|
||||
spaceListViewModel = SpaceListViewModel(
|
||||
SpaceListViewState(),
|
||||
spaceStateHandler,
|
||||
session,
|
||||
vectorPreferences.instance,
|
||||
autoAcceptInvites,
|
||||
analyticsTracker,
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
fun teardown() {
|
||||
unmockkAll()
|
||||
}
|
||||
}
|
@ -17,6 +17,16 @@
|
||||
package im.vector.app.test.fakes
|
||||
|
||||
import im.vector.app.features.analytics.AnalyticsTracker
|
||||
import im.vector.app.features.analytics.plan.Interaction
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
|
||||
class FakeAnalyticsTracker : AnalyticsTracker by mockk(relaxUnitFun = true)
|
||||
class FakeAnalyticsTracker : AnalyticsTracker by mockk(relaxUnitFun = true) {
|
||||
|
||||
fun verifyCaptureAndGetInteraction(): Interaction {
|
||||
val slot = slot<Interaction>()
|
||||
verify { capture(capture(slot)) }
|
||||
return slot.captured
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class FakeRoom(
|
||||
private val fakeSendService: FakeSendService = FakeSendService(),
|
||||
private val fakeTimelineService: FakeTimelineService = FakeTimelineService(),
|
||||
private val fakeRelationService: FakeRelationService = FakeRelationService(),
|
||||
) : Room by mockk() {
|
||||
) : Room by mockk(relaxed = true) {
|
||||
|
||||
override fun locationSharingService() = fakeLocationSharingService
|
||||
|
||||
|
@ -23,7 +23,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
|
||||
class FakeRoomService(
|
||||
private val fakeRoom: FakeRoom = FakeRoom()
|
||||
) : RoomService by mockk() {
|
||||
) : RoomService by mockk(relaxed = true) {
|
||||
|
||||
override fun getRoom(roomId: String) = fakeRoom
|
||||
|
||||
|
@ -41,6 +41,9 @@ class FakeSession(
|
||||
val fakeHomeServerCapabilitiesService: FakeHomeServerCapabilitiesService = FakeHomeServerCapabilitiesService(),
|
||||
val fakeSharedSecretStorageService: FakeSharedSecretStorageService = FakeSharedSecretStorageService(),
|
||||
val fakeRoomService: FakeRoomService = FakeRoomService(),
|
||||
val fakeUserService: FakeUserService = FakeUserService(),
|
||||
val fakeSpaceService: FakeSpaceService = FakeSpaceService(),
|
||||
val fakeAccountDataService: FakeSessionAccountDataService = FakeSessionAccountDataService(),
|
||||
private val fakeEventService: FakeEventService = FakeEventService(),
|
||||
) : Session by mockk(relaxed = true) {
|
||||
|
||||
@ -58,6 +61,9 @@ class FakeSession(
|
||||
override fun sharedSecretStorageService() = fakeSharedSecretStorageService
|
||||
override fun roomService() = fakeRoomService
|
||||
override fun eventService() = fakeEventService
|
||||
override fun userService() = fakeUserService
|
||||
override fun spaceService() = fakeSpaceService
|
||||
override fun accountDataService() = fakeAccountDataService
|
||||
|
||||
fun givenVectorStore(vectorSessionStore: VectorSessionStore) {
|
||||
coEvery {
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.app.test.fakes
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
|
||||
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataEvent
|
||||
|
||||
class FakeSessionAccountDataService : SessionAccountDataService by mockk(relaxed = true) {
|
||||
|
||||
fun getLiveRoomAccountDataEventsReturns(events: List<RoomAccountDataEvent>) {
|
||||
val liveData = MutableLiveData(events)
|
||||
every { getLiveRoomAccountDataEvents(any()) } returns liveData
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.app.test.fakes
|
||||
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import org.matrix.android.sdk.api.session.space.SpaceService
|
||||
|
||||
class FakeSpaceService : SpaceService by mockk(relaxed = true) {
|
||||
|
||||
fun verifyLeaveSpace(spaceId: String) {
|
||||
coVerify { leaveSpace(spaceId, any()) }
|
||||
}
|
||||
}
|
@ -16,11 +16,19 @@
|
||||
|
||||
package im.vector.app.test.fakes
|
||||
|
||||
import arrow.core.Option
|
||||
import im.vector.app.SpaceStateHandler
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
|
||||
class FakeSpaceStateHandler : SpaceStateHandler by mockk(relaxUnitFun = true) {
|
||||
class FakeSpaceStateHandler : SpaceStateHandler by mockk(relaxed = true) {
|
||||
|
||||
fun getSelectedSpaceFlowReturns(space: RoomSummary) {
|
||||
every { getSelectedSpaceFlow() } returns flowOf(Option(space))
|
||||
}
|
||||
|
||||
fun verifySetCurrentSpace(spaceId: String) {
|
||||
verify { setCurrentSpace(spaceId) }
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.app.test.fakes
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.matrix.android.sdk.api.session.user.UserService
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
import org.matrix.android.sdk.api.util.Optional
|
||||
|
||||
class FakeUserService : UserService by mockk(relaxed = true) {
|
||||
|
||||
fun getUserLiveReturns(user: User? = null): LiveData<Optional<User>> {
|
||||
val liveData = MutableLiveData(Optional(user))
|
||||
every { getUserLive(any()) } returns liveData
|
||||
return liveData
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ import io.mockk.verify
|
||||
|
||||
class FakeVectorPreferences {
|
||||
|
||||
val instance = mockk<VectorPreferences>(relaxUnitFun = true)
|
||||
val instance = mockk<VectorPreferences>(relaxed = true)
|
||||
|
||||
fun givenUseCompleteNotificationFormat(value: Boolean) {
|
||||
every { instance.useCompleteNotificationFormat() } returns value
|
||||
|
24
vector/src/test/java/im/vector/app/test/fixtures/UserFixture.kt
vendored
Normal file
24
vector/src/test/java/im/vector/app/test/fixtures/UserFixture.kt
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2022 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.app.test.fixtures
|
||||
|
||||
import org.matrix.android.sdk.api.session.user.model.User
|
||||
|
||||
object UserFixture {
|
||||
|
||||
fun aUser(userId: String) = User(userId)
|
||||
}
|
Loading…
Reference in New Issue
Block a user