From 5232ddfc97108a9e75e8920f580d83709b894777 Mon Sep 17 00:00:00 2001 From: kingbri Date: Sun, 23 Apr 2023 14:13:57 -0400 Subject: [PATCH] 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 --- Ferrite/ViewModels/DebridManager.swift | 2 +- Ferrite/ViewModels/PluginManager.swift | 4 +-- .../Filters/FilterLabelView.swift | 5 +-- .../ComponentViews/Filters/IAFilterView.swift | 30 +++++++++++++++--- .../Filters/SelectedDebridFilterView.swift | 22 ++++++++++--- .../Filters/SortFilterView.swift | 1 + .../Filters/SourceFilterView.swift | 31 +++++++++++++++---- .../SearchResult/SearchFilterHeaderView.swift | 5 ++- 8 files changed, 78 insertions(+), 22 deletions(-) diff --git a/Ferrite/ViewModels/DebridManager.swift b/Ferrite/ViewModels/DebridManager.swift index 752e0c5..107fbc0 100644 --- a/Ferrite/ViewModels/DebridManager.swift +++ b/Ferrite/ViewModels/DebridManager.swift @@ -33,7 +33,7 @@ public class DebridManager: ObservableObject { } } - @Published var filteredIAStatus: [IAStatus] = [] + @Published var filteredIAStatus: Set = [] var currentDebridTask: Task? var downloadUrl: String = "" diff --git a/Ferrite/ViewModels/PluginManager.swift b/Ferrite/ViewModels/PluginManager.swift index b857554..f40e498 100644 --- a/Ferrite/ViewModels/PluginManager.swift +++ b/Ferrite/ViewModels/PluginManager.swift @@ -16,7 +16,7 @@ public class PluginManager: ObservableObject { @Published var availableSources: [SourceJson] = [] @Published var availableActions: [ActionJson] = [] - @Published var filteredInstalledSources: [Source] = [] + @Published var filteredInstalledSources: Set = [] @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 { diff --git a/Ferrite/Views/ComponentViews/Filters/FilterLabelView.swift b/Ferrite/Views/ComponentViews/Filters/FilterLabelView.swift index 115d37e..8c35638 100644 --- a/Ferrite/Views/ComponentViews/Filters/FilterLabelView.swift +++ b/Ferrite/Views/ComponentViews/Filters/FilterLabelView.swift @@ -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) diff --git a/Ferrite/Views/ComponentViews/Filters/IAFilterView.swift b/Ferrite/Views/ComponentViews/Filters/IAFilterView.swift index 68365e0..1c56637 100644 --- a/Ferrite/Views/ComponentViews/Filters/IAFilterView.swift +++ b/Ferrite/Views/ComponentViews/Filters/IAFilterView.swift @@ -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 ) } diff --git a/Ferrite/Views/ComponentViews/Filters/SelectedDebridFilterView.swift b/Ferrite/Views/ComponentViews/Filters/SelectedDebridFilterView.swift index a282976..9a98c72 100644 --- a/Ferrite/Views/ComponentViews/Filters/SelectedDebridFilterView.swift +++ b/Ferrite/Views/ComponentViews/Filters/SelectedDebridFilterView.swift @@ -14,14 +14,26 @@ struct SelectedDebridFilterView: 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") + } } } } diff --git a/Ferrite/Views/ComponentViews/Filters/SortFilterView.swift b/Ferrite/Views/ComponentViews/Filters/SortFilterView.swift index f803a38..1f57f96 100644 --- a/Ferrite/Views/ComponentViews/Filters/SortFilterView.swift +++ b/Ferrite/Views/ComponentViews/Filters/SortFilterView.swift @@ -42,6 +42,7 @@ struct SortFilterView: View { } label: { FilterLabelView( name: "Sort\(navModel.currentSortFilter.map { ": \($0.rawValue)" } ?? "")", + fallbackName: "Sort", count: navModel.currentSortFilter == nil ? 0 : 1 ) } diff --git a/Ferrite/Views/ComponentViews/Filters/SourceFilterView.swift b/Ferrite/Views/ComponentViews/Filters/SourceFilterView.swift index 9d45ead..702ef7f 100644 --- a/Ferrite/Views/ComponentViews/Filters/SourceFilterView.swift +++ b/Ferrite/Views/ComponentViews/Filters/SourceFilterView.swift @@ -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 ) } diff --git a/Ferrite/Views/ComponentViews/SearchResult/SearchFilterHeaderView.swift b/Ferrite/Views/ComponentViews/SearchResult/SearchFilterHeaderView.swift index 64a2a7a..a3555fc 100644 --- a/Ferrite/Views/ComponentViews/SearchResult/SearchFilterHeaderView.swift +++ b/Ferrite/Views/ComponentViews/SearchResult/SearchFilterHeaderView.swift @@ -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