diff --git a/changelog.d/6876.feature b/changelog.d/6876.feature
new file mode 100644
index 0000000000..12a2b78a1e
--- /dev/null
+++ b/changelog.d/6876.feature
@@ -0,0 +1 @@
+[App Layout] - Invites now show empty screen after you reject last invite
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index 6e11682e77..8c2af01e52 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -451,6 +451,9 @@
Invites
+ Nothing new.
+ This is where your new requests and invites will be.
+
Conversations
Matrix contacts only
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
index 74b46cec33..f557483289 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
@@ -20,15 +20,18 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.fragmentViewModel
-import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.configureWith
+import im.vector.app.core.platform.StateView
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentInvitesBinding
import im.vector.app.features.analytics.plan.ViewRoom
import im.vector.app.features.home.room.list.RoomListListener
import im.vector.app.features.notifications.NotificationDrawerManager
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
import javax.inject.Inject
@@ -51,6 +54,8 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi
setupToolbar(views.invitesToolbar)
.allowBack()
+ views.invitesStateView.contentView = views.invitesRecycler
+
views.invitesRecycler.configureWith(controller)
controller.listener = this
@@ -62,13 +67,31 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi
when (it) {
is InvitesViewEvents.Failure -> showFailure(it.throwable)
is InvitesViewEvents.OpenRoom -> handleOpenRoom(it.roomSummary, it.shouldCloseInviteView)
- InvitesViewEvents.Close -> handleClose()
}
}
- }
- private fun handleClose() {
- requireActivity().finish()
+ viewModel.invites.onEach {
+ when (it) {
+ is InvitesContentState.Content -> {
+ views.invitesStateView.state = StateView.State.Content
+ controller.submitList(it.content)
+ }
+ is InvitesContentState.Empty -> {
+ views.invitesStateView.state = StateView.State.Empty(
+ title = it.title,
+ image = it.image,
+ message = it.message
+ )
+ }
+ is InvitesContentState.Error -> {
+ when (views.invitesStateView.state) {
+ StateView.State.Content -> showErrorInSnackbar(it.throwable)
+ else -> views.invitesStateView.state = StateView.State.Error(it.throwable.message)
+ }
+ }
+ InvitesContentState.Loading -> views.invitesStateView.state = StateView.State.Loading
+ }
+ }.launchIn(viewLifecycleOwner.lifecycleScope)
}
private fun handleOpenRoom(roomSummary: RoomSummary, shouldCloseInviteView: Boolean) {
@@ -83,14 +106,6 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi
}
}
- override fun invalidate(): Unit = withState(viewModel) { state ->
- super.invalidate()
-
- state.pagedList?.observe(viewLifecycleOwner) { list ->
- controller.submitList(list)
- }
- }
-
override fun onRejectRoomInvitation(room: RoomSummary) {
notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) }
viewModel.handle(InvitesAction.RejectInvitation(room))
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
index d68577cf95..21310592a4 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
@@ -22,5 +22,4 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
sealed class InvitesViewEvents : VectorViewEvents {
data class Failure(val throwable: Throwable) : InvitesViewEvents()
data class OpenRoom(val roomSummary: RoomSummary, val shouldCloseInviteView: Boolean) : InvitesViewEvents()
- object Close : InvitesViewEvents()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
index b0d854be66..b8034d2364 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
@@ -16,14 +16,25 @@
package im.vector.app.features.home.room.list.home.invites
+import androidx.lifecycle.asFlow
import androidx.paging.PagedList
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import im.vector.app.R
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.core.resources.DrawableProvider
+import im.vector.app.core.resources.StringProvider
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session
@@ -36,6 +47,8 @@ import timber.log.Timber
class InvitesViewModel @AssistedInject constructor(
@Assisted val initialState: InvitesViewState,
private val session: Session,
+ private val stringProvider: StringProvider,
+ private val drawableProvider: DrawableProvider
) : VectorViewModel(initialState) {
private val pagedListConfig = PagedList.Config.Builder()
@@ -52,6 +65,11 @@ class InvitesViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
+ private val _invites = MutableSharedFlow(replay = 1)
+ val invites = _invites.asSharedFlow()
+
+ private var invitesCount = -1
+
init {
observeInvites()
}
@@ -72,8 +90,6 @@ class InvitesViewModel @AssistedInject constructor(
return@withState
}
- val shouldCloseInviteView = state.pagedList?.value?.size == 1
-
viewModelScope.launch {
try {
session.roomService().leaveRoom(roomId)
@@ -81,9 +97,6 @@ class InvitesViewModel @AssistedInject constructor(
// Instead, we wait for the room to be rejected
// Known bug: if the user is invited again (after rejecting the first invitation), the loading will be displayed instead of the buttons.
// If we update the state, the button will be displayed again, so it's not ideal...
- if (shouldCloseInviteView) {
- _viewEvents.post(InvitesViewEvents.Close)
- }
} catch (failure: Throwable) {
// Notify the user
_viewEvents.post(InvitesViewEvents.Failure(failure))
@@ -101,9 +114,7 @@ class InvitesViewModel @AssistedInject constructor(
}
// close invites view when navigate to a room from the last one invite
- val shouldCloseInviteView = state.pagedList?.value?.size == 1
-
- _viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView))
+ val shouldCloseInviteView = invitesCount == 1
// quick echo
setState {
@@ -117,6 +128,8 @@ class InvitesViewModel @AssistedInject constructor(
}
)
}
+
+ _viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView))
}
private fun observeInvites() {
@@ -129,8 +142,26 @@ class InvitesViewModel @AssistedInject constructor(
sortOrder = RoomSortOrder.ACTIVITY
)
- setState {
- copy(pagedList = pagedList)
- }
+ pagedList.asFlow()
+ .map {
+ if (it.isEmpty()) {
+ InvitesContentState.Empty(
+ title = stringProvider.getString(R.string.invites_empty_title),
+ image = drawableProvider.getDrawable(R.drawable.ic_invites_empty),
+ message = stringProvider.getString(R.string.invites_empty_message)
+ )
+ } else {
+ invitesCount = it.loadedCount
+ InvitesContentState.Content(it)
+ }
+ }
+ .catch {
+ emit(InvitesContentState.Error(it))
+ }
+ .onStart {
+ emit(InvitesContentState.Loading)
+ }.onEach {
+ _invites.emit(it)
+ }.launchIn(viewModelScope)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
index 708db29604..2f82c3fe76 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
@@ -16,13 +16,24 @@
package im.vector.app.features.home.room.list.home.invites
-import androidx.lifecycle.LiveData
+import android.graphics.drawable.Drawable
import androidx.paging.PagedList
import com.airbnb.mvrx.MavericksState
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomSummary
data class InvitesViewState(
- val pagedList: LiveData>? = null,
val roomMembershipChanges: Map = emptyMap(),
) : MavericksState
+
+sealed interface InvitesContentState {
+ object Loading : InvitesContentState
+ data class Empty(
+ val title: CharSequence,
+ val image: Drawable?,
+ val message: CharSequence
+ ) : InvitesContentState
+
+ data class Content(val content: PagedList) : InvitesContentState
+ data class Error(val throwable: Throwable) : InvitesContentState
+}
diff --git a/vector/src/main/res/drawable/ic_invites_empty.xml b/vector/src/main/res/drawable/ic_invites_empty.xml
new file mode 100644
index 0000000000..79908ff380
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_invites_empty.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/vector/src/main/res/layout/fragment_invites.xml b/vector/src/main/res/layout/fragment_invites.xml
index 74226357c9..070cad5ec8 100644
--- a/vector/src/main/res/layout/fragment_invites.xml
+++ b/vector/src/main/res/layout/fragment_invites.xml
@@ -20,17 +20,24 @@
-
+ app:layout_constraintTop_toBottomOf="@id/appBarLayout">
+
+
+
+
+