Ferrite: Format

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri 2023-03-02 16:23:53 -05:00
parent 8c8e9d0215
commit 438e48be66
29 changed files with 165 additions and 192 deletions

View file

@ -6,8 +6,8 @@
// //
// //
import Foundation
import CoreData import CoreData
import Foundation
@objc(Action) @objc(Action)
public class Action: NSManagedObject, Plugin {} public class Action: NSManagedObject, Plugin {}

View file

@ -6,66 +6,61 @@
// //
// //
import Foundation
import CoreData import CoreData
import Foundation
public extension Action {
extension Action { @nonobjc class func fetchRequest() -> NSFetchRequest<Action> {
NSFetchRequest<Action>(entityName: "Action")
@nonobjc public class func fetchRequest() -> NSFetchRequest<Action> {
return NSFetchRequest<Action>(entityName: "Action")
} }
@NSManaged public var id: UUID @NSManaged var id: UUID
@NSManaged public var listId: UUID? @NSManaged var listId: UUID?
@NSManaged public var name: String @NSManaged var name: String
@NSManaged public var deeplink: String? @NSManaged var deeplink: String?
@NSManaged public var version: Int16 @NSManaged var version: Int16
@NSManaged public var requires: [String] @NSManaged var requires: [String]
@NSManaged public var author: String @NSManaged var author: String
@NSManaged public var enabled: Bool @NSManaged var enabled: Bool
@NSManaged public var tags: NSOrderedSet? @NSManaged var tags: NSOrderedSet?
public func getTags() -> [PluginTagJson] { func getTags() -> [PluginTagJson] {
return requires.map { PluginTagJson(name: $0, colorHex: nil) } + tagArray.map { $0.toJson() } requires.map { PluginTagJson(name: $0, colorHex: nil) } + tagArray.map { $0.toJson() }
} }
} }
// MARK: Generated accessors for tags // MARK: Generated accessors for tags
extension Action {
public extension Action {
@objc(insertObject:inTagsAtIndex:) @objc(insertObject:inTagsAtIndex:)
@NSManaged public func insertIntoTags(_ value: PluginTag, at idx: Int) @NSManaged func insertIntoTags(_ value: PluginTag, at idx: Int)
@objc(removeObjectFromTagsAtIndex:) @objc(removeObjectFromTagsAtIndex:)
@NSManaged public func removeFromTags(at idx: Int) @NSManaged func removeFromTags(at idx: Int)
@objc(insertTags:atIndexes:) @objc(insertTags:atIndexes:)
@NSManaged public func insertIntoTags(_ values: [PluginTag], at indexes: NSIndexSet) @NSManaged func insertIntoTags(_ values: [PluginTag], at indexes: NSIndexSet)
@objc(removeTagsAtIndexes:) @objc(removeTagsAtIndexes:)
@NSManaged public func removeFromTags(at indexes: NSIndexSet) @NSManaged func removeFromTags(at indexes: NSIndexSet)
@objc(replaceObjectInTagsAtIndex:withObject:) @objc(replaceObjectInTagsAtIndex:withObject:)
@NSManaged public func replaceTags(at idx: Int, with value: PluginTag) @NSManaged func replaceTags(at idx: Int, with value: PluginTag)
@objc(replaceTagsAtIndexes:withTags:) @objc(replaceTagsAtIndexes:withTags:)
@NSManaged public func replaceTags(at indexes: NSIndexSet, with values: [PluginTag]) @NSManaged func replaceTags(at indexes: NSIndexSet, with values: [PluginTag])
@objc(addTagsObject:) @objc(addTagsObject:)
@NSManaged public func addToTags(_ value: PluginTag) @NSManaged func addToTags(_ value: PluginTag)
@objc(removeTagsObject:) @objc(removeTagsObject:)
@NSManaged public func removeFromTags(_ value: PluginTag) @NSManaged func removeFromTags(_ value: PluginTag)
@objc(addTags:) @objc(addTags:)
@NSManaged public func addToTags(_ values: NSOrderedSet) @NSManaged func addToTags(_ values: NSOrderedSet)
@objc(removeTags:) @objc(removeTags:)
@NSManaged public func removeFromTags(_ values: NSOrderedSet) @NSManaged func removeFromTags(_ values: NSOrderedSet)
} }
extension Action : Identifiable { extension Action: Identifiable {}
}

View file

@ -6,10 +6,8 @@
// //
// //
import Foundation
import CoreData import CoreData
import Foundation
@objc(PluginList) @objc(PluginList)
public class PluginList: NSManagedObject { public class PluginList: NSManagedObject {}
}

View file

@ -6,23 +6,18 @@
// //
// //
import Foundation
import CoreData import CoreData
import Foundation
public extension PluginList {
extension PluginList { @nonobjc class func fetchRequest() -> NSFetchRequest<PluginList> {
NSFetchRequest<PluginList>(entityName: "PluginList")
@nonobjc public class func fetchRequest() -> NSFetchRequest<PluginList> {
return NSFetchRequest<PluginList>(entityName: "PluginList")
} }
@NSManaged public var author: String @NSManaged var author: String
@NSManaged public var id: UUID @NSManaged var id: UUID
@NSManaged public var name: String @NSManaged var name: String
@NSManaged public var urlString: String @NSManaged var urlString: String
} }
extension PluginList : Identifiable { extension PluginList: Identifiable {}
}

View file

@ -6,9 +6,8 @@
// //
// //
import Foundation
import CoreData import CoreData
import Foundation
@objc(PluginTag) @objc(PluginTag)
public class PluginTag: NSManagedObject { public class PluginTag: NSManagedObject {}
}

View file

@ -6,26 +6,22 @@
// //
// //
import Foundation
import CoreData import CoreData
import Foundation
public extension PluginTag {
extension PluginTag { @nonobjc class func fetchRequest() -> NSFetchRequest<PluginTag> {
NSFetchRequest<PluginTag>(entityName: "PluginTag")
@nonobjc public class func fetchRequest() -> NSFetchRequest<PluginTag> {
return NSFetchRequest<PluginTag>(entityName: "PluginTag")
} }
@NSManaged public var colorHex: String? @NSManaged var colorHex: String?
@NSManaged public var name: String @NSManaged var name: String
@NSManaged public var parentAction: Action? @NSManaged var parentAction: Action?
@NSManaged public var parentSource: Source? @NSManaged var parentSource: Source?
func toJson() -> PluginTagJson { internal func toJson() -> PluginTagJson {
return PluginTagJson(name: name, colorHex: colorHex) PluginTagJson(name: name, colorHex: colorHex)
} }
} }
extension PluginTag : Identifiable { extension PluginTag: Identifiable {}
}

View file

@ -6,73 +6,68 @@
// //
// //
import Foundation
import CoreData import CoreData
import Foundation
public extension Source {
extension Source { @nonobjc class func fetchRequest() -> NSFetchRequest<Source> {
NSFetchRequest<Source>(entityName: "Source")
@nonobjc public class func fetchRequest() -> NSFetchRequest<Source> {
return NSFetchRequest<Source>(entityName: "Source")
} }
@NSManaged public var id: UUID @NSManaged var id: UUID
@NSManaged public var baseUrl: String? @NSManaged var baseUrl: String?
@NSManaged public var fallbackUrls: [String]? @NSManaged var fallbackUrls: [String]?
@NSManaged public var dynamicBaseUrl: Bool @NSManaged var dynamicBaseUrl: Bool
@NSManaged public var enabled: Bool @NSManaged var enabled: Bool
@NSManaged public var name: String @NSManaged var name: String
@NSManaged public var author: String @NSManaged var author: String
@NSManaged public var listId: UUID? @NSManaged var listId: UUID?
@NSManaged public var preferredParser: Int16 @NSManaged var preferredParser: Int16
@NSManaged public var version: Int16 @NSManaged var version: Int16
@NSManaged public var htmlParser: SourceHtmlParser? @NSManaged var htmlParser: SourceHtmlParser?
@NSManaged public var rssParser: SourceRssParser? @NSManaged var rssParser: SourceRssParser?
@NSManaged public var jsonParser: SourceJsonParser? @NSManaged var jsonParser: SourceJsonParser?
@NSManaged public var api: SourceApi? @NSManaged var api: SourceApi?
@NSManaged public var trackers: [String]? @NSManaged var trackers: [String]?
@NSManaged public var tags: NSOrderedSet? @NSManaged var tags: NSOrderedSet?
public func getTags() -> [PluginTagJson] { func getTags() -> [PluginTagJson] {
return tagArray.map { $0.toJson() } tagArray.map { $0.toJson() }
} }
} }
// MARK: Generated accessors for tags // MARK: Generated accessors for tags
extension Source {
public extension Source {
@objc(insertObject:inTagsAtIndex:) @objc(insertObject:inTagsAtIndex:)
@NSManaged public func insertIntoTags(_ value: PluginTag, at idx: Int) @NSManaged func insertIntoTags(_ value: PluginTag, at idx: Int)
@objc(removeObjectFromTagsAtIndex:) @objc(removeObjectFromTagsAtIndex:)
@NSManaged public func removeFromTags(at idx: Int) @NSManaged func removeFromTags(at idx: Int)
@objc(insertTags:atIndexes:) @objc(insertTags:atIndexes:)
@NSManaged public func insertIntoTags(_ values: [PluginTag], at indexes: NSIndexSet) @NSManaged func insertIntoTags(_ values: [PluginTag], at indexes: NSIndexSet)
@objc(removeTagsAtIndexes:) @objc(removeTagsAtIndexes:)
@NSManaged public func removeFromTags(at indexes: NSIndexSet) @NSManaged func removeFromTags(at indexes: NSIndexSet)
@objc(replaceObjectInTagsAtIndex:withObject:) @objc(replaceObjectInTagsAtIndex:withObject:)
@NSManaged public func replaceTags(at idx: Int, with value: PluginTag) @NSManaged func replaceTags(at idx: Int, with value: PluginTag)
@objc(replaceTagsAtIndexes:withTags:) @objc(replaceTagsAtIndexes:withTags:)
@NSManaged public func replaceTags(at indexes: NSIndexSet, with values: [PluginTag]) @NSManaged func replaceTags(at indexes: NSIndexSet, with values: [PluginTag])
@objc(addTagsObject:) @objc(addTagsObject:)
@NSManaged public func addToTags(_ value: PluginTag) @NSManaged func addToTags(_ value: PluginTag)
@objc(removeTagsObject:) @objc(removeTagsObject:)
@NSManaged public func removeFromTags(_ value: PluginTag) @NSManaged func removeFromTags(_ value: PluginTag)
@objc(addTags:) @objc(addTags:)
@NSManaged public func addToTags(_ values: NSOrderedSet) @NSManaged func addToTags(_ values: NSOrderedSet)
@objc(removeTags:) @objc(removeTags:)
@NSManaged public func removeFromTags(_ values: NSOrderedSet) @NSManaged func removeFromTags(_ values: NSOrderedSet)
} }
extension Source : Identifiable { extension Source: Identifiable {}
}

View file

@ -37,11 +37,11 @@ extension View {
modifier(ViewDidAppearModifier(callback: callback)) modifier(ViewDidAppearModifier(callback: callback))
} }
func customScopeBar<Content: View>(_ content: Content) -> some View { func customScopeBar(_ content: some View) -> some View {
modifier(CustomScopeBarModifier(hostingContent: content)) modifier(CustomScopeBarModifier(hostingContent: content))
} }
func customScopeBar<Content: View>(_ content: @escaping () -> Content) -> some View { func customScopeBar(_ content: @escaping () -> some View) -> some View {
modifier(CustomScopeBarModifier(hostingContent: content())) modifier(CustomScopeBarModifier(hostingContent: content()))
} }
} }

View file

@ -7,7 +7,7 @@
import Foundation import Foundation
public struct ActionJson: Codable, Hashable, PluginJson { public struct ActionJson: Codable, Hashable, PluginJson {
public let name: String public let name: String
public let version: Int16 public let version: Int16
let minVersion: String? let minVersion: String?
@ -18,11 +18,11 @@ public struct ActionJson: Codable, Hashable, PluginJson {
public var tags: [PluginTagJson]? public var tags: [PluginTagJson]?
} }
extension ActionJson { public extension ActionJson {
// Fetches all tags without optional requirement // Fetches all tags without optional requirement
// Avoids the need for extra tag additions in DB // Avoids the need for extra tag additions in DB
public func getTags() -> [PluginTagJson] { func getTags() -> [PluginTagJson] {
return requires.map { PluginTagJson(name: $0.rawValue, colorHex: nil) } + (tags.map { $0 } ?? []) requires.map { PluginTagJson(name: $0.rawValue, colorHex: nil) } + (tags.map { $0 } ?? [])
} }
} }

View file

@ -17,6 +17,7 @@ public struct Backup: Codable {
var pluginListUrls: [String]? var pluginListUrls: [String]?
// MARK: Remove once v1 backups are unsupported // MARK: Remove once v1 backups are unsupported
var sourceLists: [PluginListBackupJson]? var sourceLists: [PluginListBackupJson]?
} }

View file

@ -29,10 +29,10 @@ public struct SourceJson: Codable, Hashable, Sendable, PluginJson {
public var tags: [PluginTagJson]? public var tags: [PluginTagJson]?
} }
extension SourceJson { public extension SourceJson {
// Fetches all tags without optional requirement // Fetches all tags without optional requirement
public func getTags() -> [PluginTagJson] { func getTags() -> [PluginTagJson] {
return tags ?? [] tags ?? []
} }
} }

View file

@ -21,7 +21,7 @@ public protocol Plugin: ObservableObject, NSManagedObject {
extension Plugin { extension Plugin {
var tagArray: [PluginTag] { var tagArray: [PluginTag] {
return self.tags?.array as? [PluginTag] ?? [] tags?.array as? [PluginTag] ?? []
} }
} }

View file

@ -93,19 +93,18 @@ public class PluginManager: ObservableObject {
} }
// forType required to guide generic inferences // forType required to guide generic inferences
func fetchFilteredPlugins<P: Plugin, PJ: PluginJson>( func fetchFilteredPlugins<PJ: PluginJson>(forType: PJ.Type,
forType: PJ.Type, installedPlugins: FetchedResults<some Plugin>,
installedPlugins: FetchedResults<P>, searchText: String) -> [PJ]
searchText: String {
) -> [PJ] {
let availablePlugins: [PJ] = fetchCastedPlugins(forType) let availablePlugins: [PJ] = fetchCastedPlugins(forType)
return availablePlugins return availablePlugins
.filter { availablePlugin in .filter { availablePlugin in
let pluginExists = installedPlugins.contains(where: { let pluginExists = installedPlugins.contains(where: {
availablePlugin.name == $0.name && availablePlugin.name == $0.name &&
availablePlugin.listId == $0.listId && availablePlugin.listId == $0.listId &&
availablePlugin.author == $0.author availablePlugin.author == $0.author
}) })
if searchText.isEmpty { if searchText.isEmpty {
@ -116,19 +115,18 @@ public class PluginManager: ObservableObject {
} }
} }
func fetchUpdatedPlugins<P: Plugin, PJ: PluginJson>( func fetchUpdatedPlugins<PJ: PluginJson>(forType: PJ.Type,
forType: PJ.Type, installedPlugins: FetchedResults<some Plugin>,
installedPlugins: FetchedResults<P>, searchText: String) -> [PJ]
searchText: String {
) -> [PJ] {
var updatedPlugins: [PJ] = [] var updatedPlugins: [PJ] = []
let availablePlugins: [PJ] = fetchCastedPlugins(forType) let availablePlugins: [PJ] = fetchCastedPlugins(forType)
for plugin in installedPlugins { for plugin in installedPlugins {
if let availablePlugin = availablePlugins.first(where: { if let availablePlugin = availablePlugins.first(where: {
plugin.listId == $0.listId && plugin.listId == $0.listId &&
plugin.name == $0.name && plugin.name == $0.name &&
plugin.author == $0.author plugin.author == $0.author
}), }),
availablePlugin.version > plugin.version availablePlugin.version > plugin.version
{ {
@ -257,7 +255,7 @@ public class PluginManager: ObservableObject {
if actionJson.requires.count < 1 { if actionJson.requires.count < 1 {
await toastModel?.updateToastDescription("Action addition error: actions must require an input. Please contact the action dev!") await toastModel?.updateToastDescription("Action addition error: actions must require an input. Please contact the action dev!")
print("Action name \(actionJson.name) does not have a requires parameter") print("Action name \(actionJson.name) does not have a requires parameter")
return return
} }
@ -289,7 +287,7 @@ public class PluginManager: ObservableObject {
newAction.version = actionJson.version newAction.version = actionJson.version
newAction.author = actionJson.author ?? "Unknown" newAction.author = actionJson.author ?? "Unknown"
newAction.listId = actionJson.listId newAction.listId = actionJson.listId
newAction.requires = actionJson.requires.map { $0.rawValue } newAction.requires = actionJson.requires.map(\.rawValue)
newAction.enabled = true newAction.enabled = true
if let jsonTags = actionJson.tags { if let jsonTags = actionJson.tags {
@ -325,7 +323,7 @@ public class PluginManager: ObservableObject {
if !dynamicBaseUrl, sourceJson.baseUrl == nil { if !dynamicBaseUrl, sourceJson.baseUrl == nil {
await toastModel?.updateToastDescription("Not adding this source because base URL parameters are malformed. Please contact the source dev.") await toastModel?.updateToastDescription("Not adding this source because base URL parameters are malformed. Please contact the source dev.")
print("Not adding source \(sourceJson.name) because base URL parameters are malformed") print("Not adding source \(sourceJson.name) because base URL parameters are malformed")
return return
} }

View file

@ -483,7 +483,6 @@ class ScrapingViewModel: ObservableObject {
} }
for item in items { for item in items {
//print(item)
// Parse magnet link or translate hash // Parse magnet link or translate hash
var magnetHash: String? var magnetHash: String?
if let magnetHashParser = rssParser.magnetHash { if let magnetHashParser = rssParser.magnetHash {

View file

@ -36,7 +36,7 @@ class ToastViewModel: ObservableObject {
@Published var showToast: Bool = false @Published var showToast: Bool = false
@Published var indeterminateToastDescription: String? = nil @Published var indeterminateToastDescription: String? = nil
@Published var indeterminateCancelAction: (() -> ())? = nil @Published var indeterminateCancelAction: (() -> Void)? = nil
@Published var showIndeterminateToast: Bool = false @Published var showIndeterminateToast: Bool = false
public func updateToastDescription(_ description: String, newToastType: ToastType? = nil) { public func updateToastDescription(_ description: String, newToastType: ToastType? = nil) {
@ -47,7 +47,7 @@ class ToastViewModel: ObservableObject {
toastDescription = description toastDescription = description
} }
public func updateIndeterminateToast(_ description: String, cancelAction: (() -> ())?) { public func updateIndeterminateToast(_ description: String, cancelAction: (() -> Void)?) {
indeterminateToastDescription = description indeterminateToastDescription = description
if let cancelAction { if let cancelAction {

View file

@ -5,8 +5,8 @@
// Created by Brian Dashore on 9/29/22. // Created by Brian Dashore on 9/29/22.
// //
import SwiftUI
import Introspect import Introspect
import SwiftUI
public struct Backport<Content> { public struct Backport<Content> {
public let content: Content public let content: Content
@ -21,12 +21,11 @@ extension View {
} }
extension Backport where Content: View { extension Backport where Content: View {
@ViewBuilder func alert( @ViewBuilder func alert(isPresented: Binding<Bool>,
isPresented: Binding<Bool>, title: String,
title: String, message: String?,
message: String?, buttons: [AlertButton] = []) -> some View
buttons: [AlertButton] = [] {
) -> some View {
if #available(iOS 15, *) { if #available(iOS 15, *) {
content content
.alert( .alert(
@ -69,11 +68,10 @@ extension Backport where Content: View {
} }
} }
@ViewBuilder func confirmationDialog( @ViewBuilder func confirmationDialog(isPresented: Binding<Bool>,
isPresented: Binding<Bool>, title: String, message: String?,
title: String, message: String?, buttons: [AlertButton]) -> some View
buttons: [AlertButton] {
) -> some View {
if #available(iOS 15, *) { if #available(iOS 15, *) {
content content
.confirmationDialog( .confirmationDialog(
@ -125,7 +123,7 @@ extension Backport where Content: View {
} }
} }
@ViewBuilder func introspectSearchController(customize: @escaping (UISearchController) -> ()) -> some View { @ViewBuilder func introspectSearchController(customize: @escaping (UISearchController) -> Void) -> some View {
if #available(iOS 15, *) { if #available(iOS 15, *) {
content.introspectSearchController(customize: customize) content.introspectSearchController(customize: customize)
} else { } else {

View file

@ -11,7 +11,5 @@ struct LibraryHeaderView: View {
@EnvironmentObject var debridManager: DebridManager @EnvironmentObject var debridManager: DebridManager
@Binding var selectedSegment: LibraryPickerSegment @Binding var selectedSegment: LibraryPickerSegment
var body: some View { var body: some View {}
}
} }

View file

@ -5,8 +5,8 @@
// Created by Brian Dashore on 2/14/23. // Created by Brian Dashore on 2/14/23.
// //
import SwiftUI
import Introspect import Introspect
import SwiftUI
struct CustomScopeBarModifier<V: View>: ViewModifier { struct CustomScopeBarModifier<V: View>: ViewModifier {
let hostingContent: V let hostingContent: V
@ -25,6 +25,7 @@ struct CustomScopeBarModifier<V: View>: ViewModifier {
searchController.searchBar.autocapitalizationType = autocorrectSearch ? .sentences : .none searchController.searchBar.autocapitalizationType = autocorrectSearch ? .sentences : .none
// MARK: One-time setup // MARK: One-time setup
guard hostingController == nil else { return } guard hostingController == nil else { return }
searchController.hidesNavigationBarDuringPresentation = true searchController.hidesNavigationBarDuringPresentation = true

View file

@ -28,7 +28,7 @@ struct SearchableContent<Content: View>: View {
lastHeight = newHeight lastHeight = newHeight
} }
.transaction { .transaction {
if geom.size.height != lastHeight && searching { if geom.size.height != lastHeight, searching {
$0.animation = .default.speed(2) $0.animation = .default.speed(2)
} }
} }

View file

@ -24,7 +24,7 @@ struct TestHostingView: View {
Text(textName) Text(textName)
.opacity(0.6) .opacity(0.6)
.foregroundColor(.primary) .foregroundColor(.primary)
Image(systemName: "chevron.down") Image(systemName: "chevron.down")
.foregroundColor(.tertiaryLabel) .foregroundColor(.tertiaryLabel)
} }
@ -49,7 +49,7 @@ struct TestHostingView: View {
Text(secondTextName) Text(secondTextName)
.opacity(0.6) .opacity(0.6)
.foregroundColor(.primary) .foregroundColor(.primary)
Image(systemName: "chevron.down") Image(systemName: "chevron.down")
.foregroundColor(.tertiaryLabel) .foregroundColor(.tertiaryLabel)
} }

View file

@ -17,7 +17,7 @@ struct DebridPickerView<Content: View>: View {
Picker("", selection: $debridManager.selectedDebridType) { Picker("", selection: $debridManager.selectedDebridType) {
Text("None") Text("None")
.tag(nil as DebridType?) .tag(nil as DebridType?)
ForEach(DebridType.allCases, id: \.self) { (debridType: DebridType) in ForEach(DebridType.allCases, id: \.self) { (debridType: DebridType) in
if debridManager.enabledDebrids.contains(debridType) { if debridManager.enabledDebrids.contains(debridType) {
Text(debridType.toString()) Text(debridType.toString())

View file

@ -26,30 +26,30 @@ struct BookmarksView: View {
sortDescriptors: [NSSortDescriptor(keyPath: \Bookmark.orderNum, ascending: true)] sortDescriptors: [NSSortDescriptor(keyPath: \Bookmark.orderNum, ascending: true)]
) { (bookmarks: FetchedResults<Bookmark>) in ) { (bookmarks: FetchedResults<Bookmark>) in
List { List {
if !bookmarks.isEmpty { if !bookmarks.isEmpty {
ForEach(bookmarks, id: \.self) { bookmark in ForEach(bookmarks, id: \.self) { bookmark in
SearchResultButtonView(result: bookmark.toSearchResult(), existingBookmark: bookmark) SearchResultButtonView(result: bookmark.toSearchResult(), existingBookmark: bookmark)
} }
.onDelete { offsets in .onDelete { offsets in
for index in offsets { for index in offsets {
if let bookmark = bookmarks[safe: index] { if let bookmark = bookmarks[safe: index] {
PersistenceController.shared.delete(bookmark, context: backgroundContext) PersistenceController.shared.delete(bookmark, context: backgroundContext)
NotificationCenter.default.post(name: .didDeleteBookmark, object: bookmark) NotificationCenter.default.post(name: .didDeleteBookmark, object: bookmark)
}
} }
} }
.onMove { source, destination in
var changedBookmarks = bookmarks.map { $0 }
changedBookmarks.move(fromOffsets: source, toOffset: destination)
for reverseIndex in stride(from: changedBookmarks.count - 1, through: 0, by: -1) {
changedBookmarks[reverseIndex].orderNum = Int16(reverseIndex)
}
PersistenceController.shared.save()
}
} }
.onMove { source, destination in
var changedBookmarks = bookmarks.map { $0 }
changedBookmarks.move(fromOffsets: source, toOffset: destination)
for reverseIndex in stride(from: changedBookmarks.count - 1, through: 0, by: -1) {
changedBookmarks[reverseIndex].orderNum = Int16(reverseIndex)
}
PersistenceController.shared.save()
}
}
} }
.listStyle(.insetGrouped) .listStyle(.insetGrouped)
.inlinedList(inset: Application.shared.osVersion.majorVersion > 14 ? 15 : -25) .inlinedList(inset: Application.shared.osVersion.majorVersion > 14 ? 15 : -25)

View file

@ -37,7 +37,7 @@ struct SearchFilterHeaderView: View {
} }
.id(scrapingModel.filteredSource) .id(scrapingModel.filteredSource)
DebridPickerView() { DebridPickerView {
FilterLabelView(name: debridManager.selectedDebridType?.toString() ?? "Debrid") FilterLabelView(name: debridManager.selectedDebridType?.toString() ?? "Debrid")
} }
.id(debridManager.selectedDebridType) .id(debridManager.selectedDebridType)

View file

@ -44,12 +44,12 @@ struct ContentView: View {
.listStyle(.insetGrouped) .listStyle(.insetGrouped)
.inlinedList(inset: Application.shared.osVersion.majorVersion > 14 ? 20 : -20) .inlinedList(inset: Application.shared.osVersion.majorVersion > 14 ? 20 : -20)
.overlay { .overlay {
if scrapingModel.searchResults.isEmpty && isSearching && scrapingModel.runningSearchTask == nil { if scrapingModel.searchResults.isEmpty, isSearching, scrapingModel.runningSearchTask == nil {
Text("No results found") Text("No results found")
} }
} }
.onChange(of: searchText) { newText in .onChange(of: searchText) { newText in
if newText.isEmpty && isSearching { if newText.isEmpty, isSearching {
searchBarText = getSearchBarText() searchBarText = getSearchBarText()
} }
} }
@ -124,7 +124,7 @@ struct ContentView: View {
// Fetches random searchbar text if enabled, otherwise deinit the last case value // Fetches random searchbar text if enabled, otherwise deinit the last case value
func getSearchBarText() -> String { func getSearchBarText() -> String {
if usesRandomSearchText { if usesRandomSearchText {
let num = Int.random(in: 0..<searchBarTextArray.count - 1) let num = Int.random(in: 0 ..< searchBarTextArray.count - 1)
if num == lastSearchTextIndex { if num == lastSearchTextIndex {
lastSearchTextIndex = num + 1 lastSearchTextIndex = num + 1
return searchBarTextArray[safe: num + 1] ?? "Search" return searchBarTextArray[safe: num + 1] ?? "Search"

View file

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

View file

@ -109,7 +109,7 @@ struct MainView: View {
isPresented: $backupManager.showRestoreAlert, isPresented: $backupManager.showRestoreAlert,
title: "Restore backup?", title: "Restore backup?",
message: message:
"Merge (preferred): Will merge your current data with the backup \n\n" + "Merge (preferred): Will merge your current data with the backup \n\n" +
"Overwrite: Will delete and replace all your data \n\n" + "Overwrite: Will delete and replace all your data \n\n" +
"If Merge causes app instability, uninstall Ferrite and use the Overwrite option.", "If Merge causes app instability, uninstall Ferrite and use the Overwrite option.",
buttons: [ buttons: [
@ -140,7 +140,7 @@ struct MainView: View {
isPresented: $showUpdateAlert, isPresented: $showUpdateAlert,
title: "Update available", title: "Update available",
message: message:
"Ferrite \(releaseVersionString) can be downloaded. \n\n" + "Ferrite \(releaseVersionString) can be downloaded. \n\n" +
"This alert can be disabled in Settings.", "This alert can be disabled in Settings.",
buttons: [ buttons: [
.init("Download") { .init("Download") {

View file

@ -48,11 +48,11 @@ struct PluginsView: View {
if checkedForPlugins { if checkedForPlugins {
switch navModel.pluginPickerSelection { switch navModel.pluginPickerSelection {
case .sources: case .sources:
if sources.isEmpty && pluginManager.availableSources.isEmpty { if sources.isEmpty, pluginManager.availableSources.isEmpty {
EmptyInstructionView(title: "No Sources", message: "Add a plugin list in Settings") EmptyInstructionView(title: "No Sources", message: "Add a plugin list in Settings")
} }
case .actions: case .actions:
if actions.isEmpty && pluginManager.availableActions.isEmpty { if actions.isEmpty, pluginManager.availableActions.isEmpty {
EmptyInstructionView(title: "No Actions", message: "Add a plugin list in Settings") EmptyInstructionView(title: "No Actions", message: "Add a plugin list in Settings")
} }
} }

View file

@ -97,7 +97,7 @@ struct SettingsView: View {
} }
Section(header: InlineHeader("Default actions")) { Section(header: InlineHeader("Default actions")) {
//if debridManager.enabledDebrids.count > 0 { if debridManager.enabledDebrids.count > 0 {
NavigationLink( NavigationLink(
destination: DefaultActionPickerView( destination: DefaultActionPickerView(
actionRequirement: .debrid, actionRequirement: .debrid,
@ -115,7 +115,7 @@ struct SettingsView: View {
} }
} }
) )
//} }
NavigationLink( NavigationLink(
destination: DefaultActionPickerView( destination: DefaultActionPickerView(

View file

@ -116,7 +116,7 @@ struct ActionChoiceView: View {
isPresented: $pluginManager.showBrokenDefaultActionAlert, isPresented: $pluginManager.showBrokenDefaultActionAlert,
title: "Action not found", title: "Action not found",
message: message:
"The default action could not be run. The action choice sheet has been opened. \n\n" + "The default action could not be run. The action choice sheet has been opened. \n\n" +
"Please check your default actions in Settings" "Please check your default actions in Settings"
) )
.onDisappear { .onDisappear {