mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 20:09:04 +00:00
Room List Filters Empty State View (#2522)
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user