Fix suggested rooms
This commit is contained in:
parent
0d3c2b4bef
commit
b635663ae3
|
@ -28,6 +28,7 @@ import androidx.core.view.isVisible
|
|||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import com.airbnb.epoxy.OnModelBuildFinishedListener
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -92,11 +93,11 @@ class RoomListFragment @Inject constructor(
|
|||
data class SectionAdapterInfo(
|
||||
var section: SectionKey,
|
||||
val headerHeaderAdapter: SectionHeaderAdapter,
|
||||
val contentAdapter: RoomSummaryPagedController
|
||||
val contentAdapter: EpoxyController
|
||||
)
|
||||
|
||||
private val adapterInfosList = mutableListOf<SectionAdapterInfo>()
|
||||
private var concatAdapter : ConcatAdapter? = null
|
||||
private var concatAdapter: ConcatAdapter? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -125,7 +126,7 @@ class RoomListFragment @Inject constructor(
|
|||
// it's for invites local echo
|
||||
adapterInfosList.filter { it.section.notifyOfLocalEcho }
|
||||
.onEach {
|
||||
it.contentAdapter.roomChangeMembershipStates = ms
|
||||
(it.contentAdapter as? RoomSummaryPagedController)?.roomChangeMembershipStates = ms
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,8 +181,8 @@ class RoomListFragment @Inject constructor(
|
|||
private fun setupCreateRoomButton() {
|
||||
when (roomListParams.displayMode) {
|
||||
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.isVisible = true
|
||||
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true
|
||||
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true
|
||||
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true
|
||||
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true
|
||||
else -> Unit // No button in this mode
|
||||
}
|
||||
|
||||
|
@ -249,23 +250,62 @@ class RoomListFragment @Inject constructor(
|
|||
it.updateSection(SectionHeaderAdapter.RoomsSectionData(section.sectionName))
|
||||
}
|
||||
|
||||
val contentAdapter = pagedControllerFactory.createRoomSummaryPagedController()
|
||||
.also { controller ->
|
||||
section.livePages.observe(viewLifecycleOwner) { pl ->
|
||||
controller.submitList(pl)
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(isHidden = pl.isEmpty()))
|
||||
checkEmptyState()
|
||||
val contentAdapter =
|
||||
when {
|
||||
section.livePages != null -> {
|
||||
pagedControllerFactory.createRoomSummaryPagedController()
|
||||
.also { controller ->
|
||||
section.livePages.observe(viewLifecycleOwner) { pl ->
|
||||
controller.submitList(pl)
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(isHidden = pl.isEmpty()))
|
||||
checkEmptyState()
|
||||
}
|
||||
section.notificationCount.observe(viewLifecycleOwner) { counts ->
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(
|
||||
notificationCount = counts.totalCount,
|
||||
isHighlighted = counts.isHighlight
|
||||
))
|
||||
}
|
||||
section.isExpanded.observe(viewLifecycleOwner) { _ ->
|
||||
refreshCollapseStates()
|
||||
}
|
||||
controller.listener = this
|
||||
}
|
||||
}
|
||||
section.notificationCount.observe(viewLifecycleOwner) { counts ->
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(
|
||||
notificationCount = counts.totalCount,
|
||||
isHighlighted = counts.isHighlight
|
||||
))
|
||||
section.liveSuggested != null -> {
|
||||
pagedControllerFactory.createSuggestedRoomListController()
|
||||
.also { controller ->
|
||||
section.liveSuggested.observe(viewLifecycleOwner) { info ->
|
||||
controller.setData(info)
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(isHidden = info.rooms.isEmpty()))
|
||||
checkEmptyState()
|
||||
}
|
||||
section.isExpanded.observe(viewLifecycleOwner) { _ ->
|
||||
refreshCollapseStates()
|
||||
}
|
||||
controller.listener = this
|
||||
}
|
||||
}
|
||||
section.isExpanded.observe(viewLifecycleOwner) { _ ->
|
||||
refreshCollapseStates()
|
||||
else -> {
|
||||
pagedControllerFactory.createRoomSummaryListController()
|
||||
.also { controller ->
|
||||
section.liveList?.observe(viewLifecycleOwner) { list ->
|
||||
controller.setData(list)
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(isHidden = list.isEmpty()))
|
||||
checkEmptyState()
|
||||
}
|
||||
section.notificationCount.observe(viewLifecycleOwner) { counts ->
|
||||
sectionAdapter.updateSection(sectionAdapter.roomsSectionData.copy(
|
||||
notificationCount = counts.totalCount,
|
||||
isHighlighted = counts.isHighlight
|
||||
))
|
||||
}
|
||||
section.isExpanded.observe(viewLifecycleOwner) { _ ->
|
||||
refreshCollapseStates()
|
||||
}
|
||||
controller.listener = this
|
||||
}
|
||||
}
|
||||
controller.listener = this
|
||||
}
|
||||
adapterInfosList.add(
|
||||
SectionAdapterInfo(
|
||||
|
@ -294,8 +334,8 @@ class RoomListFragment @Inject constructor(
|
|||
if (isAdded) {
|
||||
when (roomListParams.displayMode) {
|
||||
RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.show()
|
||||
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.show()
|
||||
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.show()
|
||||
RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.show()
|
||||
RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.show()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
@ -368,14 +408,14 @@ class RoomListFragment @Inject constructor(
|
|||
image = ContextCompat.getDrawable(requireContext(), R.drawable.ic_noun_party_popper),
|
||||
message = getString(R.string.room_list_catchup_empty_body))
|
||||
}
|
||||
RoomListDisplayMode.PEOPLE ->
|
||||
RoomListDisplayMode.PEOPLE ->
|
||||
StateView.State.Empty(
|
||||
title = getString(R.string.room_list_people_empty_title),
|
||||
image = ContextCompat.getDrawable(requireContext(), R.drawable.empty_state_dm),
|
||||
isBigImage = true,
|
||||
message = getString(R.string.room_list_people_empty_body)
|
||||
)
|
||||
RoomListDisplayMode.ROOMS ->
|
||||
RoomListDisplayMode.ROOMS ->
|
||||
StateView.State.Empty(
|
||||
title = getString(R.string.room_list_rooms_empty_title),
|
||||
image = ContextCompat.getDrawable(requireContext(), R.drawable.empty_state_room),
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
package im.vector.app.features.home.room.list
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
|
@ -32,6 +34,7 @@ import im.vector.app.core.platform.VectorViewModel
|
|||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.rxkotlin.Observables
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -70,6 +73,8 @@ class RoomListViewModel @Inject constructor(
|
|||
|
||||
private var activeSpaceAwareQueries: List<ActiveSpaceQueryUpdater>? = null
|
||||
|
||||
val suggestedRoomJoiningState: MutableLiveData<Map<String, Async<Unit>>> = MutableLiveData(emptyMap())
|
||||
|
||||
interface ActiveSpaceQueryUpdater {
|
||||
fun updateForSpaceId(roomId: String?)
|
||||
}
|
||||
|
@ -86,31 +91,12 @@ class RoomListViewModel @Inject constructor(
|
|||
appStateHandler.selectedSpaceDataSource.observe()
|
||||
// .observeOn(Schedulers.computation())
|
||||
.distinctUntilChanged()
|
||||
.switchMap { activeSpaceOption ->
|
||||
.subscribe { activeSpaceOption ->
|
||||
val selectedSpace = activeSpaceOption.orNull()
|
||||
activeSpaceAwareQueries?.onEach { updater ->
|
||||
updater.updateForSpaceId(selectedSpace?.roomId?.takeIf { MatrixPatterns.isRoomId(it) })
|
||||
}
|
||||
// activeSpaceAwareQueries?.forEach {
|
||||
// it.updateQuery {
|
||||
// it.copy(
|
||||
// activeSpaceId = ActiveSpaceFilter.ActiveSpace(selectedSpace?.roomId?.takeIf { MatrixPatterns.isRoomId(it) })
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
if (selectedSpace == null) {
|
||||
Observable.just(emptyList())
|
||||
} else {
|
||||
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
|
||||
val spaceSum = tryOrNull { session.spaceService().querySpaceChildren(selectedSpace.roomId, suggestedOnly = true) }
|
||||
val value = spaceSum?.second ?: emptyList()
|
||||
emit(value)
|
||||
}.asObservable()
|
||||
}
|
||||
}
|
||||
.execute { info ->
|
||||
copy(asyncSuggestedRooms = info)
|
||||
}
|
||||
}.disposeOnClear()
|
||||
|
||||
appStateHandler.selectedSpaceDataSource.observe()
|
||||
// .observeOn(Schedulers.computation())
|
||||
|
@ -244,6 +230,51 @@ class RoomListViewModel @Inject constructor(
|
|||
it.roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
it.roomTagQueryFilter = RoomTagQueryFilter(null, null, true)
|
||||
}
|
||||
|
||||
// add suggested rooms
|
||||
val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
|
||||
appStateHandler.selectedSpaceDataSource.observe()
|
||||
.distinctUntilChanged()
|
||||
.switchMap { activeSpaceOption ->
|
||||
val selectedSpace = activeSpaceOption.orNull()
|
||||
if (selectedSpace == null) {
|
||||
Observable.just(emptyList())
|
||||
} else {
|
||||
liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) {
|
||||
val spaceSum = tryOrNull { session.spaceService().querySpaceChildren(selectedSpace.roomId, suggestedOnly = true) }
|
||||
val value = spaceSum?.second ?: emptyList()
|
||||
// i need to check if it's already joined.
|
||||
val filtered = value.filter {
|
||||
session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true
|
||||
}
|
||||
emit(filtered)
|
||||
}.asObservable()
|
||||
}
|
||||
}
|
||||
// .subscribe {
|
||||
// Timber.w("VAL: Suggested rooms is ${it}")
|
||||
// liveSuggestedRooms.postValue(it)
|
||||
// }.disposeOnClear()
|
||||
|
||||
val liveSuggestedRooms = MutableLiveData<SuggestedRoomInfo>()
|
||||
Observables.combineLatest(
|
||||
suggestedRoomsObservable,
|
||||
suggestedRoomJoiningState.asObservable()
|
||||
) { rooms, joinStates ->
|
||||
SuggestedRoomInfo(
|
||||
rooms,
|
||||
joinStates
|
||||
)
|
||||
}.subscribe {
|
||||
liveSuggestedRooms.postValue(it)
|
||||
}.disposeOnClear()
|
||||
sections.add(
|
||||
RoomsSection(
|
||||
sectionName = stringProvider.getString(R.string.suggested_header),
|
||||
liveSuggested = liveSuggestedRooms,
|
||||
notifyOfLocalEcho = false
|
||||
)
|
||||
)
|
||||
} else if (initialState.displayMode == RoomListDisplayMode.FILTERED) {
|
||||
withQueryParams(
|
||||
{
|
||||
|
@ -499,33 +530,22 @@ class RoomListViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleJoinSuggestedRoom(action: RoomListAction.JoinSuggestedRoom) {
|
||||
setState {
|
||||
copy(
|
||||
suggestedRoomJoiningState = this.suggestedRoomJoiningState.toMutableMap().apply {
|
||||
this[action.roomId] = Loading()
|
||||
}.toMap()
|
||||
)
|
||||
}
|
||||
suggestedRoomJoiningState.postValue(suggestedRoomJoiningState.value.orEmpty().toMutableMap().apply {
|
||||
this[action.roomId] = Loading()
|
||||
}.toMap())
|
||||
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
awaitCallback<Unit> {
|
||||
session.joinRoom(action.roomId, null, action.viaServers ?: emptyList(), it)
|
||||
}
|
||||
setState {
|
||||
copy(
|
||||
suggestedRoomJoiningState = this.suggestedRoomJoiningState.toMutableMap().apply {
|
||||
this[action.roomId] = Success(Unit)
|
||||
}.toMap()
|
||||
)
|
||||
}
|
||||
suggestedRoomJoiningState.postValue(suggestedRoomJoiningState.value.orEmpty().toMutableMap().apply {
|
||||
this[action.roomId] = Success(Unit)
|
||||
}.toMap())
|
||||
} catch (failure: Throwable) {
|
||||
setState {
|
||||
copy(
|
||||
suggestedRoomJoiningState = this.suggestedRoomJoiningState.toMutableMap().apply {
|
||||
this[action.roomId] = Fail(failure)
|
||||
}.toMap()
|
||||
)
|
||||
}
|
||||
suggestedRoomJoiningState.postValue(suggestedRoomJoiningState.value.orEmpty().toMutableMap().apply {
|
||||
this[action.roomId] = Fail(failure)
|
||||
}.toMap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ data class RoomListViewState(
|
|||
val roomFilter: String = "",
|
||||
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
||||
val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized,
|
||||
val suggestedRoomJoiningState: Map<String, Async<Unit>> = emptyMap(),
|
||||
val currentUserName: String? = null,
|
||||
val currentSpace: Async<RoomSummary?> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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.home.room.list
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
|
||||
class RoomSummaryListController(
|
||||
private val roomSummaryItemFactory: RoomSummaryItemFactory
|
||||
) : TypedEpoxyController<List<RoomSummary>>() {
|
||||
|
||||
var listener: RoomListListener? = null
|
||||
|
||||
override fun buildModels(data: List<RoomSummary>?) {
|
||||
data?.forEach {
|
||||
add(roomSummaryItemFactory.create(it, emptyMap(), emptySet(), listener))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,14 @@ class RoomSummaryPagedControllerFactory @Inject constructor(
|
|||
fun createRoomSummaryPagedController(): RoomSummaryPagedController {
|
||||
return RoomSummaryPagedController(roomSummaryItemFactory)
|
||||
}
|
||||
|
||||
fun createRoomSummaryListController(): RoomSummaryListController {
|
||||
return RoomSummaryListController(roomSummaryItemFactory)
|
||||
}
|
||||
|
||||
fun createSuggestedRoomListController(): SuggestedRoomListController {
|
||||
return SuggestedRoomListController(roomSummaryItemFactory)
|
||||
}
|
||||
}
|
||||
|
||||
class RoomSummaryPagedController(
|
||||
|
|
|
@ -24,7 +24,10 @@ import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotification
|
|||
|
||||
data class RoomsSection(
|
||||
val sectionName: String,
|
||||
val livePages: LiveData<PagedList<RoomSummary>>,
|
||||
// can be a paged list or a regular list
|
||||
val livePages: LiveData<PagedList<RoomSummary>>? = null,
|
||||
val liveList: LiveData<List<RoomSummary>>? = null,
|
||||
val liveSuggested: LiveData<SuggestedRoomInfo>? = null,
|
||||
val isExpanded: MutableLiveData<Boolean> = MutableLiveData(true),
|
||||
val notificationCount: MutableLiveData<RoomAggregateNotificationCount> = MutableLiveData(RoomAggregateNotificationCount(0, 0)),
|
||||
val notifyOfLocalEcho: Boolean = false
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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.home.room.list
|
||||
|
||||
import com.airbnb.mvrx.Async
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
|
||||
class SuggestedRoomInfo(
|
||||
val rooms: List<SpaceChildInfo>,
|
||||
val joinEcho: Map<String, Async<Unit>>
|
||||
)
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2021 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.home.room.list
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
|
||||
class SuggestedRoomListController(
|
||||
private val roomSummaryItemFactory: RoomSummaryItemFactory
|
||||
) : TypedEpoxyController<SuggestedRoomInfo>() {
|
||||
|
||||
var listener: RoomListListener? = null
|
||||
|
||||
override fun buildModels(data: SuggestedRoomInfo?) {
|
||||
data?.rooms?.forEach { info ->
|
||||
roomSummaryItemFactory.createSuggestion(info, data.joinEcho) {
|
||||
listener?.onJoinSuggestedRoom(info)
|
||||
}.let {
|
||||
add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue