From 50034599628a320ca7ea32ef5f6a4a31ebf515e1 Mon Sep 17 00:00:00 2001 From: NIkita Fedrunov Date: Thu, 1 Sep 2022 14:39:13 +0200 Subject: [PATCH 01/57] empty state for new invites screen --- changelog.d/6876.feature | 1 + .../room/list/home/invites/InvitesFragment.kt | 43 ++++++++++----- .../list/home/invites/InvitesViewEvents.kt | 1 - .../list/home/invites/InvitesViewModel.kt | 53 +++++++++++++++---- .../list/home/invites/InvitesViewState.kt | 15 +++++- .../main/res/drawable/ic_invites_empty.xml | 14 +++++ .../src/main/res/layout/fragment_invites.xml | 21 +++++--- vector/src/main/res/values/strings.xml | 3 ++ 8 files changed, 117 insertions(+), 34 deletions(-) create mode 100644 changelog.d/6876.feature create mode 100644 vector/src/main/res/drawable/ic_invites_empty.xml 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/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..7fbc6f5c3f 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,19 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.lifecycle.lifecycleScope +import androidx.paging.PagedList 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 +55,8 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi setupToolbar(views.invitesToolbar) .allowBack() + views.invitesStateView.contentView = views.invitesRecycler + views.invitesRecycler.configureWith(controller) controller.listener = this @@ -62,13 +68,32 @@ 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 + Suppress("UNCHECKED_CAST") + controller.submitList(it.content as? PagedList) + } + 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 +108,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..1e5880d772 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() + + 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..397042a96a 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 class 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"> + + + + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index f8eb4b8de0..178feb2223 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -445,6 +445,9 @@ Invites + Nothing new. + This is where your new requests and invites will be. + Conversations Matrix contacts only From da7355049310179dc18dc982c429dd2105e68a33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 23:10:39 +0000 Subject: [PATCH 02/57] Bump android-embedded_fcm_distributor from 2.1.2 to 2.1.3 Bumps android-embedded_fcm_distributor from 2.1.2 to 2.1.3. --- updated-dependencies: - dependency-name: com.github.UnifiedPush:android-embedded_fcm_distributor dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- vector/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/build.gradle b/vector/build.gradle index ee549fc4b6..51ee8b561c 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -264,7 +264,7 @@ dependencies { // UnifiedPush implementation 'com.github.UnifiedPush:android-connector:2.0.1' // UnifiedPush gplay flavor only - gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.2') { + gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.3') { exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' From ad360074bf523abd9b9017a2ab8c1c1ee87384ae Mon Sep 17 00:00:00 2001 From: Germain Date: Fri, 2 Sep 2022 15:54:08 +0100 Subject: [PATCH 03/57] Remove threads board automation The threads board has been closed and is now replaced by the Delight board --- .github/workflows/triage-labelled.yml | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/.github/workflows/triage-labelled.yml b/.github/workflows/triage-labelled.yml index f478d2bd7b..174e3c54c0 100644 --- a/.github/workflows/triage-labelled.yml +++ b/.github/workflows/triage-labelled.yml @@ -142,32 +142,6 @@ jobs: env: PROJECT_ID: "PN_kwDOAM0swc2KCw" GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} - - move_threads_issues: - name: A-Threads to Thread board - runs-on: ubuntu-latest - # Skip in forks - if: > - github.repository == 'vector-im/element-android' && - contains(github.event.issue.labels.*.name, 'A-Threads') - steps: - - uses: octokit/graphql-action@v2.x - with: - headers: '{"GraphQL-Features": "projects_next_graphql"}' - query: | - mutation add_to_project($projectid:ID!,$contentid:ID!) { - addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { - projectNextItem { - id - } - } - } - projectid: ${{ env.PROJECT_ID }} - contentid: ${{ github.event.issue.node_id }} - env: - PROJECT_ID: "PN_kwDOAM0swc0rRA" - GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} - move_message_bubbles_issues: name: A-Message-Bubbles to Message bubbles board runs-on: ubuntu-latest From 0f4deb70670a0417d5039a567ed27161f2ab16bb Mon Sep 17 00:00:00 2001 From: bmarty Date: Mon, 5 Sep 2022 00:03:36 +0000 Subject: [PATCH 04/57] Sync analytics plan --- .../features/analytics/plan/Interaction.kt | 51 +++++++++++++++++++ .../features/analytics/plan/MobileScreen.kt | 15 ++++++ .../features/analytics/plan/UserProperties.kt | 28 ++++++++++ .../app/features/analytics/plan/ViewRoom.kt | 5 ++ 4 files changed, 99 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt index 6336faa74c..1df1b35439 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Interaction.kt @@ -40,6 +40,46 @@ data class Interaction( ) : VectorAnalyticsEvent { enum class Name { + /** + * User tapped the All filter in the All Chats filter tab. + */ + MobileAllChatsFilterAll, + + /** + * User tapped the Favourites filter in the All Chats filter tab. + */ + MobileAllChatsFilterFavourites, + + /** + * User tapped the People filter in the All Chats filter tab. + */ + MobileAllChatsFilterPeople, + + /** + * User tapped the Unreads filter in the All Chats filter tab. + */ + MobileAllChatsFilterUnreads, + + /** + * User disabled filters from the all chats layout settings. + */ + MobileAllChatsFiltersDisabled, + + /** + * User enabled filters from the all chats layout settings. + */ + MobileAllChatsFiltersEnabled, + + /** + * User disabled recents from the all chats layout settings. + */ + MobileAllChatsRecentsDisabled, + + /** + * User enabled recents from the all chats layout settings. + */ + MobileAllChatsRecentsEnabled, + /** * User tapped on Add to Home button on Room Details screen. */ @@ -60,6 +100,11 @@ data class Interaction( */ MobileRoomThreadSummaryItem, + /** + * User validated the creation of a new space. + */ + MobileSpaceCreationValidated, + /** * User tapped on the filter button on ThreadList screen. */ @@ -81,6 +126,12 @@ data class Interaction( */ SpacePanelSwitchSpace, + /** + * User tapped an unselected sub space from the space list -> space + * switching should occur. + */ + SpacePanelSwitchSubSpace, + /** * User clicked the create room button in the add existing room to space * dialog in Element Web/Desktop. diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt index 3ce3dfb578..7ea41e2d78 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/MobileScreen.kt @@ -43,6 +43,11 @@ data class MobileScreen( */ CreateRoom, + /** + * The screen shown to create a new space. + */ + CreateSpace, + /** * The confirmation screen shown before deactivating an account. */ @@ -78,6 +83,11 @@ data class MobileScreen( */ InviteFriends, + /** + * Room accessed via space bottom sheet list. + */ + Invites, + /** * The screen that displays the login flow (when the user already has an * account). @@ -261,6 +271,11 @@ data class MobileScreen( */ Sidebar, + /** + * Room accessed via space bottom sheet list. + */ + SpaceBottomSheet, + /** * Screen that displays the list of rooms and spaces of a space. */ diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt index 77be2456cd..d6fa918b8e 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/UserProperties.kt @@ -44,6 +44,10 @@ data class UserProperties( * Whether the user has the people space enabled. */ val webMetaSpacePeopleEnabled: Boolean? = null, + /** + * The active filter in the All Chats screen + */ + val allChatsActiveFilter: AllChatsActiveFilter? = null, /** * The selected messaging use case during the onboarding flow. */ @@ -80,6 +84,29 @@ data class UserProperties( WorkMessaging, } + enum class AllChatsActiveFilter { + + /** + * Filters are activated and All is selected + */ + All, + + /** + * Filters are activated and Favourites is selected + */ + Favourites, + + /** + * Filters are activated and People is selected + */ + People, + + /** + * Filters are activated and Unreads is selected + */ + Unreads, + } + fun getProperties(): Map? { return mutableMapOf().apply { webMetaSpaceFavouritesEnabled?.let { put("WebMetaSpaceFavouritesEnabled", it) } @@ -87,6 +114,7 @@ data class UserProperties( webMetaSpaceHomeEnabled?.let { put("WebMetaSpaceHomeEnabled", it) } webMetaSpaceOrphansEnabled?.let { put("WebMetaSpaceOrphansEnabled", it) } webMetaSpacePeopleEnabled?.let { put("WebMetaSpacePeopleEnabled", it) } + allChatsActiveFilter?.let { put("allChatsActiveFilter", it.name) } ftueUseCaseSelection?.let { put("ftueUseCaseSelection", it.name) } numFavouriteRooms?.let { put("numFavouriteRooms", it) } numSpaces?.let { put("numSpaces", it) } diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt index f6a724304b..366979025a 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/ViewRoom.kt @@ -110,6 +110,11 @@ data class ViewRoom( */ MobileSearchContactDetail, + /** + * Room accessed via space bottom sheet list. + */ + MobileSpaceBottomSheet, + /** * Room accessed via interacting with direct chat item in the space * contact detail screen. From b37996e4c3a054f6faf6dea37869040873ebf150 Mon Sep 17 00:00:00 2001 From: Nikita Fedrunov <66663241+fedrunov@users.noreply.github.com> Date: Mon, 5 Sep 2022 16:11:50 +0200 Subject: [PATCH 05/57] space switcher empty spaces (#6988) --- changelog.d/6754.bugfix | 1 + .../src/main/res/values/strings.xml | 4 ++ .../app/features/spaces/SpaceListFragment.kt | 16 ++++++- .../main/res/layout/fragment_space_list.xml | 44 +++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 changelog.d/6754.bugfix diff --git a/changelog.d/6754.bugfix b/changelog.d/6754.bugfix new file mode 100644 index 0000000000..e9f6960595 --- /dev/null +++ b/changelog.d/6754.bugfix @@ -0,0 +1 @@ +[App Layout] - space switcher now has empty state diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index df0e10627a..6b44377b79 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -442,6 +442,10 @@ "System Alerts" Suggested Rooms + + No spaces yet. + Spaces are a new way to group rooms and people. Create a space to get started. + Invites diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index ca9279cb37..0153d64df7 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -21,6 +21,7 @@ import android.view.HapticFeedbackConstants import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import com.airbnb.epoxy.EpoxyTouchHelper import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success @@ -28,6 +29,7 @@ import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.epoxy.onClick import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.StateView @@ -71,6 +73,7 @@ class SpaceListFragment : homeActivitySharedActionViewModel = activityViewModelProvider[HomeSharedActionViewModel::class.java] roomListSharedActionViewModel = activityViewModelProvider[RoomListSharedActionViewModel::class.java] views.stateView.contentView = views.groupListView + views.spacesEmptyButton.onClick { onAddSpaceSelected() } setupSpaceController() observeViewEvents() } @@ -147,13 +150,22 @@ class SpaceListFragment : } override fun invalidate() = withState(viewModel) { state -> - when (state.asyncSpaces) { + when (val spaces = state.asyncSpaces) { Uninitialized, is Loading -> { views.stateView.state = StateView.State.Loading return@withState } - is Success -> views.stateView.state = StateView.State.Content + is Success -> { + views.stateView.state = StateView.State.Content + if (spaces.invoke().isEmpty()) { + views.spacesEmptyGroup.isVisible = true + views.groupListView.isVisible = false + } else { + views.spacesEmptyGroup.isVisible = false + views.groupListView.isVisible = true + } + } else -> Unit } diff --git a/vector/src/main/res/layout/fragment_space_list.xml b/vector/src/main/res/layout/fragment_space_list.xml index d54ffa7155..8dfbb4a9c6 100644 --- a/vector/src/main/res/layout/fragment_space_list.xml +++ b/vector/src/main/res/layout/fragment_space_list.xml @@ -12,4 +12,48 @@ android:overScrollMode="always" tools:listitem="@layout/item_space" /> + + + + + + + +