Filter: Add multi-select picker and change picker style

The default SwiftUI picker is too limited for Ferrite's purposes.
Switch to a custom implementation for UI consistency.

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri 2023-04-23 14:13:57 -04:00
parent f7d2f1ce60
commit 5232ddfc97
8 changed files with 78 additions and 22 deletions

View file

@ -33,7 +33,7 @@ public class DebridManager: ObservableObject {
}
}
@Published var filteredIAStatus: [IAStatus] = []
@Published var filteredIAStatus: Set<IAStatus> = []
var currentDebridTask: Task<Void, Never>?
var downloadUrl: String = ""

View file

@ -16,7 +16,7 @@ public class PluginManager: ObservableObject {
@Published var availableSources: [SourceJson] = []
@Published var availableActions: [ActionJson] = []
@Published var filteredInstalledSources: [Source] = []
@Published var filteredInstalledSources: Set<Source> = []
@Published var showActionErrorAlert = false
@Published var actionErrorAlertMessage: String = ""
@ -270,7 +270,7 @@ public class PluginManager: ObservableObject {
let backgroundContext = PersistenceController.shared.backgroundContext
if !filteredInstalledSources.isEmpty && !searchResultsEmpty {
return filteredInstalledSources
return Array(filteredInstalledSources)
} else if let sources = try? backgroundContext.fetch(Source.fetchRequest()) {
return sources.compactMap { $0 }
} else {

View file

@ -10,7 +10,8 @@ import SwiftUI
struct FilterLabelView: View {
@Environment(\.colorScheme) var colorScheme
var name: String
var name: String?
var fallbackName: String
var count: Int?
var body: some View {
@ -19,7 +20,7 @@ struct FilterLabelView: View {
FilterAmountLabelView(amount: count)
}
Text(name)
Text(count == 1 ? name ?? fallbackName : fallbackName)
.opacity(count ?? 0 > 0 ? 1 : 0.6)
.foregroundColor(count ?? 0 > 0 && colorScheme == .light ? .accentColor : .primary)

View file

@ -14,16 +14,36 @@ struct IAFilterView: View {
var body: some View {
Menu {
Picker("", selection: $debridManager.filteredIAStatus) {
Text("All").tag([] as [IAStatus])
Button {
debridManager.filteredIAStatus = []
} label: {
Text("Any")
ForEach(IAStatus.allCases, id: \.self) { status in
Text(status.rawValue).tag([status])
if debridManager.filteredIAStatus.isEmpty {
Image(systemName: "checkmark")
}
}
ForEach(IAStatus.allCases, id: \.self) { status in
let containsIAStatus = debridManager.filteredIAStatus.contains(status)
Button {
if containsIAStatus {
debridManager.filteredIAStatus.remove(status)
} else {
debridManager.filteredIAStatus.insert(status)
}
} label: {
Text(status.rawValue)
if containsIAStatus {
Image(systemName: "checkmark")
}
}
}
} label: {
FilterLabelView(
name: debridManager.filteredIAStatus.first?.rawValue ?? "Cache Status",
name: debridManager.filteredIAStatus.first?.rawValue,
fallbackName: "Cache Status",
count: debridManager.filteredIAStatus.count
)
}

View file

@ -14,14 +14,26 @@ struct SelectedDebridFilterView<Content: View>: View {
var body: some View {
Menu {
Picker("", selection: $debridManager.selectedDebridType) {
Button {
debridManager.selectedDebridType = nil
} label: {
Text("None")
.tag(nil as DebridType?)
ForEach(DebridType.allCases, id: \.self) { (debridType: DebridType) in
if debridManager.enabledDebrids.contains(debridType) {
if debridManager.selectedDebridType == nil {
Image(systemName: "checkmark")
}
}
ForEach(DebridType.allCases, id: \.self) { (debridType: DebridType) in
if debridManager.enabledDebrids.contains(debridType) {
Button {
debridManager.selectedDebridType = debridType
} label: {
Text(debridType.toString())
.tag(DebridType?.some(debridType))
if debridManager.selectedDebridType == debridType {
Image(systemName: "checkmark")
}
}
}
}

View file

@ -42,6 +42,7 @@ struct SortFilterView: View {
} label: {
FilterLabelView(
name: "Sort\(navModel.currentSortFilter.map { ": \($0.rawValue)" } ?? "")",
fallbackName: "Sort",
count: navModel.currentSortFilter == nil ? 0 : 1
)
}

View file

@ -19,19 +19,38 @@ struct SourceFilterView: View {
var body: some View {
Menu {
Picker("", selection: $pluginManager.filteredInstalledSources) {
Text("All").tag([] as [Source])
Button {
pluginManager.filteredInstalledSources = []
} label: {
Text("All")
ForEach(sources, id: \.self) { source in
if source.enabled {
if pluginManager.filteredInstalledSources.isEmpty {
Image(systemName: "checkmark")
}
}
ForEach(sources, id: \.self) { source in
let containsSource = pluginManager.filteredInstalledSources.contains(source)
if source.enabled {
Button {
if containsSource {
pluginManager.filteredInstalledSources.remove(source)
} else {
pluginManager.filteredInstalledSources.insert(source)
}
} label: {
Text(source.name)
.tag([source])
if containsSource {
Image(systemName: "checkmark")
}
}
}
}
} label: {
FilterLabelView(
name: pluginManager.filteredInstalledSources.first?.name ?? "Source",
name: pluginManager.filteredInstalledSources.first?.name,
fallbackName: "Source",
count: pluginManager.filteredInstalledSources.count
)
}

View file

@ -52,7 +52,10 @@ struct SearchFilterHeaderView: View {
// MARK: - Selected debrid picker
SelectedDebridFilterView {
FilterLabelView(name: debridManager.selectedDebridType?.toString() ?? "Debrid")
FilterLabelView(
name: debridManager.selectedDebridType?.toString(),
fallbackName: "Debrid"
)
}
// MARK: - Cache status picker