From e063b91f3fbb181f1c177beec2e349ba4c1f01cf Mon Sep 17 00:00:00 2001 From: kingbri Date: Sat, 19 Nov 2022 11:58:02 -0500 Subject: [PATCH] Ferrite: Format and cleanup Also add swipe to delete support in source lists Signed-off-by: kingbri --- Ferrite.xcodeproj/project.pbxproj | 10 +- .../PersistenceController.swift | 4 +- Ferrite/Extensions/View.swift | 6 +- Ferrite/Models/RealDebridModels.swift | 228 +++++++++--------- Ferrite/ViewModels/BackupManager.swift | 2 +- Ferrite/ViewModels/DebridManager.swift | 2 +- Ferrite/ViewModels/ScrapingViewModel.swift | 32 +-- Ferrite/ViewModels/SourceManager.swift | 4 +- Ferrite/ViewModels/ToastViewModel.swift | 2 +- Ferrite/Views/CommonViews/AlertButton.swift | 4 +- Ferrite/Views/CommonViews/Backport.swift | 4 +- Ferrite/Views/CommonViews/ListRowViews.swift | 2 +- .../SettingsSourceListView.swift | 7 + 13 files changed, 158 insertions(+), 149 deletions(-) diff --git a/Ferrite.xcodeproj/project.pbxproj b/Ferrite.xcodeproj/project.pbxproj index 36097b0..458439c 100644 --- a/Ferrite.xcodeproj/project.pbxproj +++ b/Ferrite.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0C0167DC29293FA900B65783 /* RealDebridModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0167DB29293FA900B65783 /* RealDebridModels.swift */; }; 0C0D50E5288DFE7F0035ECC8 /* SourceModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0D50E4288DFE7F0035ECC8 /* SourceModels.swift */; }; 0C0D50E7288DFF850035ECC8 /* SourcesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0D50E6288DFF850035ECC8 /* SourcesView.swift */; }; 0C10848B28BD9A38008F0BA6 /* SettingsAppVersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C10848A28BD9A38008F0BA6 /* SettingsAppVersionView.swift */; }; @@ -68,7 +69,6 @@ 0CA148DB288903F000DE2211 /* NavView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148C1288903F000DE2211 /* NavView.swift */; }; 0CA148DC288903F000DE2211 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CA148C2288903F000DE2211 /* Assets.xcassets */; }; 0CA148DD288903F000DE2211 /* ScrapingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148C3288903F000DE2211 /* ScrapingViewModel.swift */; }; - 0CA148DE288903F000DE2211 /* RealDebridModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148C4288903F000DE2211 /* RealDebridModels.swift */; }; 0CA148DF288903F000DE2211 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CA148C6288903F000DE2211 /* Preview Assets.xcassets */; }; 0CA148E0288903F000DE2211 /* FerriteApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148C7288903F000DE2211 /* FerriteApp.swift */; }; 0CA148E1288903F000DE2211 /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148C9288903F000DE2211 /* Collection.swift */; }; @@ -104,6 +104,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 0C0167DB29293FA900B65783 /* RealDebridModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealDebridModels.swift; sourceTree = ""; }; 0C0D50E4288DFE7F0035ECC8 /* SourceModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceModels.swift; sourceTree = ""; }; 0C0D50E6288DFF850035ECC8 /* SourcesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourcesView.swift; sourceTree = ""; }; 0C10848A28BD9A38008F0BA6 /* SettingsAppVersionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAppVersionView.swift; sourceTree = ""; }; @@ -160,7 +161,6 @@ 0CA148C1288903F000DE2211 /* NavView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavView.swift; sourceTree = ""; }; 0CA148C2288903F000DE2211 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0CA148C3288903F000DE2211 /* ScrapingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrapingViewModel.swift; sourceTree = ""; }; - 0CA148C4288903F000DE2211 /* RealDebridModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.swift; path = RealDebridModels.swift; sourceTree = ""; }; 0CA148C6288903F000DE2211 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 0CA148C7288903F000DE2211 /* FerriteApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FerriteApp.swift; sourceTree = ""; }; 0CA148C9288903F000DE2211 /* Collection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = ""; }; @@ -243,7 +243,7 @@ children = ( 0C7ED14028D61BBA009E29AD /* BackupModels.swift */, 0C68135128BC1A7C00FAD890 /* GithubModels.swift */, - 0CA148C4288903F000DE2211 /* RealDebridModels.swift */, + 0C0167DB29293FA900B65783 /* RealDebridModels.swift */, 0C41BC6428C2AEB900B47DD6 /* SearchModels.swift */, 0C95D8D928A55BB6005E22B3 /* SettingsModels.swift */, 0C0D50E4288DFE7F0035ECC8 /* SourceModels.swift */, @@ -605,6 +605,7 @@ 0C4CFC4E28970C8B00AD9FAD /* SourceComplexQuery+CoreDataProperties.swift in Sources */, 0CDCB91828C662640098B513 /* EmptyInstructionView.swift in Sources */, 0CA148E2288903F000DE2211 /* Data.swift in Sources */, + 0C0167DC29293FA900B65783 /* RealDebridModels.swift in Sources */, 0C57D4CC289032ED008534E8 /* SearchResultRDView.swift in Sources */, 0C41BC6328C2AD0F00B47DD6 /* SearchResultButtonView.swift in Sources */, 0CA05459288EE9E600850554 /* SourceManager.swift in Sources */, @@ -615,7 +616,6 @@ 0CA05457288EE58200850554 /* SettingsSourceListView.swift in Sources */, 0C78041D28BFB3EA001E8CA3 /* String.swift in Sources */, 0C31133C28B1ABFA004DCB0D /* SourceJsonParser+CoreDataClass.swift in Sources */, - 0CA148DE288903F000DE2211 /* RealDebridModels.swift in Sources */, 0CBC76FF288DAAD00054BE44 /* NavigationViewModel.swift in Sources */, 0C44E2AD28D51C63007711AE /* BackupManager.swift in Sources */, 0C4CFC4D28970C8B00AD9FAD /* SourceComplexQuery+CoreDataClass.swift in Sources */, @@ -767,6 +767,7 @@ INFOPLIST_FILE = Ferrite/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Ferrite; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment"; + INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; @@ -801,6 +802,7 @@ INFOPLIST_FILE = Ferrite/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Ferrite; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment"; + INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; diff --git a/Ferrite/DataManagement/PersistenceController.swift b/Ferrite/DataManagement/PersistenceController.swift index a3ac7f0..6983d0a 100644 --- a/Ferrite/DataManagement/PersistenceController.swift +++ b/Ferrite/DataManagement/PersistenceController.swift @@ -45,7 +45,7 @@ struct PersistenceController { description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) container.loadPersistentStores { _, error in - if let error = error { + if let error { fatalError("CoreData init error: \(error)") } } @@ -203,7 +203,7 @@ struct PersistenceController { let fetchRequest = NSFetchRequest(entityName: "History") - if let predicate = predicate { + if let predicate { fetchRequest.predicate = predicate } else if range != .allTime { throw HistoryDeleteError.noDate("No history date range was provided and you weren't trying to clear everything! Try relaunching the app?") diff --git a/Ferrite/Extensions/View.swift b/Ferrite/Extensions/View.swift index 16092d5..b47adf9 100644 --- a/Ferrite/Extensions/View.swift +++ b/Ferrite/Extensions/View.swift @@ -25,13 +25,13 @@ extension View { // MARK: Modifiers - func conditionalContextMenu(id: ID, - @ViewBuilder _ internalContent: @escaping () -> InternalContent) -> some View + func conditionalContextMenu(id: some Hashable, + @ViewBuilder _ internalContent: @escaping () -> some View) -> some View { modifier(ConditionalContextMenu(internalContent, id: id)) } - func conditionalId(_ id: ID) -> some View { + func conditionalId(_ id: some Hashable) -> some View { modifier(ConditionalId(id: id)) } diff --git a/Ferrite/Models/RealDebridModels.swift b/Ferrite/Models/RealDebridModels.swift index 3d6487e..b58de72 100644 --- a/Ferrite/Models/RealDebridModels.swift +++ b/Ferrite/Models/RealDebridModels.swift @@ -2,7 +2,7 @@ // RealDebridModels.swift // Ferrite // -// Created by Brian Dashore on 7/5/22. +// Created by Brian Dashore on 11/19/22. // // Structures generated from Quicktype @@ -11,184 +11,184 @@ import Foundation // MARK: - device code endpoint public struct DeviceCodeResponse: Codable, Sendable { - let deviceCode, userCode: String - let interval, expiresIn: Int - let verificationURL, directVerificationURL: String + let deviceCode, userCode: String + let interval, expiresIn: Int + let verificationURL, directVerificationURL: String - enum CodingKeys: String, CodingKey { - case deviceCode = "device_code" - case userCode = "user_code" - case interval - case expiresIn = "expires_in" - case verificationURL = "verification_url" - case directVerificationURL = "direct_verification_url" - } + enum CodingKeys: String, CodingKey { + case deviceCode = "device_code" + case userCode = "user_code" + case interval + case expiresIn = "expires_in" + case verificationURL = "verification_url" + case directVerificationURL = "direct_verification_url" + } } // MARK: - device credentials endpoint public struct DeviceCredentialsResponse: Codable, Sendable { - let clientID, clientSecret: String? + let clientID, clientSecret: String? - enum CodingKeys: String, CodingKey { - case clientID = "client_id" - case clientSecret = "client_secret" - } + enum CodingKeys: String, CodingKey { + case clientID = "client_id" + case clientSecret = "client_secret" + } } // MARK: - token endpoint public struct TokenResponse: Codable, Sendable { - let accessToken: String - let expiresIn: Int - let refreshToken, tokenType: String + let accessToken: String + let expiresIn: Int + let refreshToken, tokenType: String - enum CodingKeys: String, CodingKey { - case accessToken = "access_token" - case expiresIn = "expires_in" - case refreshToken = "refresh_token" - case tokenType = "token_type" - } + enum CodingKeys: String, CodingKey { + case accessToken = "access_token" + case expiresIn = "expires_in" + case refreshToken = "refresh_token" + case tokenType = "token_type" + } } // MARK: - instantAvailability endpoint // Thanks Skitty! public struct InstantAvailabilityResponse: Codable, Sendable { - var data: InstantAvailabilityData? + var data: InstantAvailabilityData? - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() - if let data = try? container.decode(InstantAvailabilityData.self) { - self.data = data - } - } -} - -struct InstantAvailabilityData: Codable, Sendable { - var rd: [[String: InstantAvailabilityInfo]] -} - -struct InstantAvailabilityInfo: Codable, Sendable { - var filename: String - var filesize: Int + if let data = try? container.decode(InstantAvailabilityData.self) { + self.data = data + } + } } // MARK: - Instant Availability client side structures +struct InstantAvailabilityData: Codable, Sendable { + var rd: [[String: InstantAvailabilityInfo]] +} + +struct InstantAvailabilityInfo: Codable, Sendable { + var filename: String + var filesize: Int +} + public struct RealDebridIA: Codable, Hashable, Sendable { - let hash: String - let expiryTimeStamp: Double - var files: [RealDebridIAFile] = [] - var batches: [RealDebridIABatch] = [] + let hash: String + let expiryTimeStamp: Double + var files: [RealDebridIAFile] = [] + var batches: [RealDebridIABatch] = [] } public struct RealDebridIABatch: Codable, Hashable, Sendable { - let files: [RealDebridIABatchFile] + let files: [RealDebridIABatchFile] } public struct RealDebridIABatchFile: Codable, Hashable, Sendable { - let id: Int - let fileName: String + let id: Int + let fileName: String } public struct RealDebridIAFile: Codable, Hashable, Sendable { - let name: String - let batchIndex: Int - let batchFileIndex: Int + let name: String + let batchIndex: Int + let batchFileIndex: Int } public enum RealDebridIAStatus: Codable, Hashable, Sendable { - case full - case partial - case none + case full + case partial + case none } // MARK: - addMagnet endpoint public struct AddMagnetResponse: Codable, Sendable { - let id: String - let uri: String + let id: String + let uri: String } // MARK: - torrentInfo endpoint struct TorrentInfoResponse: Codable, Sendable { - let id, filename, originalFilename, hash: String - let bytes, originalBytes: Int - let host: String - let split, progress: Int - let status, added: String - let files: [TorrentInfoFile] - let links: [String] - let ended: String? - let speed: Int? - let seeders: Int? + let id, filename, originalFilename, hash: String + let bytes, originalBytes: Int + let host: String + let split, progress: Int + let status, added: String + let files: [TorrentInfoFile] + let links: [String] + let ended: String? + let speed: Int? + let seeders: Int? - enum CodingKeys: String, CodingKey { - case id, filename - case originalFilename = "original_filename" - case hash, bytes - case originalBytes = "original_bytes" - case host, split, progress, status, added, files, links, ended, speed, seeders - } + enum CodingKeys: String, CodingKey { + case id, filename + case originalFilename = "original_filename" + case hash, bytes + case originalBytes = "original_bytes" + case host, split, progress, status, added, files, links, ended, speed, seeders + } } struct TorrentInfoFile: Codable, Sendable { - let id: Int - let path: String - let bytes, selected: Int + let id: Int + let path: String + let bytes, selected: Int } public struct UserTorrentsResponse: Codable, Sendable { - let id, filename, hash: String - let bytes: Int - let host: String - let split, progress: Int - let status, added: String - let links: [String] - let speed, seeders: Int? - let ended: String? + let id, filename, hash: String + let bytes: Int + let host: String + let split, progress: Int + let status, added: String + let links: [String] + let speed, seeders: Int? + let ended: String? } // MARK: - unrestrictLink endpoint struct UnrestrictLinkResponse: Codable, Sendable { - let id, filename: String - let mimeType: String? - let filesize: Int - let link: String - let host: String - let hostIcon: String - let chunks, crc: Int - let download: String - let streamable: Int + let id, filename: String + let mimeType: String? + let filesize: Int + let link: String + let host: String + let hostIcon: String + let chunks, crc: Int + let download: String + let streamable: Int - enum CodingKeys: String, CodingKey { - case id, filename, mimeType, filesize, link, host - case hostIcon = "host_icon" - case chunks, crc, download, streamable - } + enum CodingKeys: String, CodingKey { + case id, filename, mimeType, filesize, link, host + case hostIcon = "host_icon" + case chunks, crc, download, streamable + } } // MARK: - User downloads list public struct UserDownloadsResponse: Codable, Sendable { - let id, filename: String - let mimeType: String? - let filesize: Int - let link: String - let host: String - let hostIcon: String - let chunks: Int - let download: String - let streamable: Int - let generated: String + let id, filename: String + let mimeType: String? + let filesize: Int + let link: String + let host: String + let hostIcon: String + let chunks: Int + let download: String + let streamable: Int + let generated: String - enum CodingKeys: String, CodingKey { - case id, filename, mimeType, filesize, link, host - case hostIcon = "host_icon" - case chunks, download, streamable, generated - } + enum CodingKeys: String, CodingKey { + case id, filename, mimeType, filesize, link, host + case hostIcon = "host_icon" + case chunks, download, streamable, generated + } } diff --git a/Ferrite/ViewModels/BackupManager.swift b/Ferrite/ViewModels/BackupManager.swift index dbc68c9..045ecf9 100644 --- a/Ferrite/ViewModels/BackupManager.swift +++ b/Ferrite/ViewModels/BackupManager.swift @@ -177,7 +177,7 @@ public class BackupManager: ObservableObject { do { try FileManager.default.removeItem(at: backupUrl) - if let index = index { + if let index { backupUrls.remove(at: index) } else { backupUrls.removeAll(where: { $0 == backupUrl }) diff --git a/Ferrite/ViewModels/DebridManager.swift b/Ferrite/ViewModels/DebridManager.swift index 42ccccd..f5a85bc 100644 --- a/Ferrite/ViewModels/DebridManager.swift +++ b/Ferrite/ViewModels/DebridManager.swift @@ -82,7 +82,7 @@ public class DebridManager: ObservableObject { } public func matchSearchResult(result: SearchResult?) -> RealDebridIAStatus { - guard let result = result else { + guard let result else { return .none } diff --git a/Ferrite/ViewModels/ScrapingViewModel.swift b/Ferrite/ViewModels/ScrapingViewModel.swift index 2e217d3..fce8a84 100644 --- a/Ferrite/ViewModels/ScrapingViewModel.swift +++ b/Ferrite/ViewModels/ScrapingViewModel.swift @@ -74,7 +74,7 @@ class ScrapingViewModel: ObservableObject { fallbackUrls: source.fallbackUrls ) - if let data = data, + if let data, let html = String(data: data, encoding: .utf8) { let sourceResults = await scrapeHtml(source: source, baseUrl: baseUrl, html: html) @@ -99,7 +99,7 @@ class ScrapingViewModel: ObservableObject { ) } - if let data = data, + if let data, let rss = String(data: data, encoding: .utf8) { let sourceResults = await scrapeRss(source: source, rss: rss) @@ -145,7 +145,7 @@ class ScrapingViewModel: ObservableObject { fallbackUrls: source.fallbackUrls ) - if let data = data { + if let data { let sourceResults = await scrapeJson(source: source, jsonData: data) tempResults += sourceResults } @@ -170,7 +170,7 @@ class ScrapingViewModel: ObservableObject { return data } - if let fallbackUrls = fallbackUrls { + if let fallbackUrls { for fallbackUrl in fallbackUrls { if let data = await fetchWebsiteData(urlString: fallbackUrl + replacedSearchUrl) { return data @@ -359,7 +359,7 @@ class ScrapingViewModel: ObservableObject { } } } else if - let searchResult = searchResult, + let searchResult, let magnetLink = searchResult.magnetLink, magnetLink.starts(with: "magnet:"), !tempResults.contains(searchResult) @@ -404,7 +404,7 @@ class ScrapingViewModel: ObservableObject { if let magnetLinkParser = jsonParser.magnetLink, existingSearchResult?.magnetLink == nil { let rawLink = result[magnetLinkParser.query.components(separatedBy: ".")].rawValue link = rawLink is NSNull ? nil : String(describing: rawLink) - } else if let magnetHash = magnetHash { + } else if let magnetHash { link = generateMagnetLink(magnetHash: magnetHash, title: title, trackers: source.trackers) } @@ -506,7 +506,7 @@ class ScrapingViewModel: ObservableObject { discriminator: magnetLinkParser.discriminator, regexString: magnetLinkParser.regex ) - } else if let magnetHash = magnetHash { + } else if let magnetHash { link = generateMagnetLink(magnetHash: magnetHash, title: title, trackers: source.trackers) } else { continue @@ -586,7 +586,7 @@ class ScrapingViewModel: ObservableObject { parsedValue = try item.getElementsByTag(query).first()?.text() default: // If there's a key/value to lookup the attribute with, query it. Othewise assume the value is in the same attribute - if let discriminator = discriminator { + if let discriminator { let containerElement = try item.getElementsByAttributeValue(discriminator, query).first() parsedValue = try containerElement?.attr(attribute) } else { @@ -596,8 +596,8 @@ class ScrapingViewModel: ObservableObject { } // A capture group must be used in the provided regex - if let regexString = regexString, - let parsedValue = parsedValue, + if let regexString, + let parsedValue, let regexValue = try? Regex(regexString).firstMatch(in: parsedValue)?.groups[safe: 0]?.value { return regexValue @@ -777,8 +777,8 @@ class ScrapingViewModel: ObservableObject { } // A capture group must be used in the provided regex - if let regexString = regexString, - let parsedValue = parsedValue, + if let regexString, + let parsedValue, let regexValue = try? Regex(regexString).firstMatch(in: parsedValue)?.groups[safe: 0]?.value { return regexValue @@ -791,10 +791,10 @@ class ScrapingViewModel: ObservableObject { public func fetchMagnetHash(magnetLink: String? = nil, existingHash: String? = nil) -> String? { var magnetHash: String - if let existingHash = existingHash { + if let existingHash { magnetHash = existingHash } else if - let magnetLink = magnetLink, + let magnetLink, let firstSplit = magnetLink.split(separator: ":")[safe: 3], let tempHash = firstSplit.split(separator: "&")[safe: 0] { @@ -839,11 +839,11 @@ class ScrapingViewModel: ObservableObject { magnetLinkArray.append(magnetHash) - if let title = title, let encodedTitle = title.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) { + if let title, let encodedTitle = title.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) { magnetLinkArray.append("&dn=\(encodedTitle)") } - if let trackers = trackers { + if let trackers { for trackerUrl in trackers { if URL(string: trackerUrl) != nil, let encodedUrlString = trackerUrl.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) diff --git a/Ferrite/ViewModels/SourceManager.swift b/Ferrite/ViewModels/SourceManager.swift index 8c8d0e2..de8989f 100644 --- a/Ferrite/ViewModels/SourceManager.swift +++ b/Ferrite/ViewModels/SourceManager.swift @@ -71,7 +71,7 @@ public class SourceManager: ObservableObject { // Checks if the current app version is supported by the source func checkAppVersion(minVersion: String?) -> Bool { // If there's no min version, assume that every version is supported - guard let minVersion = minVersion else { + guard let minVersion else { return true } @@ -385,7 +385,7 @@ public class SourceManager: ObservableObject { let (data, _) = try await URLSession.shared.data(for: URLRequest(url: URL(string: sourceUrl)!)) let rawResponse = try JSONDecoder().decode(SourceListJson.self, from: data) - if let existingSourceList = existingSourceList { + if let existingSourceList { existingSourceList.urlString = sourceUrl existingSourceList.name = rawResponse.name existingSourceList.author = rawResponse.author diff --git a/Ferrite/ViewModels/ToastViewModel.swift b/Ferrite/ViewModels/ToastViewModel.swift index e35d052..d3f1704 100644 --- a/Ferrite/ViewModels/ToastViewModel.swift +++ b/Ferrite/ViewModels/ToastViewModel.swift @@ -36,7 +36,7 @@ class ToastViewModel: ObservableObject { @Published var showToast: Bool = false public func updateToastDescription(_ description: String, newToastType: ToastType? = nil) { - if let newToastType = newToastType { + if let newToastType { toastType = newToastType } diff --git a/Ferrite/Views/CommonViews/AlertButton.swift b/Ferrite/Views/CommonViews/AlertButton.swift index 19cf66d..664317a 100644 --- a/Ferrite/Views/CommonViews/AlertButton.swift +++ b/Ferrite/Views/CommonViews/AlertButton.swift @@ -37,7 +37,7 @@ struct AlertButton: Identifiable { } func toActionButton() -> Alert.Button { - if let role = role { + if let role { switch role { case .cancel: return .cancel(Text(label)) @@ -57,7 +57,7 @@ struct AlertButton: Identifiable { @available(iOS 15.0, *) func toButtonRole(_ role: Role?) -> ButtonRole? { - if let role = role { + if let role { switch role { case .destructive: return .destructive diff --git a/Ferrite/Views/CommonViews/Backport.swift b/Ferrite/Views/CommonViews/Backport.swift index e5077e1..d57643a 100644 --- a/Ferrite/Views/CommonViews/Backport.swift +++ b/Ferrite/Views/CommonViews/Backport.swift @@ -32,7 +32,7 @@ extension Backport where Content: View { } }, message: { - if let message = message { + if let message { Text(message) } } @@ -75,7 +75,7 @@ extension Backport where Content: View { button.toButtonView() } } message: { - if let message = message { + if let message { Text(message) } } diff --git a/Ferrite/Views/CommonViews/ListRowViews.swift b/Ferrite/Views/CommonViews/ListRowViews.swift index 80e736f..60cf80a 100644 --- a/Ferrite/Views/CommonViews/ListRowViews.swift +++ b/Ferrite/Views/CommonViews/ListRowViews.swift @@ -64,7 +64,7 @@ struct ListRowTextView: View { Spacer() - if let rightText = rightText { + if let rightText { Text(rightText) } else { Image(systemName: rightSymbol!) diff --git a/Ferrite/Views/SettingsViews/SettingsSourceListView.swift b/Ferrite/Views/SettingsViews/SettingsSourceListView.swift index cc1032e..7ab13d4 100644 --- a/Ferrite/Views/SettingsViews/SettingsSourceListView.swift +++ b/Ferrite/Views/SettingsViews/SettingsSourceListView.swift @@ -64,6 +64,13 @@ struct SettingsSourceListView: View { } } } + .onDelete { offsets in + for index in offsets { + if let list = sourceLists[safe: index] { + PersistenceController.shared.delete(list, context: backgroundContext) + } + } + } } .listStyle(.insetGrouped) .inlinedList()