Add a Low Priority room filter behind a feature flag. (#4394)

* Add Low Priority room filter with incompatibility rules

Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com>

* Add a feature flag and use the SDK filters.

* Fix filter tests and add RoomSummaryProvider tests for the default filters.

* Remove unnecessary comment.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com>
Co-authored-by: Doug <douglase@element.io>
This commit is contained in:
Copilot
2025-08-20 11:56:44 +01:00
committed by GitHub
parent 5a7dbf8a50
commit 8c38c11146
21 changed files with 234 additions and 35 deletions
@@ -113,7 +113,7 @@ struct HomeScreenViewState: BindableState {
return rooms
}
var bindings = HomeScreenViewStateBindings()
var bindings: HomeScreenViewStateBindings
var placeholderRooms: [HomeScreenRoom] {
(1...10).map { _ in
@@ -136,7 +136,7 @@ struct HomeScreenViewState: BindableState {
}
struct HomeScreenViewStateBindings {
var filtersState = RoomListFiltersState()
var filtersState: RoomListFiltersState
var searchQuery = ""
var isSearchFieldFocused = false
@@ -40,7 +40,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
roomSummaryProvider = userSession.clientProxy.roomSummaryProvider
super.init(initialViewState: .init(userID: userSession.clientProxy.userID),
super.init(initialViewState: .init(userID: userSession.clientProxy.userID,
bindings: .init(filtersState: .init(appSettings: appSettings))),
mediaProvider: userSession.mediaProvider)
userSession.clientProxy.userAvatarURLPublisher
@@ -21,6 +21,7 @@ enum RoomListFilter: Int, CaseIterable, Identifiable {
case rooms
case favourites
case invites
case lowPriority
static var availableFilters: [RoomListFilter] {
RoomListFilter.allCases
@@ -38,6 +39,8 @@ enum RoomListFilter: Int, CaseIterable, Identifiable {
return L10n.screenRoomlistFilterFavourites
case .invites:
return L10n.screenRoomlistFilterInvites
case .lowPriority:
return L10n.screenRoomlistFilterLowPriority
}
}
@@ -50,10 +53,11 @@ enum RoomListFilter: Int, CaseIterable, Identifiable {
case .unreads:
return [.invites]
case .favourites:
// When we will have Low Priority we may need to return it here
return [.invites]
return [.invites, .lowPriority]
case .invites:
return [.rooms, .people, .unreads, .favourites]
return [.rooms, .people, .unreads, .favourites, .lowPriority]
case .lowPriority:
return [.favourites, .invites]
}
}
@@ -69,20 +73,29 @@ enum RoomListFilter: Int, CaseIterable, Identifiable {
return .all(filters: [.favourite, .joined])
case .invites:
return .invite
case .lowPriority:
// Note: When not activated, the setFilter method automatically applies the .nonLowPriority filter.
return .all(filters: [.lowPriority, .joined])
}
}
}
struct RoomListFiltersState {
private(set) var activeFilters: OrderedSet<RoomListFilter>
private let appSettings: AppSettings
init(activeFilters: OrderedSet<RoomListFilter> = []) {
init(activeFilters: OrderedSet<RoomListFilter> = [], appSettings: AppSettings) {
self.activeFilters = .init(activeFilters)
self.appSettings = appSettings
}
var availableFilters: [RoomListFilter] {
var availableFilters = OrderedSet(RoomListFilter.availableFilters)
if !appSettings.lowPriorityFilterEnabled {
availableFilters.remove(.lowPriority)
}
for filter in activeFilters {
availableFilters.remove(filter)
filter.incompatibleFilters.forEach { availableFilters.remove($0) }
@@ -19,13 +19,6 @@ struct RoomListFilterView: View {
}
}
struct RoomListFilterView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
RoomListFilterView(filter: .people, isActive: .constant(false))
RoomListFilterView(filter: .people, isActive: .constant(true))
}
}
private struct FilterToggleStyle: ToggleStyle {
private func strokeColor(isOn: Bool) -> Color {
isOn ? .compound.bgActionPrimaryRest : .compound.borderInteractiveSecondary
@@ -59,3 +52,12 @@ private struct FilterToggleStyle: ToggleStyle {
}
}
}
// MARK: - Previews
struct RoomListFilterView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
RoomListFilterView(filter: .people, isActive: .constant(false))
RoomListFilterView(filter: .people, isActive: .constant(true))
}
}
@@ -23,6 +23,8 @@ struct RoomListFiltersEmptyStateView: View {
return L10n.screenRoomlistFilterFavouritesEmptyStateTitle
case .invites:
return L10n.screenRoomlistFilterInvitesEmptyStateTitle
case .lowPriority:
return L10n.screenRoomlistFilterLowPriorityEmptyStateTitle
}
}
return L10n.screenRoomlistFilterMixedEmptyStateTitle
@@ -55,9 +57,11 @@ 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: [filter],
appSettings: ServiceLocator.shared.settings))
}
RoomListFiltersEmptyStateView(state: .init(activeFilters: [.people, .favourites]))
RoomListFiltersEmptyStateView(state: .init(activeFilters: [.people, .favourites],
appSettings: ServiceLocator.shared.settings))
}
.padding(.bottom)
.previewLayout(.sizeThatFits)
@@ -87,7 +87,10 @@ struct RoomListFiltersView: View {
struct RoomListFiltersView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
RoomListFiltersView(state: .constant(.init()))
RoomListFiltersView(state: .constant(.init(activeFilters: [.rooms, .favourites])))
RoomListFiltersView(state: .constant(.init(appSettings: ServiceLocator.shared.settings)))
RoomListFiltersView(state: .constant(.init(activeFilters: [.rooms, .favourites],
appSettings: ServiceLocator.shared.settings)))
RoomListFiltersView(state: .constant(.init(activeFilters: [.lowPriority],
appSettings: ServiceLocator.shared.settings)))
}
}