mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Room List Filters implementation (#2423)
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// 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 Combine
|
||||
import Foundation
|
||||
|
||||
import MatrixRustSDK
|
||||
|
||||
enum RoomListFilter: Int, CaseIterable, Identifiable {
|
||||
var id: Int {
|
||||
rawValue
|
||||
}
|
||||
|
||||
case people
|
||||
case rooms
|
||||
case unreads
|
||||
case favourites
|
||||
|
||||
var localizedName: String {
|
||||
switch self {
|
||||
case .people:
|
||||
return L10n.screenRoomlistFilterPeople
|
||||
case .rooms:
|
||||
return L10n.screenRoomlistFilterRooms
|
||||
case .unreads:
|
||||
return L10n.screenRoomlistFilterUnreads
|
||||
case .favourites:
|
||||
return L10n.screenRoomlistFilterFavourites
|
||||
}
|
||||
}
|
||||
|
||||
var incompatibleFilter: RoomListFilter? {
|
||||
switch self {
|
||||
case .people:
|
||||
return .rooms
|
||||
case .rooms:
|
||||
return .people
|
||||
case .unreads:
|
||||
return nil
|
||||
case .favourites:
|
||||
// When we will have Low Priority we may need to return it here
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var rustFilter: RoomListEntriesDynamicFilterKind? {
|
||||
switch self {
|
||||
case .people:
|
||||
return .category(expect: .people)
|
||||
case .rooms:
|
||||
return .category(expect: .group)
|
||||
case .unreads:
|
||||
return .unread
|
||||
case .favourites:
|
||||
// Not implemented yet
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class RoomListFiltersState: ObservableObject {
|
||||
@Published private(set) var activeFilters: Set<RoomListFilter>
|
||||
|
||||
init(activeFilters: Set<RoomListFilter> = []) {
|
||||
self.activeFilters = activeFilters
|
||||
}
|
||||
|
||||
var sortedActiveFilters: [RoomListFilter] {
|
||||
activeFilters.sorted(by: { $0.rawValue < $1.rawValue })
|
||||
}
|
||||
|
||||
var availableFilters: [RoomListFilter] {
|
||||
var availableFilters = Set(RoomListFilter.allCases)
|
||||
for filter in activeFilters {
|
||||
availableFilters.remove(filter)
|
||||
if let complementaryFilter = filter.incompatibleFilter {
|
||||
availableFilters.remove(complementaryFilter)
|
||||
}
|
||||
}
|
||||
return availableFilters.sorted(by: { $0.rawValue < $1.rawValue })
|
||||
}
|
||||
|
||||
var isFiltering: Bool {
|
||||
!activeFilters.isEmpty
|
||||
}
|
||||
|
||||
func activateFilter(_ filter: RoomListFilter) {
|
||||
if let incompatibleFilter = filter.incompatibleFilter,
|
||||
activeFilters.contains(incompatibleFilter) {
|
||||
fatalError("[RoomListFiltersState] adding mutually exclusive filters is not allowed")
|
||||
}
|
||||
activeFilters.insert(filter)
|
||||
}
|
||||
|
||||
func deactivateFilter(_ filter: RoomListFilter) {
|
||||
activeFilters.remove(filter)
|
||||
}
|
||||
|
||||
func clearFilters() {
|
||||
activeFilters.removeAll()
|
||||
}
|
||||
|
||||
func isFilterActive(_ filter: RoomListFilter) -> Bool {
|
||||
activeFilters.contains(filter)
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,9 @@ struct RoomListFilterView: View {
|
||||
|
||||
var body: some View {
|
||||
let binding = Binding<Bool>(get: {
|
||||
state.isEnabled(filter)
|
||||
state.isFilterActive(filter)
|
||||
}, set: { isEnabled, _ in
|
||||
state.set(filter, isEnabled: isEnabled)
|
||||
isEnabled ? state.activateFilter(filter) : state.deactivateFilter(filter)
|
||||
})
|
||||
Toggle(isOn: binding) {
|
||||
Text(filter.localizedName)
|
||||
@@ -36,7 +36,7 @@ struct RoomListFilterView: View {
|
||||
struct RoomListFilterView_Previews: PreviewProvider, TestablePreview {
|
||||
static var previews: some View {
|
||||
RoomListFilterView(filter: .people, state: .init())
|
||||
RoomListFilterView(filter: .people, state: .init(enabledFilters: [.people]))
|
||||
RoomListFilterView(filter: .people, state: .init(activeFilters: [.people]))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,10 +31,10 @@ struct RoomListFiltersView: View {
|
||||
.hidden()
|
||||
.frame(width: 0)
|
||||
}
|
||||
ForEach(state.sortedEnabledFilters) { filter in
|
||||
ForEach(state.sortedActiveFilters) { filter in
|
||||
RoomListFilterView(filter: filter, state: state)
|
||||
}
|
||||
ForEach(state.sortedAvailableFilters) { filter in
|
||||
ForEach(state.availableFilters) { filter in
|
||||
RoomListFilterView(filter: filter, state: state)
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,6 @@ struct RoomListFiltersView: View {
|
||||
struct RoomListFiltersView_Previews: PreviewProvider, TestablePreview {
|
||||
static var previews: some View {
|
||||
RoomListFiltersView(state: .init())
|
||||
RoomListFiltersView(state: .init(enabledFilters: [.rooms, .favourites]))
|
||||
RoomListFiltersView(state: .init(activeFilters: [.rooms, .favourites]))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user