mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
Room List Filters Empty State View (#2522)
This commit is contained in:
parent
1b5db6c63d
commit
8c68f5a591
@ -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 */,
|
||||
|
@ -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 won’t 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 don’t 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 don’t have chats for this selection";
|
||||
"screen_roomlist_filter_people_empty_state_title" = "You don’t have any DMs yet";
|
||||
"screen_roomlist_filter_rooms" = "Rooms";
|
||||
"screen_roomlist_filter_rooms_empty_state_title" = "You’re not in any room yet";
|
||||
"screen_roomlist_filter_unreads" = "Unreads";
|
||||
"screen_roomlist_filter_unreads_empty_state_title" = "Congrats!\nYou don’t 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";
|
||||
|
@ -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 won’t 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 don’t 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 don’t 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 don’t 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") }
|
||||
/// You’re 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 don’t 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
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
BIN
PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_roomListFiltersEmptyStateView.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
1
changelog.d/2522.wip
Normal file
1
changelog.d/2522.wip
Normal file
@ -0,0 +1 @@
|
||||
Added an empty state view when the filter returns no rooms.
|
Loading…
x
Reference in New Issue
Block a user