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:
parent
f7d2f1ce60
commit
5232ddfc97
8 changed files with 78 additions and 22 deletions
|
|
@ -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 = ""
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ struct SortFilterView: View {
|
|||
} label: {
|
||||
FilterLabelView(
|
||||
name: "Sort\(navModel.currentSortFilter.map { ": \($0.rawValue)" } ?? "")",
|
||||
fallbackName: "Sort",
|
||||
count: navModel.currentSortFilter == nil ? 0 : 1
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue