Ferrite: WIP iOS 14 backport
Signed-off-by: kingbri <bdashore3@gmail.com>
This commit is contained in:
parent
9b12671a97
commit
d7d01465d8
15 changed files with 209 additions and 131 deletions
|
|
@ -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 = "<group>"; };
|
||||
0C79DC052899AF3C003F1C5A /* SourceSeedLeech+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceSeedLeech+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
0C79DC062899AF3C003F1C5A /* SourceSeedLeech+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceSeedLeech+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||
0C7D11FB28AA01E900ED92DB /* DynamicAccentColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicAccentColor.swift; sourceTree = "<group>"; };
|
||||
0C7D11FD28AA03FE00ED92DB /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = "<group>"; };
|
||||
0C84F4762895BE680074B7C9 /* FerriteDB.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = FerriteDB.xcdatamodel; sourceTree = "<group>"; };
|
||||
0C84F47A2895BFED0074B7C9 /* Source+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Source+CoreDataClass.swift"; sourceTree = "<group>"; };
|
||||
0C84F47B2895BFED0074B7C9 /* Source+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Source+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||
|
|
@ -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 = "<group>";
|
||||
|
|
@ -240,6 +245,7 @@
|
|||
0CA148CA288903F000DE2211 /* Data.swift */,
|
||||
0CA148CB288903F000DE2211 /* Task.swift */,
|
||||
0C32FB542890D1BF002BD219 /* UIApplication.swift */,
|
||||
0C7D11FD28AA03FE00ED92DB /* View.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
16
Ferrite/Extensions/View.swift
Normal file
16
Ferrite/Extensions/View.swift
Normal file
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
import SwiftUI
|
||||
|
||||
struct AboutView: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Image("AppImage")
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
22
Ferrite/Views/CommonViews/DynamicAccentColor.swift
Normal file
22
Ferrite/Views/CommonViews/DynamicAccentColor.swift
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ?? ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,11 +36,13 @@ struct SourcesView: View {
|
|||
return tempSources
|
||||
}
|
||||
|
||||
@State private var viewTask: Task<Void, Never>? = 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")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue