From cb608c05fc2f7acc2359c17ac58295b819a79606 Mon Sep 17 00:00:00 2001 From: kingbri Date: Sun, 14 Aug 2022 21:36:34 -0400 Subject: [PATCH 1/6] Ferrite: WIP iOS 14 backport Signed-off-by: kingbri --- Ferrite.xcodeproj/project.pbxproj | 36 +++++---- Ferrite/Extensions/View.swift | 16 ++++ Ferrite/ViewModels/NavigationViewModel.swift | 15 +++- Ferrite/Views/AboutView.swift | 2 - Ferrite/Views/BatchChoiceView.swift | 7 +- .../CommonViews/DynamicAccentColor.swift | 22 ++++++ Ferrite/Views/CommonViews/GroupBoxStyle.swift | 2 +- Ferrite/Views/ContentView.swift | 71 ++++++++++++------ Ferrite/Views/LoginWebView.swift | 5 +- Ferrite/Views/MagnetChoiceView.swift | 31 +++++--- Ferrite/Views/SearchResultsView.swift | 22 ++---- Ferrite/Views/SettingsView.swift | 6 +- .../SettingsViews/SourceListEditorView.swift | 6 +- .../SourceViews/SourceSettingsView.swift | 74 ++++++++----------- Ferrite/Views/SourcesView.swift | 25 +++++-- 15 files changed, 209 insertions(+), 131 deletions(-) create mode 100644 Ferrite/Extensions/View.swift create mode 100644 Ferrite/Views/CommonViews/DynamicAccentColor.swift diff --git a/Ferrite.xcodeproj/project.pbxproj b/Ferrite.xcodeproj/project.pbxproj index cc3dcb4..d5ac462 100644 --- a/Ferrite.xcodeproj/project.pbxproj +++ b/Ferrite.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 0C64A4B4288903680079976D /* Base32 in Frameworks */ = {isa = PBXBuildFile; productRef = 0C64A4B3288903680079976D /* Base32 */; }; 0C64A4B7288903880079976D /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0C64A4B6288903880079976D /* KeychainSwift */; }; 0C733287289C4C820058D1FE /* SourceSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C733286289C4C820058D1FE /* SourceSettingsView.swift */; }; + 0C7376F028A97D1400D60918 /* SwiftUIX in Frameworks */ = {isa = PBXBuildFile; productRef = 0C7376EF28A97D1400D60918 /* SwiftUIX */; }; 0C750744289B003E004B3906 /* SourceRssParser+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C750742289B003E004B3906 /* SourceRssParser+CoreDataClass.swift */; }; 0C750745289B003E004B3906 /* SourceRssParser+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C750743289B003E004B3906 /* SourceRssParser+CoreDataProperties.swift */; }; 0C794B67289DACB600DD1CC8 /* SourceUpdateButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C794B66289DACB600DD1CC8 /* SourceUpdateButtonView.swift */; }; @@ -28,6 +29,8 @@ 0C794B6D289EFA2E00DD1CC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0C794B6C289EFA2E00DD1CC8 /* LaunchScreen.storyboard */; }; 0C79DC072899AF3C003F1C5A /* SourceSeedLeech+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C79DC052899AF3C003F1C5A /* SourceSeedLeech+CoreDataClass.swift */; }; 0C79DC082899AF3C003F1C5A /* SourceSeedLeech+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C79DC062899AF3C003F1C5A /* SourceSeedLeech+CoreDataProperties.swift */; }; + 0C7D11FC28AA01E900ED92DB /* DynamicAccentColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7D11FB28AA01E900ED92DB /* DynamicAccentColor.swift */; }; + 0C7D11FE28AA03FE00ED92DB /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7D11FD28AA03FE00ED92DB /* View.swift */; }; 0C84F4772895BE680074B7C9 /* FerriteDB.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F4752895BE680074B7C9 /* FerriteDB.xcdatamodeld */; }; 0C84F4822895BFED0074B7C9 /* Source+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47A2895BFED0074B7C9 /* Source+CoreDataClass.swift */; }; 0C84F4832895BFED0074B7C9 /* Source+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47B2895BFED0074B7C9 /* Source+CoreDataProperties.swift */; }; @@ -35,7 +38,6 @@ 0C84F4852895BFED0074B7C9 /* SourceHtmlParser+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47D2895BFED0074B7C9 /* SourceHtmlParser+CoreDataProperties.swift */; }; 0C84F4862895BFED0074B7C9 /* SourceList+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47E2895BFED0074B7C9 /* SourceList+CoreDataClass.swift */; }; 0C84F4872895BFED0074B7C9 /* SourceList+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C84F47F2895BFED0074B7C9 /* SourceList+CoreDataProperties.swift */; }; - 0C90E32C2888E5D000C0BC89 /* ActivityView in Frameworks */ = {isa = PBXBuildFile; productRef = 0C90E32B2888E5D000C0BC89 /* ActivityView */; }; 0C95D8D828A55B03005E22B3 /* DefaultActionsPickerViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C95D8D728A55B03005E22B3 /* DefaultActionsPickerViews.swift */; }; 0C95D8DA28A55BB6005E22B3 /* SettingsModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C95D8D928A55BB6005E22B3 /* SettingsModels.swift */; }; 0CA05457288EE58200850554 /* SettingsSourceListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA05456288EE58200850554 /* SettingsSourceListView.swift */; }; @@ -88,6 +90,8 @@ 0C794B6C289EFA2E00DD1CC8 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 0C79DC052899AF3C003F1C5A /* SourceSeedLeech+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceSeedLeech+CoreDataClass.swift"; sourceTree = ""; }; 0C79DC062899AF3C003F1C5A /* SourceSeedLeech+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceSeedLeech+CoreDataProperties.swift"; sourceTree = ""; }; + 0C7D11FB28AA01E900ED92DB /* DynamicAccentColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicAccentColor.swift; sourceTree = ""; }; + 0C7D11FD28AA03FE00ED92DB /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; 0C84F4762895BE680074B7C9 /* FerriteDB.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = FerriteDB.xcdatamodel; sourceTree = ""; }; 0C84F47A2895BFED0074B7C9 /* Source+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Source+CoreDataClass.swift"; sourceTree = ""; }; 0C84F47B2895BFED0074B7C9 /* Source+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Source+CoreDataProperties.swift"; sourceTree = ""; }; @@ -134,9 +138,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0C90E32C2888E5D000C0BC89 /* ActivityView in Frameworks */, 0C64A4B4288903680079976D /* Base32 in Frameworks */, 0C4CFC462897030D00AD9FAD /* Regex in Frameworks */, + 0C7376F028A97D1400D60918 /* SwiftUIX in Frameworks */, 0C64A4B7288903880079976D /* KeychainSwift in Frameworks */, 0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */, ); @@ -221,6 +225,7 @@ 0CA148C1288903F000DE2211 /* NavView.swift */, 0CFEFCFC288A006200B3F490 /* GroupBoxStyle.swift */, 0C32FB562890D1F2002BD219 /* ListRowViews.swift */, + 0C7D11FB28AA01E900ED92DB /* DynamicAccentColor.swift */, ); path = CommonViews; sourceTree = ""; @@ -240,6 +245,7 @@ 0CA148CA288903F000DE2211 /* Data.swift */, 0CA148CB288903F000DE2211 /* Task.swift */, 0C32FB542890D1BF002BD219 /* UIApplication.swift */, + 0C7D11FD28AA03FE00ED92DB /* View.swift */, ); path = Extensions; sourceTree = ""; @@ -338,10 +344,10 @@ name = Ferrite; packageProductDependencies = ( 0CAF1C7A286F5C8600296F86 /* SwiftSoup */, - 0C90E32B2888E5D000C0BC89 /* ActivityView */, 0C64A4B3288903680079976D /* Base32 */, 0C64A4B6288903880079976D /* KeychainSwift */, 0C4CFC452897030D00AD9FAD /* Regex */, + 0C7376EF28A97D1400D60918 /* SwiftUIX */, ); productName = Torrenter; productReference = 0CAF1C68286F5C0E00296F86 /* Ferrite.app */; @@ -373,10 +379,10 @@ mainGroup = 0CAF1C5F286F5C0D00296F86; packageReferences = ( 0CAF1C79286F5C8600296F86 /* XCRemoteSwiftPackageReference "SwiftSoup" */, - 0C90E32A2888E5D000C0BC89 /* XCRemoteSwiftPackageReference "ActivityView" */, 0C64A4B2288903680079976D /* XCRemoteSwiftPackageReference "Base32" */, 0C64A4B5288903880079976D /* XCRemoteSwiftPackageReference "keychain-swift" */, 0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */, + 0C7376EE28A97D1400D60918 /* XCRemoteSwiftPackageReference "SwiftUIX" */, ); productRefGroup = 0CAF1C69286F5C0E00296F86 /* Products */; projectDirPath = ""; @@ -419,6 +425,7 @@ 0CBC76FD288D914F0054BE44 /* BatchChoiceView.swift in Sources */, 0CF501F2289AE06A0099C785 /* SourceTracker+CoreDataClass.swift in Sources */, 0C32FB552890D1BF002BD219 /* UIApplication.swift in Sources */, + 0C7D11FE28AA03FE00ED92DB /* View.swift in Sources */, 0C0D50E7288DFF850035ECC8 /* SourcesView.swift in Sources */, 0CA148EC288903F000DE2211 /* ContentView.swift in Sources */, 0C95D8D828A55B03005E22B3 /* DefaultActionsPickerViews.swift in Sources */, @@ -439,6 +446,7 @@ 0C4CFC4E28970C8B00AD9FAD /* SourceComplexQuery+CoreDataProperties.swift in Sources */, 0CA148E2288903F000DE2211 /* Data.swift in Sources */, 0C57D4CC289032ED008534E8 /* SearchResultRDView.swift in Sources */, + 0C7D11FC28AA01E900ED92DB /* DynamicAccentColor.swift in Sources */, 0CA05459288EE9E600850554 /* SourceManager.swift in Sources */, 0C84F4772895BE680074B7C9 /* FerriteDB.xcdatamodeld in Sources */, 0C733287289C4C820058D1FE /* SourceSettingsView.swift in Sources */, @@ -513,7 +521,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -567,7 +575,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -596,6 +604,7 @@ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -628,6 +637,7 @@ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -689,12 +699,12 @@ kind = branch; }; }; - 0C90E32A2888E5D000C0BC89 /* XCRemoteSwiftPackageReference "ActivityView" */ = { + 0C7376EE28A97D1400D60918 /* XCRemoteSwiftPackageReference "SwiftUIX" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SwiftUI-Plus/ActivityView.git"; + repositoryURL = "https://github.com/SwiftUIX/SwiftUIX"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.0; + branch = master; + kind = branch; }; }; 0CAF1C79286F5C8600296F86 /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { @@ -723,10 +733,10 @@ package = 0C64A4B5288903880079976D /* XCRemoteSwiftPackageReference "keychain-swift" */; productName = KeychainSwift; }; - 0C90E32B2888E5D000C0BC89 /* ActivityView */ = { + 0C7376EF28A97D1400D60918 /* SwiftUIX */ = { isa = XCSwiftPackageProductDependency; - package = 0C90E32A2888E5D000C0BC89 /* XCRemoteSwiftPackageReference "ActivityView" */; - productName = ActivityView; + package = 0C7376EE28A97D1400D60918 /* XCRemoteSwiftPackageReference "SwiftUIX" */; + productName = SwiftUIX; }; 0CAF1C7A286F5C8600296F86 /* SwiftSoup */ = { isa = XCSwiftPackageProductDependency; diff --git a/Ferrite/Extensions/View.swift b/Ferrite/Extensions/View.swift new file mode 100644 index 0000000..7b7e4cc --- /dev/null +++ b/Ferrite/Extensions/View.swift @@ -0,0 +1,16 @@ +// +// View.swift +// Ferrite +// +// Created by Brian Dashore on 8/15/22. +// + +import SwiftUI + +extension View { + // MARK: Modifiers + + func dynamicAccentColor(_ color: Color) -> some View { + modifier(DynamicAccentColor(color: color)) + } +} diff --git a/Ferrite/ViewModels/NavigationViewModel.swift b/Ferrite/ViewModels/NavigationViewModel.swift index 5cdb6d1..ab97121 100644 --- a/Ferrite/ViewModels/NavigationViewModel.swift +++ b/Ferrite/ViewModels/NavigationViewModel.swift @@ -5,7 +5,6 @@ // Created by Brian Dashore on 7/24/22. // -import ActivityView import SwiftUI enum ViewTab { @@ -28,8 +27,14 @@ class NavigationViewModel: ObservableObject { case batch } + @Published var isEditingSearch: Bool = false + @Published var isSearching: Bool = false + + @Published var hideNavigationBar = false + @Published var currentChoiceSheet: ChoiceSheetType? - @Published var currentActivityItem: ActivityItem? + @Published var activityItems: [Any] = [] + @Published var showActivityView: Bool = false @Published var selectedTab: ViewTab = .search @Published var showSearchProgress: Bool = false @@ -70,7 +75,8 @@ class NavigationViewModel: ObservableObject { } case .shareDownload: if let downloadUrl = URL(string: urlString), currentChoiceSheet == nil { - currentActivityItem = ActivityItem(items: downloadUrl) + activityItems = [downloadUrl] + showActivityView.toggle() } else { toastModel?.toastDescription = "Could not create object for sharing" } @@ -91,7 +97,8 @@ class NavigationViewModel: ObservableObject { } case .shareMagnet: if let magnetUrl = URL(string: searchResult.magnetLink), currentChoiceSheet == nil { - currentActivityItem = ActivityItem(items: magnetUrl) + activityItems = [magnetUrl] + showActivityView.toggle() } else { toastModel?.toastDescription = "Could not create object for sharing" } diff --git a/Ferrite/Views/AboutView.swift b/Ferrite/Views/AboutView.swift index 611b4fa..720d80e 100644 --- a/Ferrite/Views/AboutView.swift +++ b/Ferrite/Views/AboutView.swift @@ -8,8 +8,6 @@ import SwiftUI struct AboutView: View { - @Environment(\.dismiss) var dismiss - var body: some View { VStack { Image("AppImage") diff --git a/Ferrite/Views/BatchChoiceView.swift b/Ferrite/Views/BatchChoiceView.swift index 8722689..3d97be7 100644 --- a/Ferrite/Views/BatchChoiceView.swift +++ b/Ferrite/Views/BatchChoiceView.swift @@ -8,7 +8,7 @@ import SwiftUI struct BatchChoiceView: View { - @Environment(\.dismiss) var dismiss + @Environment(\.presentationMode) var presentationMode @EnvironmentObject var debridManager: DebridManager @EnvironmentObject var scrapingModel: ScrapingViewModel @@ -34,10 +34,11 @@ struct BatchChoiceView: View { } } - dismiss() + presentationMode.wrappedValue.dismiss() } } } + .listStyle(.insetGrouped) .navigationTitle("Select a file") .navigationBarTitleDisplayMode(.inline) .toolbar { @@ -45,7 +46,7 @@ struct BatchChoiceView: View { Button("Done") { debridManager.selectedRealDebridItem = nil - dismiss() + presentationMode.wrappedValue.dismiss() } } } diff --git a/Ferrite/Views/CommonViews/DynamicAccentColor.swift b/Ferrite/Views/CommonViews/DynamicAccentColor.swift new file mode 100644 index 0000000..02a2e79 --- /dev/null +++ b/Ferrite/Views/CommonViews/DynamicAccentColor.swift @@ -0,0 +1,22 @@ +// +// dynamicAccentColor.swift +// Ferrite +// +// Created by Brian Dashore on 8/15/22. +// + +import SwiftUI + +struct DynamicAccentColor: ViewModifier { + let color: Color + + func body(content: Content) -> some View { + if #available(iOS 15, *) { + content + .tint(color) + } else { + content + .accentColor(color) + } + } +} diff --git a/Ferrite/Views/CommonViews/GroupBoxStyle.swift b/Ferrite/Views/CommonViews/GroupBoxStyle.swift index 5bfc686..6398a3b 100644 --- a/Ferrite/Views/CommonViews/GroupBoxStyle.swift +++ b/Ferrite/Views/CommonViews/GroupBoxStyle.swift @@ -14,7 +14,7 @@ struct ErrorGroupBoxStyle: GroupBoxStyle { configuration.content } .padding(10) - .background(Color(uiColor: .secondarySystemGroupedBackground)) + .background(Color(UIColor.secondarySystemGroupedBackground)) .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous)) } } diff --git a/Ferrite/Views/ContentView.swift b/Ferrite/Views/ContentView.swift index ac35939..85f0a3c 100644 --- a/Ferrite/Views/ContentView.swift +++ b/Ferrite/Views/ContentView.swift @@ -5,8 +5,8 @@ // Created by Brian Dashore on 7/1/22. // -import ActivityView import SwiftUI +import SwiftUIX struct ContentView: View { @EnvironmentObject var scrapingModel: ScrapingViewModel @@ -66,38 +66,63 @@ struct ContentView: View { Spacer() } + .padding(.vertical, 5) .padding(.horizontal, 20) SearchResultsView() } - .searchable(text: $scrapingModel.searchText) - .onSubmit(of: .search) { - scrapingModel.runningSearchTask = Task { - navModel.showSearchProgress = true - - await scrapingModel.scanSources(sources: sources.compactMap { $0 }) - - if realDebridEnabled, !scrapingModel.searchResults.isEmpty { - await debridManager.populateDebridHashes(scrapingModel.searchResults) + .sheet(item: $navModel.currentChoiceSheet) { item in + Group { + switch item { + case .magnet: + MagnetChoiceView() + .environmentObject(debridManager) + .environmentObject(scrapingModel) + .environmentObject(navModel) + case .batch: + BatchChoiceView() + .environmentObject(debridManager) + .environmentObject(scrapingModel) + .environmentObject(navModel) } - - navModel.showSearchProgress = false + } + .dynamicAccentColor(.primary) + } + .sheet(isPresented: $navModel.showActivityView) { + if #available(iOS 16, *) { + AppActivityView(activityItems: navModel.activityItems) + .presentationDetents([.medium]) + } else { + AppActivityView(activityItems: navModel.activityItems) } } .navigationTitle("Search") - } - .sheet(item: $navModel.currentChoiceSheet) { item in - Group { - switch item { - case .magnet: - MagnetChoiceView() - case .batch: - BatchChoiceView() - } + .navigationSearchBar { + SearchBar("Search", text: $scrapingModel.searchText, isEditing: $navModel.isEditingSearch, + onCommit: { + scrapingModel.runningSearchTask = Task { + navModel.isSearching = true + navModel.showSearchProgress = true + + await scrapingModel.scanSources(sources: sources.compactMap { $0 }) + + if realDebridEnabled, !scrapingModel.searchResults.isEmpty { + await debridManager.populateDebridHashes(scrapingModel.searchResults) + } + + navModel.showSearchProgress = false + } + }) + .showsCancelButton(navModel.isEditingSearch || navModel.isSearching) + .onCancel { + scrapingModel.searchResults = [] + scrapingModel.runningSearchTask?.cancel() + scrapingModel.runningSearchTask = nil + navModel.isSearching = false + scrapingModel.searchText = "" + } } - .tint(.primary) } - .activitySheet($navModel.currentActivityItem) } } diff --git a/Ferrite/Views/LoginWebView.swift b/Ferrite/Views/LoginWebView.swift index a65a683..4a8009f 100644 --- a/Ferrite/Views/LoginWebView.swift +++ b/Ferrite/Views/LoginWebView.swift @@ -8,8 +8,9 @@ import SwiftUI struct LoginWebView: View { - @Environment(\.dismiss) var dismiss + @Environment(\.presentationMode) var presentationMode var url: URL + var body: some View { NavView { WebView(url: url) @@ -18,7 +19,7 @@ struct LoginWebView: View { .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("Done") { - dismiss() + presentationMode.wrappedValue.dismiss() } } } diff --git a/Ferrite/Views/MagnetChoiceView.swift b/Ferrite/Views/MagnetChoiceView.swift index b08f674..a71bb66 100644 --- a/Ferrite/Views/MagnetChoiceView.swift +++ b/Ferrite/Views/MagnetChoiceView.swift @@ -5,11 +5,11 @@ // Created by Brian Dashore on 7/20/22. // -import ActivityView import SwiftUI +import SwiftUIX struct MagnetChoiceView: View { - @Environment(\.dismiss) var dismiss + @Environment(\.presentationMode) var presentationMode @EnvironmentObject var scrapingModel: ScrapingViewModel @EnvironmentObject var debridManager: DebridManager @@ -20,13 +20,13 @@ struct MagnetChoiceView: View { @State private var showActivityView = false @State private var showLinkCopyAlert = false @State private var showMagnetCopyAlert = false - @State private var activityItem: ActivityItem? + @State private var activityItems: [Any] = [] var body: some View { NavView { Form { if realDebridEnabled, debridManager.matchSearchResult(result: scrapingModel.selectedSearchResult) != .none { - Section("Real Debrid options") { + Section(header: "Real Debrid options") { ListRowButtonView("Play on Outplayer", systemImage: "arrow.up.forward.app.fill") { navModel.runDebridAction(action: .outplayer, urlString: debridManager.realDebridDownloadUrl) } @@ -52,16 +52,15 @@ struct MagnetChoiceView: View { } ListRowButtonView("Share download URL", systemImage: "square.and.arrow.up.fill") { - guard let url = URL(string: debridManager.realDebridDownloadUrl) else { - return + if let url = URL(string: debridManager.realDebridDownloadUrl) { + activityItems = [url] + navModel.showActivityView.toggle() } - - activityItem = ActivityItem(items: url) } } } - Section("Magnet options") { + Section(header: "Magnet options") { ListRowButtonView("Copy magnet", systemImage: "doc.on.doc.fill") { UIPasteboard.general.string = scrapingModel.selectedSearchResult?.magnetLink showMagnetCopyAlert.toggle() @@ -76,7 +75,8 @@ struct MagnetChoiceView: View { ListRowButtonView("Share magnet", systemImage: "square.and.arrow.up.fill") { if let result = scrapingModel.selectedSearchResult, let url = URL(string: result.magnetLink) { - activityItem = ActivityItem(items: url) + activityItems = [url] + navModel.showActivityView.toggle() } } @@ -87,7 +87,14 @@ struct MagnetChoiceView: View { } } } - .activitySheet($activityItem) + .sheet(isPresented: $navModel.showActivityView) { + if #available(iOS 16, *) { + AppActivityView(activityItems: activityItems) + .presentationDetents([.medium]) + } else { + AppActivityView(activityItems: activityItems) + } + } .navigationTitle("Link actions") .navigationBarTitleDisplayMode(.inline) .toolbar { @@ -95,7 +102,7 @@ struct MagnetChoiceView: View { Button("Done") { debridManager.realDebridDownloadUrl = "" - dismiss() + presentationMode.wrappedValue.dismiss() } } } diff --git a/Ferrite/Views/SearchResultsView.swift b/Ferrite/Views/SearchResultsView.swift index d5561a8..913d01e 100644 --- a/Ferrite/Views/SearchResultsView.swift +++ b/Ferrite/Views/SearchResultsView.swift @@ -8,9 +8,6 @@ import SwiftUI struct SearchResultsView: View { - @Environment(\.isSearching) var isSearching - @Environment(\.dismissSearch) var dismissSearch - @EnvironmentObject var scrapingModel: ScrapingViewModel @EnvironmentObject var debridManager: DebridManager @EnvironmentObject var navModel: NavigationViewModel @@ -43,7 +40,7 @@ struct SearchResultsView: View { .font(.callout) .fixedSize(horizontal: false, vertical: true) } - .tint(.primary) + .dynamicAccentColor(.primary) .padding(.bottom, 5) SearchResultRDView(result: result) @@ -51,6 +48,7 @@ struct SearchResultsView: View { } } } + .listStyle(.insetGrouped) .overlay { if scrapingModel.searchResults.isEmpty { if navModel.showSearchProgress { @@ -58,7 +56,7 @@ struct SearchResultsView: View { ProgressView() Text("Loading \(scrapingModel.currentSourceName ?? "")") } - } else if isSearching, scrapingModel.runningSearchTask != nil { + } else if navModel.isSearching, scrapingModel.runningSearchTask != nil { Text("No results found") } } @@ -66,25 +64,19 @@ struct SearchResultsView: View { .onChange(of: navModel.selectedTab) { tab in // Cancel the search if tab is switched while search is in progress if tab != .search, navModel.showSearchProgress { + scrapingModel.searchResults = [] scrapingModel.runningSearchTask?.cancel() scrapingModel.runningSearchTask = nil - dismissSearch() + navModel.isSearching = false + scrapingModel.searchText = "" } } .onChange(of: scrapingModel.searchResults) { _ in // Cleans up any leftover search results in the event of an abrupt cancellation - if !isSearching { + if !navModel.isSearching { scrapingModel.searchResults = [] } } - .onChange(of: isSearching) { changed in - // Clear the results array and cleans up search tasks on cancel - if !changed { - scrapingModel.searchResults = [] - scrapingModel.runningSearchTask?.cancel() - scrapingModel.runningSearchTask = nil - } - } } } diff --git a/Ferrite/Views/SettingsView.swift b/Ferrite/Views/SettingsView.swift index bc49f05..61c4d05 100644 --- a/Ferrite/Views/SettingsView.swift +++ b/Ferrite/Views/SettingsView.swift @@ -22,7 +22,7 @@ struct SettingsView: View { var body: some View { NavView { Form { - Section("Debrid services") { + Section(header: "Debrid services") { HStack { Text("Real Debrid") Spacer() @@ -42,11 +42,11 @@ struct SettingsView: View { } } - Section("Source management") { + Section(header: "Source management") { NavigationLink("Source lists", destination: SettingsSourceListView()) } - Section("Default actions") { + Section(header: "Default actions") { if realDebridEnabled { NavigationLink( destination: DebridActionPickerView(), diff --git a/Ferrite/Views/SettingsViews/SourceListEditorView.swift b/Ferrite/Views/SettingsViews/SourceListEditorView.swift index 004e3fe..9db11c7 100644 --- a/Ferrite/Views/SettingsViews/SourceListEditorView.swift +++ b/Ferrite/Views/SettingsViews/SourceListEditorView.swift @@ -8,7 +8,7 @@ import SwiftUI struct SourceListEditorView: View { - @Environment(\.dismiss) var dismiss + @Environment(\.presentationMode) var presentationMode @EnvironmentObject var navModel: NavigationViewModel @EnvironmentObject var sourceManager: SourceManager @@ -42,7 +42,7 @@ struct SourceListEditorView: View { .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button("Cancel") { - dismiss() + presentationMode.wrappedValue.dismiss() } } @@ -53,7 +53,7 @@ struct SourceListEditorView: View { sourceUrl: sourceUrl, existingSourceList: navModel.selectedSourceList ) { - dismiss() + presentationMode.wrappedValue.dismiss() } } } diff --git a/Ferrite/Views/SourceViews/SourceSettingsView.swift b/Ferrite/Views/SourceViews/SourceSettingsView.swift index 0e2c524..4a6a8a6 100644 --- a/Ferrite/Views/SourceViews/SourceSettingsView.swift +++ b/Ferrite/Views/SourceViews/SourceSettingsView.swift @@ -8,15 +8,15 @@ import SwiftUI struct SourceSettingsView: View { - @Environment(\.dismiss) var dismiss + @Environment(\.presentationMode) var presentationMode @EnvironmentObject var navModel: NavigationViewModel var body: some View { NavView { - Form { + List { if let selectedSource = navModel.selectedSource { - Section("Info") { + Section(header: "Info") { VStack(alignment: .leading, spacing: 5) { HStack { Text(selectedSource.name) @@ -53,6 +53,7 @@ struct SourceSettingsView: View { SourceSettingsMethodView(selectedSource: selectedSource) } } + .listStyle(.insetGrouped) .onDisappear { PersistenceController.shared.save() } @@ -60,7 +61,7 @@ struct SourceSettingsView: View { .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("Done") { - dismiss() + presentationMode.wrappedValue.dismiss() } } } @@ -71,29 +72,25 @@ struct SourceSettingsView: View { struct SourceSettingsBaseUrlView: View { @ObservedObject var selectedSource: Source - @FocusState var baseUrlFocused: Bool - @State private var tempBaseUrl: String = "" var body: some View { Section( header: Text("Base URL"), footer: Text("Enter the base URL of your server.") ) { - TextField("https://...", text: $tempBaseUrl) - .keyboardType(.URL) - .focused($baseUrlFocused) - .onChange(of: baseUrlFocused) { isFocused in - if !isFocused { - if tempBaseUrl.last == "/" { - selectedSource.baseUrl = String(tempBaseUrl.dropLast()) - } else { - selectedSource.baseUrl = tempBaseUrl - } + TextField("https://...", text: $tempBaseUrl, onEditingChanged: { isFocused in + if !isFocused { + if tempBaseUrl.last == "/" { + selectedSource.baseUrl = String(tempBaseUrl.dropLast()) + } else { + selectedSource.baseUrl = tempBaseUrl } } - .onAppear { - tempBaseUrl = selectedSource.baseUrl ?? "" - } + }) + .keyboardType(.URL) + .onAppear { + tempBaseUrl = selectedSource.baseUrl ?? "" + } } } } @@ -101,9 +98,6 @@ struct SourceSettingsBaseUrlView: View { struct SourceSettingsApiView: View { @ObservedObject var selectedSourceApi: SourceApi - @FocusState var clientIdFieldFocused: Bool - @FocusState var tokenFieldFocused: Bool - @State private var tempClientId: String = "" @State private var tempClientSecret: String = "" @@ -117,31 +111,27 @@ struct SourceSettingsApiView: View { footer: Text("Grab the required API credentials from the website. A client secret can be an API token.") ) { if selectedSourceApi.dynamicClientId { - TextField("Client ID", text: $tempClientId) - .textInputAutocapitalization(.never) - .focused($clientIdFieldFocused) - .onChange(of: clientIdFieldFocused) { isFocused in - if !isFocused { - selectedSourceApi.clientId = tempClientId - } - } - .onAppear { - tempClientId = selectedSourceApi.clientId ?? "" + TextField("Client ID", text: $tempClientId, onEditingChanged: { isFocused in + if !isFocused { + selectedSourceApi.clientId = tempClientId } + }) + .autocapitalization(.none) + .onAppear { + tempClientId = selectedSourceApi.clientId ?? "" + } } if selectedSourceApi.clientSecret != nil { - TextField("Token", text: $tempClientSecret) - .textInputAutocapitalization(.never) - .focused($tokenFieldFocused) - .onChange(of: clientIdFieldFocused) { isFocused in - if !isFocused { - selectedSourceApi.clientSecret = tempClientSecret - } - } - .onAppear { - tempClientSecret = selectedSourceApi.clientSecret ?? "" + TextField("Token", text: $tempClientSecret, onEditingChanged: { isFocused in + if !isFocused { + selectedSourceApi.clientSecret = tempClientSecret } + }) + .autocapitalization(.none) + .onAppear { + tempClientSecret = selectedSourceApi.clientSecret ?? "" + } } } } diff --git a/Ferrite/Views/SourcesView.swift b/Ferrite/Views/SourcesView.swift index 10f08a1..570c92b 100644 --- a/Ferrite/Views/SourcesView.swift +++ b/Ferrite/Views/SourcesView.swift @@ -36,11 +36,13 @@ struct SourcesView: View { return tempSources } + @State private var viewTask: Task? = nil + var body: some View { NavView { List { if !updatedSources.isEmpty { - Section("Updates") { + Section(header: "Updates") { ForEach(updatedSources, id: \.self) { source in SourceUpdateButtonView(updatedSource: source) } @@ -48,13 +50,10 @@ struct SourcesView: View { } if !sources.isEmpty { - Section("Installed") { + Section(header: "Installed") { ForEach(sources, id: \.self) { source in InstalledSourceView(installedSource: source) } - .sheet(isPresented: $navModel.showSourceSettings) { - SourceSettingsView() - } } } @@ -67,7 +66,7 @@ struct SourcesView: View { } ) }) { - Section("Catalog") { + Section(header: "Catalog") { ForEach(sourceManager.availableSources, id: \.self) { availableSource in if !sources.contains( where: { @@ -82,8 +81,18 @@ struct SourcesView: View { } } } - .task { - await sourceManager.fetchSourcesFromUrl() + .listStyle(.insetGrouped) + .sheet(isPresented: $navModel.showSourceSettings) { + SourceSettingsView() + .environmentObject(navModel) + } + .onAppear { + viewTask = Task { + await sourceManager.fetchSourcesFromUrl() + } + } + .onDisappear { + viewTask?.cancel() } .navigationTitle("Sources") } -- 2.45.2 From 0cd822b9fa1676089a9a1af045884822ab0d2ecd Mon Sep 17 00:00:00 2001 From: kingbri Date: Mon, 15 Aug 2022 00:42:02 -0400 Subject: [PATCH 2/6] Update README iOS 14 Signed-off-by: kingbri --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 1306e36..7a90388 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,7 @@ I also wanted to support the use of RealDebrid since there aren't any (free) opt ## What iOS versions are supported? -iOS 15 and up. This is because SwiftUI is very flexible with these versions. I have no intention of backporting Ferrite to iOS 14, so please update if you want to use it. - -However, if you want an immersive browser for your websites with iOS 14 support, please look at my sister app Asobi. +iOS 14 and up. I was able to successfully backport the app! ## Planned features -- 2.45.2 From 96af9eb23b0893ef4b4efc1fa54ffc024a9b4055 Mon Sep 17 00:00:00 2001 From: kingbri Date: Mon, 15 Aug 2022 00:42:10 -0400 Subject: [PATCH 3/6] Remove Sources.md The wiki now exists. Signed-off-by: kingbri --- Sources.md | 124 ----------------------------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 Sources.md diff --git a/Sources.md b/Sources.md deleted file mode 100644 index 56714ab..0000000 --- a/Sources.md +++ /dev/null @@ -1,124 +0,0 @@ -# Sources - -This is a tentative guide for Ferrite sources. The source format can change at any time without warning throughout the duration of the alpha so do not jump the gun if you don't want to. - -## Source lists - -Source lists must adhere to the following template. All of these fields are `required` to properly add a source to Ferrite. - -(Note: Name and author fields are not enforced, but they will be in future versions of Ferrite) - -```json -{ - "name": "Repository name", - "author": "Repository author", - "sources": ["source objects go here"] -} -``` - -## Creating a source object - -Here is a quick template to what a source entry looks like with all the possible parameters. You can copy/paste this template into your editor of choice. I will go through all the keys one-by-one. - -```json -{ - "name": "Website (source) name", - "version": "1", - "baseUrl": "https://sourceurl.com", - "htmlParser": { - "searchUrl": "?q={query}", - "rows": "row selector", - "magnet": { - "query": "magnet selector", - "externalLinkQuery": "https://sourceurl.com/magnetUrl" - "attribute": "href", - "regex": "regex" - }, - "title": { - "query": "title selector", - "attribute": "text", - "regex": "regex" - }, - "size": { - "query": "size selector", - "attribute": "text", - "regex": "regex" - }, - "sl": { - "seeders": "seeder selector", - "leechers": "leecher selector", - "combined": "seeder/leecher ratio selector", - "seederRegex": "regex", - "leecherRegex": "regex" - } - } -} -``` - -### name - -`Required`: This is the name that is shown when the user is looking at a source - -### version - -`Required`: This is the version number of the source. Each update to the source increments the version by 1. Only increment the version when you are sure that the source is ready to be published. - -### baseUrl - -`Required`: The base URL of the website. For example, `https://google.com` is the base URL of Google. DO NOT include the slash on the end of the base URL otherwise the source will break. - -### htmlParser - -`Optional`: The web scraping module for a source. Use this if a source does not have an API and allows scraping! (NOTE: API support will be added in a future build of Ferrite, use the htmlParser for now) - -### searchUrl - -`Required for htmlParser`: The URL given when searching content on a website. For example, when given a URL such as `https://www.google.com/search?q=hello`, the search URL is whatever comes after the base URL (in this case `/search?q=hello`). It is important to include the slash at the beginning otherwise the source will break. - -### rows - -`Required for htmlParser`: The CSS selector for selecting a table row. Most of these sites use HTML tables. Please consult this while web scraping. - -### magnet - -`Required for htmlParser`: A complex query. Please reference complex queries to understand the other keys. Unique keys are provided below: - -- externalLinkQuery: If a magnet link is located on a different page, this fetches the URL required to navigate to that page and fetch the magnet link. - -### title - -`Optional for htmlParser`: This is a complex query. Please reference complex queries to understand the keys - -### size - -`Optional for htmlParser`: This is a complex query. Please reference complex queries to understand the keys - -### sl (seeders and leechers) - -`Optional for htmlParser`: Used to get seeder and leecher values on a website. All the below properties are optional. - -- seeders: The seeder CSS selector - -- leechers: The leecher CSS selector - -- combined: A CSS selector used when seeders and leechers are in one string (ex. `Seeders: 100 / Leechers: 200`) - -- seederRegex: Regex used to strip the seeder value from a string (follows the same rules as complex query regexes) - -- leecherRegex: Regex used to strip the leecher value from a string (follows the same rules as complex query regexes) - -## Complex queries - -These are generic queries used by Ferrite for keys that require a little more information when parsing the contents. Any key that has a complex query disclaimer will always use these parameters: - -- query `Required`: The CSS selector for selecting the element in question - -- attribute `Required`: The attribute to look for after selecting the query (ex. href, title, span). If you want the textContent, use `text` in the attribute parameter. - -- regex `Optional`: Runs regex on the query result before presentation to the user. - - - Do not include the beginning and end slashes in this string (ex. `/regex/`) - - - When using a `\` character, escape it using `\\` - - - This regex must have only one capturing group. [Don't know what a capture group is?](https://www.regular-expressions.info/brackets.html) -- 2.45.2 From f56954ac0021b3fbe97d1d4da1bc0455417b2241 Mon Sep 17 00:00:00 2001 From: kingbri Date: Mon, 15 Aug 2022 20:55:16 -0400 Subject: [PATCH 4/6] Debrid: Don't show sheet on error If a download link isn't set, don't show the choice sheet and present the error instead. Signed-off-by: kingbri --- Ferrite/Views/BatchChoiceView.swift | 8 +++++--- Ferrite/Views/MainView.swift | 1 + Ferrite/Views/SearchResultsView.swift | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Ferrite/Views/BatchChoiceView.swift b/Ferrite/Views/BatchChoiceView.swift index 3d97be7..a251ce8 100644 --- a/Ferrite/Views/BatchChoiceView.swift +++ b/Ferrite/Views/BatchChoiceView.swift @@ -25,9 +25,11 @@ struct BatchChoiceView: View { Task { await debridManager.fetchRdDownload(searchResult: searchResult, iaFile: file) - // The download may complete before this sheet dismisses - try? await Task.sleep(seconds: 1) - navModel.runDebridAction(action: nil, urlString: debridManager.realDebridDownloadUrl) + if !debridManager.realDebridDownloadUrl.isEmpty { + // The download may complete before this sheet dismisses + try? await Task.sleep(seconds: 1) + navModel.runDebridAction(action: nil, urlString: debridManager.realDebridDownloadUrl) + } debridManager.selectedRealDebridFile = nil debridManager.selectedRealDebridItem = nil diff --git a/Ferrite/Views/MainView.swift b/Ferrite/Views/MainView.swift index e3b1c17..d04d0be 100644 --- a/Ferrite/Views/MainView.swift +++ b/Ferrite/Views/MainView.swift @@ -51,6 +51,7 @@ struct MainView: View { } } .font(.caption) + .shadow(radius: 10) .animation(.easeInOut(duration: 0.3), value: toastModel.showToast) } } diff --git a/Ferrite/Views/SearchResultsView.swift b/Ferrite/Views/SearchResultsView.swift index 913d01e..5ded689 100644 --- a/Ferrite/Views/SearchResultsView.swift +++ b/Ferrite/Views/SearchResultsView.swift @@ -26,7 +26,10 @@ struct SearchResultsView: View { case .full: Task { await debridManager.fetchRdDownload(searchResult: result) - navModel.runDebridAction(action: nil, urlString: debridManager.realDebridDownloadUrl) + + if !debridManager.realDebridDownloadUrl.isEmpty { + navModel.runDebridAction(action: nil, urlString: debridManager.realDebridDownloadUrl) + } } case .partial: if debridManager.setSelectedRdResult(result: result) { -- 2.45.2 From 2fce2b5bc599b4e5b26240920745bfae3c1194d6 Mon Sep 17 00:00:00 2001 From: kingbri Date: Mon, 15 Aug 2022 21:18:33 -0400 Subject: [PATCH 5/6] Settings: Fix how modified source lists are saved Since an existing source list is fetched from the ViewContext, save in the scope of that context. This will fix any fetching issues when grabbing sources from the new URL. Signed-off-by: kingbri --- Ferrite/DataManagement/PersistenceController.swift | 4 ++++ Ferrite/ViewModels/SourceManager.swift | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Ferrite/DataManagement/PersistenceController.swift b/Ferrite/DataManagement/PersistenceController.swift index debcc87..ad5ae0d 100644 --- a/Ferrite/DataManagement/PersistenceController.swift +++ b/Ferrite/DataManagement/PersistenceController.swift @@ -46,6 +46,10 @@ struct PersistenceController { backgroundContext.automaticallyMergesChangesFromParent = true backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy try? backgroundContext.setQueryGenerationFrom(.current) + + container.viewContext.automaticallyMergesChangesFromParent = true + container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy + try? container.viewContext.setQueryGenerationFrom(.current) } func save(_ context: NSManagedObjectContext? = nil) { diff --git a/Ferrite/ViewModels/SourceManager.swift b/Ferrite/ViewModels/SourceManager.swift index 2746f07..9cf9971 100644 --- a/Ferrite/ViewModels/SourceManager.swift +++ b/Ferrite/ViewModels/SourceManager.swift @@ -274,6 +274,8 @@ public class SourceManager: ObservableObject { existingSourceList.urlString = sourceUrl existingSourceList.name = rawResponse.name existingSourceList.author = rawResponse.author + + try PersistenceController.shared.container.viewContext.save() } else { let sourceListRequest = SourceList.fetchRequest() let urlPredicate = NSPredicate(format: "urlString == %@", sourceUrl) @@ -293,9 +295,9 @@ public class SourceManager: ObservableObject { newSourceUrl.urlString = sourceUrl newSourceUrl.name = rawResponse.name newSourceUrl.author = rawResponse.author - } - try backgroundContext.save() + try backgroundContext.save() + } return true } catch { -- 2.45.2 From aad063607b5797a07780d0cdb3979a3d6582aa53 Mon Sep 17 00:00:00 2001 From: kingbri Date: Tue, 16 Aug 2022 14:17:01 -0400 Subject: [PATCH 6/6] Ferrite: Bump version Signed-off-by: kingbri --- Ferrite.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Ferrite.xcodeproj/project.pbxproj b/Ferrite.xcodeproj/project.pbxproj index d5ac462..7f8f605 100644 --- a/Ferrite.xcodeproj/project.pbxproj +++ b/Ferrite.xcodeproj/project.pbxproj @@ -591,7 +591,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_ASSET_PATHS = "\"Ferrite/Preview Content\""; DEVELOPMENT_TEAM = 8A74DBQ6S3; ENABLE_PREVIEWS = YES; @@ -609,7 +609,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.3.2; + MARKETING_VERSION = 0.3.3; PRODUCT_BUNDLE_IDENTIFIER = me.kingbri.Ferrite; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -624,7 +624,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 8; DEVELOPMENT_ASSET_PATHS = "\"Ferrite/Preview Content\""; DEVELOPMENT_TEAM = 8A74DBQ6S3; ENABLE_PREVIEWS = YES; @@ -642,7 +642,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.3.2; + MARKETING_VERSION = 0.3.3; PRODUCT_BUNDLE_IDENTIFIER = me.kingbri.Ferrite; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; -- 2.45.2