-
Notifications
You must be signed in to change notification settings - Fork 912
empty state for new invites screen #6986
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| [App Layout] - Invites now show empty screen after you reject last invite |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<InvitesViewState, InvitesAction, InvitesViewEvents>(initialState) { | ||
|
|
||
| private val pagedListConfig = PagedList.Config.Builder() | ||
|
|
@@ -52,6 +65,11 @@ class InvitesViewModel @AssistedInject constructor( | |
|
|
||
| companion object : MavericksViewModelFactory<InvitesViewModel, InvitesViewState> by hiltMavericksViewModelFactory() | ||
|
|
||
| private val _invites = MutableSharedFlow<InvitesContentState>(replay = 1) | ||
| val invites = _invites.asSharedFlow() | ||
|
|
||
| private var invitesCount = -1 | ||
|
|
||
| init { | ||
| observeInvites() | ||
| } | ||
|
|
@@ -72,18 +90,13 @@ class InvitesViewModel @AssistedInject constructor( | |
| return@withState | ||
| } | ||
|
|
||
| val shouldCloseInviteView = state.pagedList?.value?.size == 1 | ||
|
|
||
| viewModelScope.launch { | ||
| try { | ||
| session.roomService().leaveRoom(roomId) | ||
| // We do not update the rejectingRoomsIds here, because, the room is not rejected yet regarding the sync data. | ||
| // 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will work since we will test only if this is equal to 1, but I think it's more correct to use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. from my understanding, the exact count is returned by |
||
| InvitesContentState.Content(it) | ||
| } | ||
| } | ||
| .catch { | ||
| emit(InvitesContentState.Error(it)) | ||
| } | ||
| .onStart { | ||
| emit(InvitesContentState.Loading) | ||
| }.onEach { | ||
| _invites.emit(it) | ||
| }.launchIn(viewModelScope) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="60dp" | ||
| android:height="60dp" | ||
| android:viewportWidth="60" | ||
| android:viewportHeight="60"> | ||
| <path | ||
| android:pathData="M30,30m-30,0a30,30 0,1 1,60 0a30,30 0,1 1,-60 0" | ||
| android:fillColor="#E3E8F0"/> | ||
| <path | ||
| android:pathData="M25.665,33.544L15.229,23.209L29.236,13.398C29.993,12.868 31.007,12.868 31.764,13.398L45.771,23.209L35.247,33.631L33.851,32.446C31.93,30.816 29.11,30.778 27.145,32.355L25.665,33.544ZM22.439,36.134L14,42.91V27.777L22.439,36.134ZM47,27.777V43.606L38.393,36.301L47,27.777ZM31.177,35.566L43.47,46H16.714L29.733,35.546C30.156,35.208 30.765,35.216 31.177,35.566Z" | ||
| android:strokeWidth="2" | ||
| android:fillColor="#737D8C" | ||
| android:strokeColor="#737D8C"/> | ||
| </vector> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,17 +20,24 @@ | |
|
|
||
| </com.google.android.material.appbar.AppBarLayout> | ||
|
|
||
| <androidx.recyclerview.widget.RecyclerView | ||
| android:id="@+id/invites_recycler" | ||
| <im.vector.app.core.platform.StateView | ||
| android:id="@+id/invites_state_view" | ||
| android:layout_width="0dp" | ||
| android:layout_height="0dp" | ||
| android:fastScrollEnabled="true" | ||
| android:overScrollMode="always" | ||
| android:scrollbars="vertical" | ||
| app:layout_behavior="@string/appbar_scrolling_view_behavior" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To double check, is it OK to remove this layout_behavior?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, we don't need it for state view |
||
| app:layout_constraintBottom_toBottomOf="parent" | ||
| app:layout_constraintEnd_toEndOf="parent" | ||
| app:layout_constraintStart_toStartOf="parent" | ||
| app:layout_constraintTop_toBottomOf="@id/appBarLayout" /> | ||
| app:layout_constraintTop_toBottomOf="@id/appBarLayout"> | ||
|
|
||
| <androidx.recyclerview.widget.RecyclerView | ||
| android:id="@+id/invites_recycler" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" | ||
| android:fastScrollEnabled="true" | ||
| android:overScrollMode="always" | ||
| android:scrollbars="vertical" /> | ||
|
|
||
| </im.vector.app.core.platform.StateView> | ||
|
|
||
|
|
||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
out of interest, is an empty result only returned after the
pagedListhas finished loading?or is it possible for it to emit an empty state instantly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
up to my tests it emits empty list only when there are no invites