Filters: Fix animations and add clear all button

Filters are more comprehensive and responsive to how many filters
are stored and if a user should clear all of them or not.

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri 2023-04-11 22:23:53 -04:00
parent 8123fd8d0c
commit 1d89b9519d
13 changed files with 270 additions and 86 deletions

View file

@ -36,7 +36,6 @@
0C41BC6528C2AEB900B47DD6 /* SearchModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C41BC6428C2AEB900B47DD6 /* SearchModels.swift */; };
0C422E7E293542EA00486D65 /* PremiumizeWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C422E7D293542EA00486D65 /* PremiumizeWrapper.swift */; };
0C422E80293542F300486D65 /* PremiumizeModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C422E7F293542F300486D65 /* PremiumizeModels.swift */; };
0C42B5962932F2D5008057A0 /* DebridPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C42B5952932F2D5008057A0 /* DebridPickerView.swift */; };
0C42B5982932F6DD008057A0 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C42B5972932F6DD008057A0 /* Set.swift */; };
0C445C62293F9A0B0060744D /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C445C61293F9A0B0060744D /* Bundle.swift */; };
0C448BE929A135F100F4E266 /* Introspect-Static in Frameworks */ = {isa = PBXBuildFile; productRef = 0C448BE829A135F100F4E266 /* Introspect-Static */; };
@ -90,6 +89,11 @@
0C84F4832895BFED0074B7C9 /* Source+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47B2895BFED0074B7C9 /* Source+CoreDataProperties.swift */; };
0C84F4842895BFED0074B7C9 /* SourceHtmlParser+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47C2895BFED0074B7C9 /* SourceHtmlParser+CoreDataClass.swift */; };
0C84F4852895BFED0074B7C9 /* SourceHtmlParser+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47D2895BFED0074B7C9 /* SourceHtmlParser+CoreDataProperties.swift */; };
0C84FCE129E4B41D00B0DFE4 /* SourceFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84FCE029E4B41D00B0DFE4 /* SourceFilterView.swift */; };
0C84FCE329E4B42600B0DFE4 /* IAFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84FCE229E4B42600B0DFE4 /* IAFilterView.swift */; };
0C84FCE529E4B43200B0DFE4 /* SelectedDebridFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84FCE429E4B43200B0DFE4 /* SelectedDebridFilterView.swift */; };
0C84FCE729E4B61A00B0DFE4 /* FilterModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84FCE629E4B61A00B0DFE4 /* FilterModels.swift */; };
0C84FCE929E5ADEF00B0DFE4 /* FilterAmountLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84FCE829E5ADEF00B0DFE4 /* FilterAmountLabelView.swift */; };
0C871BDF29994D9D005279AC /* FilterLabelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C871BDE29994D9D005279AC /* FilterLabelView.swift */; };
0C8DC35229CE287E008A83AD /* PluginInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C8DC35129CE287E008A83AD /* PluginInfoView.swift */; };
0C8DC35429CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C8DC35329CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift */; };
@ -182,7 +186,6 @@
0C41BC6428C2AEB900B47DD6 /* SearchModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchModels.swift; sourceTree = "<group>"; };
0C422E7D293542EA00486D65 /* PremiumizeWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumizeWrapper.swift; sourceTree = "<group>"; };
0C422E7F293542F300486D65 /* PremiumizeModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PremiumizeModels.swift; sourceTree = "<group>"; };
0C42B5952932F2D5008057A0 /* DebridPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebridPickerView.swift; sourceTree = "<group>"; };
0C42B5972932F6DD008057A0 /* Set.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Set.swift; sourceTree = "<group>"; };
0C445C61293F9A0B0060744D /* Bundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = "<group>"; };
0C44E2A728D4DDDC007711AE /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
@ -230,6 +233,11 @@
0C84F47B2895BFED0074B7C9 /* Source+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Source+CoreDataProperties.swift"; sourceTree = "<group>"; };
0C84F47C2895BFED0074B7C9 /* SourceHtmlParser+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceHtmlParser+CoreDataClass.swift"; sourceTree = "<group>"; };
0C84F47D2895BFED0074B7C9 /* SourceHtmlParser+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceHtmlParser+CoreDataProperties.swift"; sourceTree = "<group>"; };
0C84FCE029E4B41D00B0DFE4 /* SourceFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceFilterView.swift; sourceTree = "<group>"; };
0C84FCE229E4B42600B0DFE4 /* IAFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAFilterView.swift; sourceTree = "<group>"; };
0C84FCE429E4B43200B0DFE4 /* SelectedDebridFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedDebridFilterView.swift; sourceTree = "<group>"; };
0C84FCE629E4B61A00B0DFE4 /* FilterModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterModels.swift; sourceTree = "<group>"; };
0C84FCE829E5ADEF00B0DFE4 /* FilterAmountLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterAmountLabelView.swift; sourceTree = "<group>"; };
0C871BDE29994D9D005279AC /* FilterLabelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterLabelView.swift; sourceTree = "<group>"; };
0C8DC35129CE287E008A83AD /* PluginInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginInfoView.swift; sourceTree = "<group>"; };
0C8DC35329CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceSettingsBaseUrlView.swift; sourceTree = "<group>"; };
@ -322,6 +330,7 @@
0C0755C32934244500ECA142 /* ComponentViews */ = {
isa = PBXGroup;
children = (
0C84FCDB29E4B3F400B0DFE4 /* Filters */,
0C3E00D4296F560800ECECB2 /* Plugin */,
0C0755C42934245800ECA142 /* Debrid */,
0CA3B23528C265FD00616D3A /* Library */,
@ -334,7 +343,6 @@
0C0755C42934245800ECA142 /* Debrid */ = {
isa = PBXGroup;
children = (
0C42B5952932F2D5008057A0 /* DebridPickerView.swift */,
0C0755C5293424A200ECA142 /* DebridLabelView.swift */,
);
path = Debrid;
@ -378,6 +386,7 @@
0C6C7C9C29315292002DF910 /* AllDebridModels.swift */,
0C7ED14028D61BBA009E29AD /* BackupModels.swift */,
0C0755C7293425B500ECA142 /* DebridManagerModels.swift */,
0C84FCE629E4B61A00B0DFE4 /* FilterModels.swift */,
0C68135128BC1A7C00FAD890 /* GithubModels.swift */,
0C422E7F293542F300486D65 /* PremiumizeModels.swift */,
0C0167DB29293FA900B65783 /* RealDebridModels.swift */,
@ -493,6 +502,18 @@
path = Source;
sourceTree = "<group>";
};
0C84FCDB29E4B3F400B0DFE4 /* Filters */ = {
isa = PBXGroup;
children = (
0C84FCE029E4B41D00B0DFE4 /* SourceFilterView.swift */,
0C84FCE229E4B42600B0DFE4 /* IAFilterView.swift */,
0C84FCE429E4B43200B0DFE4 /* SelectedDebridFilterView.swift */,
0C871BDE29994D9D005279AC /* FilterLabelView.swift */,
0C84FCE829E5ADEF00B0DFE4 /* FilterAmountLabelView.swift */,
);
path = Filters;
sourceTree = "<group>";
};
0CA0545C288F7CB200850554 /* Settings */ = {
isa = PBXGroup;
children = (
@ -532,7 +553,6 @@
children = (
0C44E2A928D4DFC4007711AE /* Modifiers */,
0CDCB91728C662640098B513 /* EmptyInstructionView.swift */,
0C871BDE29994D9D005279AC /* FilterLabelView.swift */,
0CA148C1288903F000DE2211 /* NavView.swift */,
0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */,
0CB6516928C5B4A600DCA721 /* InlineHeader.swift */,
@ -802,6 +822,7 @@
0C70E40628C40C4E00A5C72D /* NotificationCenter.swift in Sources */,
0C84F4832895BFED0074B7C9 /* Source+CoreDataProperties.swift in Sources */,
0C2D9653299316CC00A504B6 /* Tag.swift in Sources */,
0C84FCE129E4B41D00B0DFE4 /* SourceFilterView.swift in Sources */,
0CD5E78928CD932B001BF684 /* DisabledAppearance.swift in Sources */,
0CA148DB288903F000DE2211 /* NavView.swift in Sources */,
0CA3B23C28C2AA5600616D3A /* Bookmark+CoreDataClass.swift in Sources */,
@ -820,7 +841,6 @@
0C5005522992B6750064606A /* PluginTagsView.swift in Sources */,
0CB0AB5F29BD2A200015422C /* KodiServerView.swift in Sources */,
0CF2C0A529D1EBD400E716DD /* UIApplication.swift in Sources */,
0C42B5962932F2D5008057A0 /* DebridPickerView.swift in Sources */,
0C2886D72960C50900D6FC16 /* RealDebridCloudView.swift in Sources */,
0C3DD44229B6ACD9006429DB /* KodiServer+CoreDataClass.swift in Sources */,
0C794B6B289DACF100DD1CC8 /* PluginCatalogButtonView.swift in Sources */,
@ -839,6 +859,7 @@
0CC389542970AD900066D06F /* Action+CoreDataProperties.swift in Sources */,
0C7ED14128D61BBA009E29AD /* BackupModels.swift in Sources */,
0CAF9319296399190050812A /* PremiumizeCloudView.swift in Sources */,
0C84FCE529E4B43200B0DFE4 /* SelectedDebridFilterView.swift in Sources */,
0CA148EC288903F000DE2211 /* ContentView.swift in Sources */,
0CC389532970AD900066D06F /* Action+CoreDataClass.swift in Sources */,
0C03EB72296F619900162E9A /* PluginList+CoreDataProperties.swift in Sources */,
@ -881,8 +902,10 @@
0C41BC6328C2AD0F00B47DD6 /* SearchResultButtonView.swift in Sources */,
0CA05459288EE9E600850554 /* PluginManager.swift in Sources */,
0C84F4772895BE680074B7C9 /* FerriteDB.xcdatamodeld in Sources */,
0C84FCE729E4B61A00B0DFE4 /* FilterModels.swift in Sources */,
0C12D43D28CC332A000195BF /* HistoryButtonView.swift in Sources */,
0C733287289C4C820058D1FE /* SourceSettingsView.swift in Sources */,
0C84FCE929E5ADEF00B0DFE4 /* FilterAmountLabelView.swift in Sources */,
0C10848B28BD9A38008F0BA6 /* SettingsAppVersionView.swift in Sources */,
0CA05457288EE58200850554 /* SettingsPluginListView.swift in Sources */,
0C78041D28BFB3EA001E8CA3 /* String.swift in Sources */,
@ -898,6 +921,7 @@
0C7075E429D374C50093DB2D /* Color.swift in Sources */,
0C8DC35229CE287E008A83AD /* PluginInfoView.swift in Sources */,
0C422E80293542F300486D65 /* PremiumizeModels.swift in Sources */,
0C84FCE329E4B42600B0DFE4 /* IAFilterView.swift in Sources */,
0C8DC35629CE2ABF008A83AD /* SourceSettingsApiView.swift in Sources */,
0C4CFC4D28970C8B00AD9FAD /* SourceComplexQuery+CoreDataClass.swift in Sources */,
0C0974B029CCAAAF006DE7A3 /* OperatingSystemVersion.swift in Sources */,

View file

@ -0,0 +1,14 @@
//
// FilterModels.swift
// Ferrite
//
// Created by Brian Dashore on 4/10/23.
//
import Foundation
enum FilterType {
case source
case IA
case sort
}

View file

@ -48,6 +48,9 @@ public class NavigationViewModel: ObservableObject {
@Published var selectedTitle: String = ""
@Published var selectedBatchTitle: String = ""
// For filters
@Published var enabledFilters: Set<FilterType> = []
@Published var kodiExpanded: Bool = false
@Published var currentChoiceSheet: ChoiceSheetType?

View file

@ -265,6 +265,19 @@ public class PluginManager: ObservableObject {
return Application.shared.appVersion >= minVersion
}
// Fetches sources using the background context
public func fetchInstalledSources(searchResultsEmpty: Bool) -> [Source] {
let backgroundContext = PersistenceController.shared.backgroundContext
if !filteredInstalledSources.isEmpty && !searchResultsEmpty {
return filteredInstalledSources
} else if let sources = try? backgroundContext.fetch(Source.fetchRequest()) {
return sources.compactMap { $0 }
} else {
return []
}
}
@MainActor
public func runDefaultAction(urlString: String?, navModel: NavigationViewModel) {
let context = PersistenceController.shared.backgroundContext

View file

@ -1,30 +0,0 @@
//
// FilterLabelView.swift
// Ferrite
//
// Created by Brian Dashore on 2/12/23.
//
import SwiftUI
struct FilterLabelView: View {
var name: String
var body: some View {
HStack(spacing: 4) {
Text(name)
.opacity(0.6)
.foregroundColor(.primary)
Image(systemName: "chevron.down")
.foregroundColor(.init(uiColor: .tertiaryLabel))
}
.padding(.horizontal, 9)
.padding(.vertical, 7)
.font(
.caption
.weight(.medium)
)
.background(Capsule().foregroundColor(.init(uiColor: .secondarySystemFill)))
}
}

View file

@ -0,0 +1,24 @@
//
// FilterAmountLabelView.swift
// Ferrite
//
// Created by Brian Dashore on 4/11/23.
//
import SwiftUI
struct FilterAmountLabelView: View {
@Environment (\.colorScheme) var colorScheme
var amount: Int
var body: some View {
Text(String(amount))
.padding(5)
.foregroundColor(colorScheme == .light ? .white : .accentColor)
.background {
Circle()
.foregroundColor(colorScheme == .light ? .accentColor : .white)
}
}
}

View file

@ -0,0 +1,43 @@
//
// FilterLabelView.swift
// Ferrite
//
// Created by Brian Dashore on 2/12/23.
//
import SwiftUI
struct FilterLabelView: View {
@Environment(\.colorScheme) var colorScheme
var name: String
var count: Int?
var body: some View {
HStack(spacing: 4) {
if let count, count > 1 {
FilterAmountLabelView(amount: count)
}
Text(name)
.opacity(count ?? 0 > 0 ? 1 : 0.6)
.foregroundColor(count ?? 0 > 0 && colorScheme == .light ? .accentColor : .primary)
Image(systemName: "chevron.down")
.foregroundColor(count ?? 0 > 0 ? (colorScheme == .light ? .accentColor : .primary) : .init(uiColor: .tertiaryLabel))
}
.padding(.horizontal, 9)
.padding(.vertical, count ?? 1 > 1 ? 2 : 7)
.font(
.caption
.weight(.medium)
)
.background(
Capsule()
.foregroundColor(
count ?? 0 > 0 ? .accentColor : .init(uiColor: .secondarySystemFill)
)
.opacity(count ?? 0 > 0 && colorScheme == .light ? 0.1 : 1)
)
}
}

View file

@ -0,0 +1,47 @@
//
// IAFilterView.swift
// Ferrite
//
// Created by Brian Dashore on 4/10/23.
//
import SwiftUI
// TODO: Make this use multiple selections
struct IAFilterView: View {
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var navModel: NavigationViewModel
var body: some View {
Menu {
Picker("", selection: $debridManager.filteredIAStatus) {
Text("All").tag([] as [IAStatus])
ForEach(IAStatus.allCases, id: \.self) { status in
Text(status.rawValue).tag([status])
}
}
} label: {
FilterLabelView(
name: debridManager.filteredIAStatus.first?.rawValue ?? "Cache Status",
count: debridManager.filteredIAStatus.count
)
}
.id(debridManager.filteredIAStatus)
.onChange(of: debridManager.filteredIAStatus) { newSources in
if newSources.isEmpty {
navModel.enabledFilters.remove(.IA)
} else {
navModel.enabledFilters.insert(.IA)
}
}
.onChange(of: navModel.enabledFilters) { newFilters in
if newFilters.isEmpty {
Task {
try? await Task.sleep(seconds: 0.25)
debridManager.filteredIAStatus = []
}
}
}
}
}

View file

@ -1,13 +1,13 @@
//
// DebridChoiceView.swift
// SelectedDebridFilterView.swift
// Ferrite
//
// Created by Brian Dashore on 11/26/22.
// Created by Brian Dashore on 4/10/23.
//
import SwiftUI
struct DebridPickerView<Content: View>: View {
struct SelectedDebridFilterView<Content: View>: View {
@EnvironmentObject var debridManager: DebridManager
@ViewBuilder var label: Content
@ -28,5 +28,6 @@ struct DebridPickerView<Content: View>: View {
} label: {
label
}
.id(debridManager.selectedDebridType)
}
}

View file

@ -0,0 +1,55 @@
//
// SourceFilterView.swift
// Ferrite
//
// Created by Brian Dashore on 4/10/23.
//
import SwiftUI
// TODO: Make this use multiple selections
struct SourceFilterView: View {
@EnvironmentObject var pluginManager: PluginManager
@EnvironmentObject var navModel: NavigationViewModel
@FetchRequest(
entity: Source.entity(),
sortDescriptors: []
) var sources: FetchedResults<Source>
var body: some View {
Menu {
Picker("", selection: $pluginManager.filteredInstalledSources) {
Text("All").tag([] as [Source])
ForEach(sources, id: \.self) { source in
if source.enabled {
Text(source.name)
.tag([source])
}
}
}
} label: {
FilterLabelView(
name: pluginManager.filteredInstalledSources.first?.name ?? "Source",
count: pluginManager.filteredInstalledSources.count
)
}
.id(pluginManager.filteredInstalledSources)
.onChange(of: pluginManager.filteredInstalledSources) { newSources in
if newSources.isEmpty {
navModel.enabledFilters.remove(.source)
} else {
navModel.enabledFilters.insert(.source)
}
}
.onChange(of: navModel.enabledFilters) { newFilters in
if newFilters.isEmpty {
Task {
try? await Task.sleep(seconds: 0.25)
pluginManager.filteredInstalledSources = []
}
}
}
}
}

View file

@ -12,61 +12,57 @@ struct SearchFilterHeaderView: View {
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var pluginManager: PluginManager
var sources: FetchedResults<Source>
@EnvironmentObject var navModel: NavigationViewModel
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 6) {
// MARK: - Current filters
if !navModel.enabledFilters.isEmpty {
Menu {
Button("Clear filters", role: .destructive) {
navModel.enabledFilters = []
}
} label: {
HStack(spacing: 4) {
Image(systemName: "line.3.horizontal.decrease")
.opacity(0.6)
.foregroundColor(.primary)
FilterAmountLabelView(amount: navModel.enabledFilters.count)
}
.padding(.horizontal, 9)
.padding(.vertical, 2)
.font(
.caption
.weight(.medium)
)
.background(Capsule().foregroundColor(.init(uiColor: .secondarySystemFill)))
}
Divider()
.frame(width:2, height: 20)
}
// MARK: - Source filter picker
// TODO: Make this use multiple selections
Menu {
Picker("", selection: $pluginManager.filteredInstalledSources) {
Text("All").tag([] as [Source])
ForEach(sources, id: \.self) { source in
if source.enabled {
Text(source.name)
.tag([source])
}
}
}
} label: {
FilterLabelView(
name: pluginManager.filteredInstalledSources.first?.name ?? "Source"
)
}
.id(pluginManager.filteredInstalledSources)
SourceFilterView()
// MARK: - Selected debrid picker
DebridPickerView {
SelectedDebridFilterView {
FilterLabelView(name: debridManager.selectedDebridType?.toString() ?? "Debrid")
}
.id(debridManager.selectedDebridType)
// MARK: - Cache status picker
// TODO: Make this use multiple selections
if !debridManager.enabledDebrids.isEmpty {
Menu {
Picker("", selection: $debridManager.filteredIAStatus) {
Text("All").tag([] as [IAStatus])
ForEach(IAStatus.allCases, id: \.self) { status in
Text(status.rawValue).tag([status])
}
}
} label: {
FilterLabelView(
name: debridManager.filteredIAStatus.first?.rawValue ?? "Cache Status"
)
}
.id(debridManager.filteredIAStatus)
IAFilterView()
}
}
.padding(.horizontal, verticalSizeClass == .compact ? 65 : 18)
.animation(.easeInOut, value: navModel.enabledFilters)
}
}
}

View file

@ -56,7 +56,7 @@ struct ContentView: View {
prompt: navModel.searchPrompt,
dismiss: $dismissAction,
scopeBarContent: {
SearchFilterHeaderView(sources: sources)
SearchFilterHeaderView()
},
onSubmit: {
if
@ -75,21 +75,15 @@ struct ContentView: View {
.onAppear {
navModel.getSearchPrompt()
}
.onChange(of: isEditingSearch) { newVal in
print(newVal)
}
}
}
func executeSearch() {
scrapingModel.runningSearchTask = Task {
await scrapingModel.scanSources(
sources:
scrapingModel.searchResults.isEmpty ?
sources.compactMap { $0 } :
(pluginManager.filteredInstalledSources.isEmpty ?
sources.compactMap { $0 } :
pluginManager.filteredInstalledSources),
sources: pluginManager.fetchInstalledSources(
searchResultsEmpty: scrapingModel.searchResults.isEmpty
),
searchText: searchText,
debridManager: debridManager
)

View file

@ -68,7 +68,7 @@ struct LibraryView: View {
switch navModel.libraryPickerSelection {
case .bookmarks, .debridCloud:
DebridPickerView {
SelectedDebridFilterView {
Text(debridManager.selectedDebridType?.toString(abbreviated: true) ?? "Debrid")
}
.transaction {