From d7d01465d8c2317baa7458c871a5f9a734089f31 Mon Sep 17 00:00:00 2001 From: kingbri Date: Sun, 14 Aug 2022 21:36:34 -0400 Subject: [PATCH] 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") }