Room List Filters Empty State View (#2522)

This commit is contained in:
Mauro 2024-03-05 15:15:07 +01:00 committed by GitHub
parent 1b5db6c63d
commit 8c68f5a591
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 141 additions and 1 deletions

View File

@ -772,6 +772,7 @@
BB784A02BADB03C820617A46 /* TextRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A55430639712CFACA34F43 /* TextRoomTimelineItem.swift */; };
BB9B800C6094E34860E89DC5 /* AppLockSetupBiometricsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8CCF9A924521DECA44778C4 /* AppLockSetupBiometricsScreen.swift */; };
BCC864190651B3A3CF51E4DF /* MediaFileHandleProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC1D382565A4E9CAC2F14EA /* MediaFileHandleProxy.swift */; };
BD0BE20DBCE31253AE4490A1 /* RoomListFiltersEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1DDB2293A51EA4C2739351 /* RoomListFiltersEmptyStateView.swift */; };
BD203FC6A7AE7637EA003643 /* RoomProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ABDE6F66532CBEB0E016F94 /* RoomProxyMock.swift */; };
BD2BF1EC73FFB0C01552ECDA /* WelcomeScreenScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB782CE6176A5D2C082EC5D /* WelcomeScreenScreenModels.swift */; };
BD6D98676111DA8FC2BE4908 /* InvitesScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86873A768B13069BB5CAECF6 /* InvitesScreenViewModelProtocol.swift */; };
@ -1877,6 +1878,7 @@
CBF9AEA706926DD0DA2B954C /* JoinedRoomSize+MemberCount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JoinedRoomSize+MemberCount.swift"; sourceTree = "<group>"; };
CC03209FDE8CE0810617BFFF /* RoomMembersListScreenMemberCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenMemberCell.swift; sourceTree = "<group>"; };
CC14E5209C262530E19BC4C1 /* InvitesScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitesScreenViewModelTests.swift; sourceTree = "<group>"; };
CC1DDB2293A51EA4C2739351 /* RoomListFiltersEmptyStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomListFiltersEmptyStateView.swift; sourceTree = "<group>"; };
CC680E0E79D818706CB28CF8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
CC743C7A85E3171BCBF0A653 /* AvatarHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarHeaderView.swift; sourceTree = "<group>"; };
CCACD75595C40EACD6AD4A74 /* AuthenticationTextFieldStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationTextFieldStyle.swift; sourceTree = "<group>"; };
@ -2207,6 +2209,7 @@
isa = PBXGroup;
children = (
E06AAD6D9D3F5833E7A5A2F9 /* RoomListFilterModels.swift */,
CC1DDB2293A51EA4C2739351 /* RoomListFiltersEmptyStateView.swift */,
E6372DD10DED30E7AD7BCE21 /* RoomListFiltersView.swift */,
24EC819497BB5F8C4998D760 /* RoomListFilterView.swift */,
);
@ -6013,6 +6016,7 @@
04A16B45228F7678A027C079 /* RoomHeaderView.swift in Sources */,
F4996C82A4B3A5FF0C8EDD03 /* RoomListFilterModels.swift in Sources */,
4A9CEEE612D6D8B3DDBD28BA /* RoomListFilterView.swift in Sources */,
BD0BE20DBCE31253AE4490A1 /* RoomListFiltersEmptyStateView.swift in Sources */,
33F1FB19F222BA9930AB1A00 /* RoomListFiltersView.swift in Sources */,
8DC176CC5ABA24138EB443DD /* RoomMemberDetails.swift in Sources */,
19FE025AE9BA2959B6589B0D /* RoomMemberDetailsScreen.swift in Sources */,

View File

@ -48,6 +48,7 @@
"action_enter_pin" = "Enter PIN";
"action_forgot_password" = "Forgot password?";
"action_forward" = "Forward";
"action_go_back" = "Go back";
"action_invite" = "Invite";
"action_invite_friends" = "Invite people";
"action_invite_friends_to_app" = "Invite people to %1$@";
@ -162,6 +163,7 @@
"common_room" = "Room";
"common_room_name" = "Room name";
"common_room_name_placeholder" = "e.g. your project name";
"common_saved_changes" = "Saved changes";
"common_saving" = "Saving";
"common_screen_lock" = "Screen lock";
"common_search_for_someone" = "Search for someone";
@ -217,6 +219,8 @@
"dialog_permission_notification" = "In order to let the application display notifications, please grant the permission in the system settings.";
"dialog_title_confirmation" = "Confirmation";
"dialog_title_warning" = "Warning";
"dialog_unsaved_changes_description_ios" = "Your changes wont be saved";
"dialog_unsaved_changes_title" = "Save changes?";
"emoji_picker_category_activity" = "Activities";
"emoji_picker_category_flags" = "Flags";
"emoji_picker_category_foods" = "Food & Drink";
@ -510,6 +514,8 @@
"screen_room_change_role_confirm_demote_self_description" = "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.";
"screen_room_change_role_confirm_demote_self_title" = "Demote yourself?";
"screen_room_change_role_moderators_title" = "Edit Moderators";
"screen_room_change_role_unsaved_changes_description" = "You have unsaved changes.";
"screen_room_change_role_unsaved_changes_title" = "Save changes?";
"screen_room_details_add_topic_title" = "Add topic";
"screen_room_details_already_a_member" = "Already a member";
"screen_room_details_already_invited" = "Already invited";
@ -577,6 +583,9 @@
"screen_room_retry_send_menu_send_again_action" = "Send again";
"screen_room_retry_send_menu_title" = "Your message failed to send";
"screen_room_roles_and_permissions_admins" = "Admins";
"screen_room_roles_and_permissions_change_my_role" = "Change my role";
"screen_room_roles_and_permissions_change_role_demote_to_member" = "Demote to member";
"screen_room_roles_and_permissions_change_role_demote_to_moderator" = "Demote to moderator";
"screen_room_roles_and_permissions_member_moderation" = "Member moderation";
"screen_room_roles_and_permissions_messages_and_content" = "Messages and content";
"screen_room_roles_and_permissions_moderators" = "Moderators";
@ -596,9 +605,16 @@
"screen_roomlist_empty_message" = "Get started by messaging someone.";
"screen_roomlist_empty_title" = "No chats yet.";
"screen_roomlist_filter_favourites" = "Favourites";
"screen_roomlist_filter_favourites_empty_state_subtitle" = "You can add a chat to your favourites in the chat settings.\nFor now, you can deselect filters in order to see your other chats";
"screen_roomlist_filter_favourites_empty_state_title" = "You dont have favourite chats yet";
"screen_roomlist_filter_low_priority" = "Low Priority";
"screen_roomlist_filter_mixed_empty_state_subtitle" = "You can deselect filters in order to see your other chats";
"screen_roomlist_filter_mixed_empty_state_title" = "You dont have chats for this selection";
"screen_roomlist_filter_people_empty_state_title" = "You dont have any DMs yet";
"screen_roomlist_filter_rooms" = "Rooms";
"screen_roomlist_filter_rooms_empty_state_title" = "Youre not in any room yet";
"screen_roomlist_filter_unreads" = "Unreads";
"screen_roomlist_filter_unreads_empty_state_title" = "Congrats!\nYou dont have any unread messages!";
"screen_roomlist_main_space_title" = "Chats";
"screen_roomlist_mark_as_read" = "Mark as read";
"screen_roomlist_mark_as_unread" = "Mark as unread";

View File

@ -126,6 +126,8 @@ internal enum L10n {
internal static var actionForgotPassword: String { return L10n.tr("Localizable", "action_forgot_password") }
/// Forward
internal static var actionForward: String { return L10n.tr("Localizable", "action_forward") }
/// Go back
internal static var actionGoBack: String { return L10n.tr("Localizable", "action_go_back") }
/// Invite
internal static var actionInvite: String { return L10n.tr("Localizable", "action_invite") }
/// Invite people
@ -378,6 +380,8 @@ internal enum L10n {
internal static var commonRoomName: String { return L10n.tr("Localizable", "common_room_name") }
/// e.g. your project name
internal static var commonRoomNamePlaceholder: String { return L10n.tr("Localizable", "common_room_name_placeholder") }
/// Saved changes
internal static var commonSavedChanges: String { return L10n.tr("Localizable", "common_saved_changes") }
/// Saving
internal static var commonSaving: String { return L10n.tr("Localizable", "common_saving") }
/// Screen lock
@ -494,6 +498,10 @@ internal enum L10n {
internal static var dialogTitleSuccess: String { return L10n.tr("Localizable", "dialog_title_success") }
/// Warning
internal static var dialogTitleWarning: String { return L10n.tr("Localizable", "dialog_title_warning") }
/// Your changes wont be saved
internal static var dialogUnsavedChangesDescriptionIos: String { return L10n.tr("Localizable", "dialog_unsaved_changes_description_ios") }
/// Save changes?
internal static var dialogUnsavedChangesTitle: String { return L10n.tr("Localizable", "dialog_unsaved_changes_title") }
/// Activities
internal static var emojiPickerCategoryActivity: String { return L10n.tr("Localizable", "emoji_picker_category_activity") }
/// Flags
@ -1251,6 +1259,10 @@ internal enum L10n {
internal static var screenRoomChangeRoleConfirmDemoteSelfTitle: String { return L10n.tr("Localizable", "screen_room_change_role_confirm_demote_self_title") }
/// Edit Moderators
internal static var screenRoomChangeRoleModeratorsTitle: String { return L10n.tr("Localizable", "screen_room_change_role_moderators_title") }
/// You have unsaved changes.
internal static var screenRoomChangeRoleUnsavedChangesDescription: String { return L10n.tr("Localizable", "screen_room_change_role_unsaved_changes_description") }
/// Save changes?
internal static var screenRoomChangeRoleUnsavedChangesTitle: String { return L10n.tr("Localizable", "screen_room_change_role_unsaved_changes_title") }
/// Add topic
internal static var screenRoomDetailsAddTopicTitle: String { return L10n.tr("Localizable", "screen_room_details_add_topic_title") }
/// Already a member
@ -1419,6 +1431,12 @@ internal enum L10n {
internal static var screenRoomRetrySendMenuTitle: String { return L10n.tr("Localizable", "screen_room_retry_send_menu_title") }
/// Admins
internal static var screenRoomRolesAndPermissionsAdmins: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_admins") }
/// Change my role
internal static var screenRoomRolesAndPermissionsChangeMyRole: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_change_my_role") }
/// Demote to member
internal static var screenRoomRolesAndPermissionsChangeRoleDemoteToMember: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_change_role_demote_to_member") }
/// Demote to moderator
internal static var screenRoomRolesAndPermissionsChangeRoleDemoteToModerator: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_change_role_demote_to_moderator") }
/// Member moderation
internal static var screenRoomRolesAndPermissionsMemberModeration: String { return L10n.tr("Localizable", "screen_room_roles_and_permissions_member_moderation") }
/// Messages and content
@ -1473,14 +1491,30 @@ internal enum L10n {
internal static var screenRoomlistEmptyTitle: String { return L10n.tr("Localizable", "screen_roomlist_empty_title") }
/// Favourites
internal static var screenRoomlistFilterFavourites: String { return L10n.tr("Localizable", "screen_roomlist_filter_favourites") }
/// You can add a chat to your favourites in the chat settings.
/// For now, you can deselect filters in order to see your other chats
internal static var screenRoomlistFilterFavouritesEmptyStateSubtitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_favourites_empty_state_subtitle") }
/// You dont have favourite chats yet
internal static var screenRoomlistFilterFavouritesEmptyStateTitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_favourites_empty_state_title") }
/// Low Priority
internal static var screenRoomlistFilterLowPriority: String { return L10n.tr("Localizable", "screen_roomlist_filter_low_priority") }
/// You can deselect filters in order to see your other chats
internal static var screenRoomlistFilterMixedEmptyStateSubtitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_mixed_empty_state_subtitle") }
/// You dont have chats for this selection
internal static var screenRoomlistFilterMixedEmptyStateTitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_mixed_empty_state_title") }
/// People
internal static var screenRoomlistFilterPeople: String { return L10n.tr("Localizable", "screen_roomlist_filter_people") }
/// You dont have any DMs yet
internal static var screenRoomlistFilterPeopleEmptyStateTitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_people_empty_state_title") }
/// Rooms
internal static var screenRoomlistFilterRooms: String { return L10n.tr("Localizable", "screen_roomlist_filter_rooms") }
/// Youre not in any room yet
internal static var screenRoomlistFilterRoomsEmptyStateTitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_rooms_empty_state_title") }
/// Unreads
internal static var screenRoomlistFilterUnreads: String { return L10n.tr("Localizable", "screen_roomlist_filter_unreads") }
/// Congrats!
/// You dont have any unread messages!
internal static var screenRoomlistFilterUnreadsEmptyStateTitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_unreads_empty_state_title") }
/// Chats
internal static var screenRoomlistMainSpaceTitle: String { return L10n.tr("Localizable", "screen_roomlist_main_space_title") }
/// Mark as read

View File

@ -118,6 +118,10 @@ struct HomeScreenViewState: BindableState {
var shouldHideRoomList: Bool {
bindings.isSearchFieldFocused && bindings.searchQuery.isEmpty
}
var shouldShowEmptyFilterState: Bool {
shouldShowFilters && bindings.filtersState.isFiltering && visibleRooms.isEmpty
}
}
struct HomeScreenViewStateBindings {

View File

@ -0,0 +1,71 @@
//
// Copyright 2024 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.
//
import SwiftUI
struct RoomListFiltersEmptyStateView: View {
let state: RoomListFiltersState
private var emptyStateTitle: String {
if state.activeFilters.count == 1 {
switch state.activeFilters[0] {
case .unreads:
return L10n.screenRoomlistFilterUnreadsEmptyStateTitle
case .people:
return L10n.screenRoomlistFilterPeopleEmptyStateTitle
case .rooms:
return L10n.screenRoomlistFilterRoomsEmptyStateTitle
case .favourites:
return L10n.screenRoomlistFilterFavouritesEmptyStateTitle
}
}
return L10n.screenRoomlistFilterMixedEmptyStateTitle
}
private var emptyStateSubtitle: String {
if state.activeFilters.first == .favourites {
return L10n.screenRoomlistFilterFavouritesEmptyStateSubtitle
}
return L10n.screenRoomlistFilterMixedEmptyStateSubtitle
}
var body: some View {
VStack(spacing: 24) {
Text(emptyStateTitle)
.multilineTextAlignment(.center)
.font(.compound.headingSMSemibold)
.foregroundColor(.compound.textPrimary)
Text(emptyStateSubtitle)
.multilineTextAlignment(.center)
.font(.compound.bodyMD)
.foregroundColor(.compound.textSecondary)
}
.padding(.horizontal, 60)
}
}
struct RoomListFiltersEmptyStateView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
VStack(spacing: 24) {
ForEach(RoomListFilter.allCases) { filter in
RoomListFiltersEmptyStateView(state: .init(activeFilters: [filter]))
}
RoomListFiltersEmptyStateView(state: .init(activeFilters: [.people, .favourites]))
}
.previewLayout(.sizeThatFits)
}
}

View File

@ -20,6 +20,7 @@ struct HomeScreenContent: View {
@Environment(\.verticalSizeClass) private var verticalSizeClass
@ObservedObject var context: HomeScreenViewModel.Context
@State private var topSectionFrame: CGRect = .zero
let scrollViewAdapter: ScrollViewAdapter
var body: some View {
@ -56,9 +57,15 @@ struct HomeScreenContent: View {
// Showing empty views in pinned headers makes the room list spasm when reaching the top
LazyVStack(spacing: 0, pinnedViews: [.sectionHeaders]) {
Section {
HomeScreenRoomList(context: context)
if context.viewState.shouldShowEmptyFilterState {
RoomListFiltersEmptyStateView(state: context.filtersState)
.frame(height: geometry.size.height - topSectionFrame.height)
} else {
HomeScreenRoomList(context: context)
}
} header: {
topSection
.readFrame($topSectionFrame)
}
}
.searchable(text: $context.searchQuery)

Binary file not shown.

1
changelog.d/2522.wip Normal file
View File

@ -0,0 +1 @@
Added an empty state view when the filter returns no rooms.