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 currentDebridTask: Task<Void, Never>?
|
||||||
var downloadUrl: String = ""
|
var downloadUrl: String = ""
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ public class PluginManager: ObservableObject {
|
||||||
@Published var availableSources: [SourceJson] = []
|
@Published var availableSources: [SourceJson] = []
|
||||||
@Published var availableActions: [ActionJson] = []
|
@Published var availableActions: [ActionJson] = []
|
||||||
|
|
||||||
@Published var filteredInstalledSources: [Source] = []
|
@Published var filteredInstalledSources: Set<Source> = []
|
||||||
|
|
||||||
@Published var showActionErrorAlert = false
|
@Published var showActionErrorAlert = false
|
||||||
@Published var actionErrorAlertMessage: String = ""
|
@Published var actionErrorAlertMessage: String = ""
|
||||||
|
|
@ -270,7 +270,7 @@ public class PluginManager: ObservableObject {
|
||||||
let backgroundContext = PersistenceController.shared.backgroundContext
|
let backgroundContext = PersistenceController.shared.backgroundContext
|
||||||
|
|
||||||
if !filteredInstalledSources.isEmpty && !searchResultsEmpty {
|
if !filteredInstalledSources.isEmpty && !searchResultsEmpty {
|
||||||
return filteredInstalledSources
|
return Array(filteredInstalledSources)
|
||||||
} else if let sources = try? backgroundContext.fetch(Source.fetchRequest()) {
|
} else if let sources = try? backgroundContext.fetch(Source.fetchRequest()) {
|
||||||
return sources.compactMap { $0 }
|
return sources.compactMap { $0 }
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ import SwiftUI
|
||||||
struct FilterLabelView: View {
|
struct FilterLabelView: View {
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
|
||||||
var name: String
|
var name: String?
|
||||||
|
var fallbackName: String
|
||||||
var count: Int?
|
var count: Int?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
|
@ -19,7 +20,7 @@ struct FilterLabelView: View {
|
||||||
FilterAmountLabelView(amount: count)
|
FilterAmountLabelView(amount: count)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(name)
|
Text(count == 1 ? name ?? fallbackName : fallbackName)
|
||||||
.opacity(count ?? 0 > 0 ? 1 : 0.6)
|
.opacity(count ?? 0 > 0 ? 1 : 0.6)
|
||||||
.foregroundColor(count ?? 0 > 0 && colorScheme == .light ? .accentColor : .primary)
|
.foregroundColor(count ?? 0 > 0 && colorScheme == .light ? .accentColor : .primary)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,36 @@ struct IAFilterView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Menu {
|
Menu {
|
||||||
Picker("", selection: $debridManager.filteredIAStatus) {
|
Button {
|
||||||
Text("All").tag([] as [IAStatus])
|
debridManager.filteredIAStatus = []
|
||||||
|
} label: {
|
||||||
|
Text("Any")
|
||||||
|
|
||||||
ForEach(IAStatus.allCases, id: \.self) { status in
|
if debridManager.filteredIAStatus.isEmpty {
|
||||||
Text(status.rawValue).tag([status])
|
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: {
|
} label: {
|
||||||
FilterLabelView(
|
FilterLabelView(
|
||||||
name: debridManager.filteredIAStatus.first?.rawValue ?? "Cache Status",
|
name: debridManager.filteredIAStatus.first?.rawValue,
|
||||||
|
fallbackName: "Cache Status",
|
||||||
count: debridManager.filteredIAStatus.count
|
count: debridManager.filteredIAStatus.count
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,26 @@ struct SelectedDebridFilterView<Content: View>: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Menu {
|
Menu {
|
||||||
Picker("", selection: $debridManager.selectedDebridType) {
|
Button {
|
||||||
|
debridManager.selectedDebridType = nil
|
||||||
|
} label: {
|
||||||
Text("None")
|
Text("None")
|
||||||
.tag(nil as DebridType?)
|
|
||||||
|
|
||||||
ForEach(DebridType.allCases, id: \.self) { (debridType: DebridType) in
|
if debridManager.selectedDebridType == nil {
|
||||||
if debridManager.enabledDebrids.contains(debridType) {
|
Image(systemName: "checkmark")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ForEach(DebridType.allCases, id: \.self) { (debridType: DebridType) in
|
||||||
|
if debridManager.enabledDebrids.contains(debridType) {
|
||||||
|
Button {
|
||||||
|
debridManager.selectedDebridType = debridType
|
||||||
|
} label: {
|
||||||
Text(debridType.toString())
|
Text(debridType.toString())
|
||||||
.tag(DebridType?.some(debridType))
|
|
||||||
|
if debridManager.selectedDebridType == debridType {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ struct SortFilterView: View {
|
||||||
} label: {
|
} label: {
|
||||||
FilterLabelView(
|
FilterLabelView(
|
||||||
name: "Sort\(navModel.currentSortFilter.map { ": \($0.rawValue)" } ?? "")",
|
name: "Sort\(navModel.currentSortFilter.map { ": \($0.rawValue)" } ?? "")",
|
||||||
|
fallbackName: "Sort",
|
||||||
count: navModel.currentSortFilter == nil ? 0 : 1
|
count: navModel.currentSortFilter == nil ? 0 : 1
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,19 +19,38 @@ struct SourceFilterView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Menu {
|
Menu {
|
||||||
Picker("", selection: $pluginManager.filteredInstalledSources) {
|
Button {
|
||||||
Text("All").tag([] as [Source])
|
pluginManager.filteredInstalledSources = []
|
||||||
|
} label: {
|
||||||
|
Text("All")
|
||||||
|
|
||||||
ForEach(sources, id: \.self) { source in
|
if pluginManager.filteredInstalledSources.isEmpty {
|
||||||
if source.enabled {
|
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)
|
Text(source.name)
|
||||||
.tag([source])
|
|
||||||
|
if containsSource {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} label: {
|
} label: {
|
||||||
FilterLabelView(
|
FilterLabelView(
|
||||||
name: pluginManager.filteredInstalledSources.first?.name ?? "Source",
|
name: pluginManager.filteredInstalledSources.first?.name,
|
||||||
|
fallbackName: "Source",
|
||||||
count: pluginManager.filteredInstalledSources.count
|
count: pluginManager.filteredInstalledSources.count
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,10 @@ struct SearchFilterHeaderView: View {
|
||||||
// MARK: - Selected debrid picker
|
// MARK: - Selected debrid picker
|
||||||
|
|
||||||
SelectedDebridFilterView {
|
SelectedDebridFilterView {
|
||||||
FilterLabelView(name: debridManager.selectedDebridType?.toString() ?? "Debrid")
|
FilterLabelView(
|
||||||
|
name: debridManager.selectedDebridType?.toString(),
|
||||||
|
fallbackName: "Debrid"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Cache status picker
|
// MARK: - Cache status picker
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue