mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 20:06:51 +03:00
Support summary pagination API in manage space
This commit is contained in:
parent
5297512f87
commit
c01b36a648
7 changed files with 110 additions and 25 deletions
|
@ -213,5 +213,4 @@ class SpaceDirectoryFragment @Inject constructor(
|
|||
// nothing?
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
paginationStatus = state.paginationStatus.toMutableMap().apply {
|
||||
this[spaceId] = Uninitialized
|
||||
}.toMap(),
|
||||
knownRoomSummaries = (state.knownRoomSummaries + knownSummaries).distinctBy { it.roomId },
|
||||
knownRoomSummaries = (state.knownRoomSummaries + knownSummaries).distinctBy { it.roomId }
|
||||
)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
|
@ -288,7 +288,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
|
|||
cachedResults[currentRootId] = Success(
|
||||
currentResponse.copy(
|
||||
children = currentResponse.children + query.children,
|
||||
nextToken = query.nextToken,
|
||||
nextToken = query.nextToken
|
||||
)
|
||||
)
|
||||
setState {
|
||||
|
|
|
@ -25,4 +25,5 @@ sealed class SpaceManageRoomViewAction : VectorViewModelAction {
|
|||
data class MarkAllAsSuggested(val suggested: Boolean) : SpaceManageRoomViewAction()
|
||||
object BulkRemove : SpaceManageRoomViewAction()
|
||||
object RefreshFromServer : SpaceManageRoomViewAction()
|
||||
object LoadAdditionalItemsIfNeeded : SpaceManageRoomViewAction()
|
||||
}
|
||||
|
|
|
@ -20,15 +20,16 @@ import com.airbnb.mvrx.Async
|
|||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
import org.matrix.android.sdk.internal.session.space.SpaceHierarchySummary
|
||||
|
||||
data class SpaceManageRoomViewState(
|
||||
val spaceId: String,
|
||||
val spaceSummary: Async<RoomSummary> = Uninitialized,
|
||||
val childrenInfo: Async<List<SpaceChildInfo>> = Uninitialized,
|
||||
val childrenInfo: Async<SpaceHierarchySummary> = Uninitialized,
|
||||
val selectedRooms: List<String> = emptyList(),
|
||||
val currentFilter: String = "",
|
||||
val actionState: Async<Unit> = Uninitialized
|
||||
val actionState: Async<Unit> = Uninitialized,
|
||||
val paginationStatus: Async<Unit> = Uninitialized
|
||||
) : MvRxState {
|
||||
constructor(args: SpaceManageArgs) : this(
|
||||
spaceId = args.spaceId
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.spaces.manage
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.epoxy.VisibilityState
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import im.vector.app.R
|
||||
|
@ -39,6 +40,7 @@ class SpaceManageRoomsController @Inject constructor(
|
|||
interface Listener {
|
||||
fun toggleSelection(childInfo: SpaceChildInfo)
|
||||
fun retry()
|
||||
fun loadAdditionalItemsIfNeeded()
|
||||
}
|
||||
|
||||
var listener: Listener? = null
|
||||
|
@ -60,7 +62,7 @@ class SpaceManageRoomsController @Inject constructor(
|
|||
return
|
||||
}
|
||||
|
||||
val roomList = roomListAsync?.invoke() ?: return
|
||||
val roomList = roomListAsync?.invoke()?.children ?: return
|
||||
|
||||
val directChildren = roomList.filter {
|
||||
it.parentRoomId == data.spaceId
|
||||
|
@ -88,5 +90,29 @@ class SpaceManageRoomsController @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
val nextToken = roomListAsync.invoke()?.nextToken
|
||||
if (nextToken != null) {
|
||||
// show loading item
|
||||
val paginationStatus = data.paginationStatus
|
||||
if (paginationStatus is Fail) {
|
||||
errorWithRetryItem {
|
||||
id("error_$nextToken")
|
||||
text(host.errorFormatter.toHumanReadable(paginationStatus.error))
|
||||
listener { host.listener?.retry() }
|
||||
}
|
||||
} else {
|
||||
loadingItem {
|
||||
id("pagination_$nextToken")
|
||||
showLoader(true)
|
||||
onVisibilityStateChanged { _, _, visibilityState ->
|
||||
// Do something with the new visibility state
|
||||
if (visibilityState == VisibilityState.VISIBLE) {
|
||||
// we can trigger a seamless load of additional items
|
||||
host.listener?.loadAdditionalItemsIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import androidx.appcompat.view.ActionMode
|
|||
import androidx.appcompat.view.ActionMode.Callback
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.transition.TransitionManager
|
||||
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -54,6 +55,7 @@ class SpaceManageRoomsFragment @Inject constructor(
|
|||
|
||||
private val viewModel by fragmentViewModel(SpaceManageRoomsViewModel::class)
|
||||
private val sharedViewModel: SpaceManageSharedViewModel by activityViewModel()
|
||||
private val epoxyVisibilityTracker = EpoxyVisibilityTracker()
|
||||
|
||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?) = FragmentSpaceAddRoomsBinding.inflate(inflater)
|
||||
|
||||
|
@ -69,6 +71,7 @@ class SpaceManageRoomsFragment @Inject constructor(
|
|||
views.createNewRoom.isVisible = false
|
||||
epoxyController.listener = this
|
||||
views.roomList.configureWith(epoxyController, hasFixedSize = true, dividerDrawable = R.drawable.divider_horizontal)
|
||||
epoxyVisibilityTracker.attach(views.roomList)
|
||||
|
||||
views.publicRoomsFilter.queryTextChanges()
|
||||
.debounce(200, TimeUnit.MILLISECONDS)
|
||||
|
@ -99,6 +102,7 @@ class SpaceManageRoomsFragment @Inject constructor(
|
|||
|
||||
override fun onDestroyView() {
|
||||
epoxyController.listener = null
|
||||
epoxyVisibilityTracker.detach(views.roomList)
|
||||
views.roomList.cleanup()
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
@ -136,6 +140,10 @@ class SpaceManageRoomsFragment @Inject constructor(
|
|||
viewModel.handle(SpaceManageRoomViewAction.RefreshFromServer)
|
||||
}
|
||||
|
||||
override fun loadAdditionalItemsIfNeeded() {
|
||||
viewModel.handle(SpaceManageRoomViewAction.LoadAdditionalItemsIfNeeded)
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
val inflater = mode?.menuInflater
|
||||
inflater?.inflate(R.menu.menu_manage_space, menu)
|
||||
|
@ -150,7 +158,7 @@ class SpaceManageRoomsFragment @Inject constructor(
|
|||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||
withState(viewModel) { state ->
|
||||
// check if we show mark as suggested or not
|
||||
val areAllSuggested = state.childrenInfo.invoke().orEmpty().filter { state.selectedRooms.contains(it.childRoomId) }
|
||||
val areAllSuggested = state.childrenInfo.invoke()?.children.orEmpty().filter { state.selectedRooms.contains(it.childRoomId) }
|
||||
.all { it.suggested == true }
|
||||
menu?.findItem(R.id.action_mark_as_suggested)?.isVisible = !areAllSuggested
|
||||
menu?.findItem(R.id.action_mark_as_not_suggested)?.isVisible = areAllSuggested
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.spaces.manage
|
|||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.ActivityViewModelContext
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
|
@ -39,6 +40,8 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
|
|||
private val session: Session
|
||||
) : VectorViewModel<SpaceManageRoomViewState, SpaceManageRoomViewAction, SpaceManageRoomViewEvents>(initialState) {
|
||||
|
||||
private val paginationLimit = 10
|
||||
|
||||
init {
|
||||
val spaceSummary = session.getRoomSummary(initialState.spaceId)
|
||||
setState {
|
||||
|
@ -49,14 +52,7 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
|
|||
}
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val apiResult = runCatchingToAsync {
|
||||
session.spaceService().querySpaceChildren(spaceId = initialState.spaceId).children
|
||||
}
|
||||
setState {
|
||||
copy(
|
||||
childrenInfo = apiResult
|
||||
)
|
||||
}
|
||||
refreshSummaryAPI()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,6 +89,9 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
|
|||
SpaceManageRoomViewAction.RefreshFromServer -> {
|
||||
refreshSummaryAPI()
|
||||
}
|
||||
SpaceManageRoomViewAction.LoadAdditionalItemsIfNeeded -> {
|
||||
paginateIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,7 +119,7 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
|
|||
|
||||
private fun handleBulkMarkAsSuggested(suggested: Boolean) = withState { state ->
|
||||
setState { copy(actionState = Loading()) }
|
||||
val selection = state.childrenInfo.invoke()?.filter {
|
||||
val selection = state.childrenInfo.invoke()?.children?.filter {
|
||||
state.selectedRooms.contains(it.childRoomId)
|
||||
}.orEmpty()
|
||||
session.coroutineScope.launch(Dispatchers.IO) {
|
||||
|
@ -156,16 +155,67 @@ class SpaceManageRoomsViewModel @AssistedInject constructor(
|
|||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val apiResult = runCatchingToAsync {
|
||||
session.spaceService().querySpaceChildren(spaceId = initialState.spaceId).children
|
||||
session.spaceService().querySpaceChildren(
|
||||
spaceId = initialState.spaceId,
|
||||
limit = paginationLimit
|
||||
)
|
||||
}
|
||||
setState {
|
||||
copy(
|
||||
childrenInfo = apiResult
|
||||
childrenInfo = apiResult,
|
||||
paginationStatus = Uninitialized
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun paginateIfNeeded() = withState { state ->
|
||||
if (state.paginationStatus is Loading) return@withState
|
||||
val knownResults = state.childrenInfo.invoke()
|
||||
val nextToken = knownResults?.nextToken
|
||||
if (knownResults == null || nextToken == null) {
|
||||
setState {
|
||||
copy(
|
||||
paginationStatus = Uninitialized
|
||||
)
|
||||
}
|
||||
return@withState
|
||||
}
|
||||
setState {
|
||||
copy(
|
||||
paginationStatus = Loading()
|
||||
)
|
||||
}
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val apiResult = session.spaceService().querySpaceChildren(
|
||||
spaceId = initialState.spaceId,
|
||||
from = nextToken,
|
||||
knownStateList = knownResults.childrenState.orEmpty(),
|
||||
limit = paginationLimit
|
||||
)
|
||||
setState {
|
||||
copy(
|
||||
childrenInfo = Success(
|
||||
knownResults.copy(
|
||||
children = knownResults.children + apiResult.children,
|
||||
nextToken = apiResult.nextToken
|
||||
)
|
||||
),
|
||||
paginationStatus = Success(Unit)
|
||||
)
|
||||
}
|
||||
} catch (failure: Throwable) {
|
||||
setState {
|
||||
copy(
|
||||
paginationStatus = Fail(failure)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleToggleSelection(action: SpaceManageRoomViewAction.ToggleSelection) = withState { state ->
|
||||
val existing = state.selectedRooms.toMutableList()
|
||||
if (existing.contains(action.roomId)) {
|
||||
|
|
Loading…
Reference in a new issue