Ferrite: Format
Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
parent
8c8e9d0215
commit
438e48be66
29 changed files with 165 additions and 192 deletions
|
|
@ -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 {}
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,8 @@
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import CoreData
|
import CoreData
|
||||||
|
import Foundation
|
||||||
|
|
||||||
@objc(PluginList)
|
@objc(PluginList)
|
||||||
public class PluginList: NSManagedObject {
|
public class PluginList: NSManagedObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,8 @@
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import CoreData
|
import CoreData
|
||||||
|
import Foundation
|
||||||
|
|
||||||
@objc(PluginTag)
|
@objc(PluginTag)
|
||||||
public class PluginTag: NSManagedObject {
|
public class PluginTag: NSManagedObject {}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 } ?? [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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]?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 ?? []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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] ?? []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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") {
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue