Compare commits

..

No commits in common. "next" and "default" have entirely different histories.

32 changed files with 249 additions and 73 deletions

View file

@ -41,6 +41,7 @@
0C422E80293542F300486D65 /* PremiumizeModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C422E7F293542F300486D65 /* PremiumizeModels.swift */; }; 0C422E80293542F300486D65 /* PremiumizeModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C422E7F293542F300486D65 /* PremiumizeModels.swift */; };
0C42B5982932F6DD008057A0 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C42B5972932F6DD008057A0 /* Set.swift */; }; 0C42B5982932F6DD008057A0 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C42B5972932F6DD008057A0 /* Set.swift */; };
0C445C62293F9A0B0060744D /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C445C61293F9A0B0060744D /* Bundle.swift */; }; 0C445C62293F9A0B0060744D /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C445C61293F9A0B0060744D /* Bundle.swift */; };
0C448BE929A135F100F4E266 /* Introspect-Static in Frameworks */ = {isa = PBXBuildFile; productRef = 0C448BE829A135F100F4E266 /* Introspect-Static */; };
0C44E2A828D4DDDC007711AE /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C44E2A728D4DDDC007711AE /* Application.swift */; }; 0C44E2A828D4DDDC007711AE /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C44E2A728D4DDDC007711AE /* Application.swift */; };
0C44E2AD28D51C63007711AE /* BackupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C44E2AC28D51C63007711AE /* BackupManager.swift */; }; 0C44E2AD28D51C63007711AE /* BackupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C44E2AC28D51C63007711AE /* BackupManager.swift */; };
0C44E2AF28D52E8A007711AE /* BackupsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C44E2AE28D52E8A007711AE /* BackupsView.swift */; }; 0C44E2AF28D52E8A007711AE /* BackupsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C44E2AE28D52E8A007711AE /* BackupsView.swift */; };
@ -68,6 +69,7 @@
0C6C7C9D29315292002DF910 /* AllDebridModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C6C7C9C29315292002DF910 /* AllDebridModels.swift */; }; 0C6C7C9D29315292002DF910 /* AllDebridModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C6C7C9C29315292002DF910 /* AllDebridModels.swift */; };
0C7075E429D374C50093DB2D /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7075E329D374C50093DB2D /* Color.swift */; }; 0C7075E429D374C50093DB2D /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7075E329D374C50093DB2D /* Color.swift */; };
0C7075E629D3845D0093DB2D /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7075E529D3845D0093DB2D /* ShareSheet.swift */; }; 0C7075E629D3845D0093DB2D /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7075E529D3845D0093DB2D /* ShareSheet.swift */; };
0C70E40228C3CE9C00A5C72D /* ConditionalContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C70E40128C3CE9C00A5C72D /* ConditionalContextMenu.swift */; };
0C70E40628C40C4E00A5C72D /* NotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C70E40528C40C4E00A5C72D /* NotificationCenter.swift */; }; 0C70E40628C40C4E00A5C72D /* NotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C70E40528C40C4E00A5C72D /* NotificationCenter.swift */; };
0C733287289C4C820058D1FE /* SourceSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C733286289C4C820058D1FE /* SourceSettingsView.swift */; }; 0C733287289C4C820058D1FE /* SourceSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C733286289C4C820058D1FE /* SourceSettingsView.swift */; };
0C748EDA29D9256D0049B8BE /* Yams in Frameworks */ = {isa = PBXBuildFile; productRef = 0C748ED929D9256D0049B8BE /* Yams */; }; 0C748EDA29D9256D0049B8BE /* Yams in Frameworks */ = {isa = PBXBuildFile; productRef = 0C748ED929D9256D0049B8BE /* Yams */; };
@ -80,7 +82,6 @@
0C794B6D289EFA2E00DD1CC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0C794B6C289EFA2E00DD1CC8 /* LaunchScreen.storyboard */; }; 0C794B6D289EFA2E00DD1CC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0C794B6C289EFA2E00DD1CC8 /* LaunchScreen.storyboard */; };
0C79DC072899AF3C003F1C5A /* SourceSeedLeech+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C79DC052899AF3C003F1C5A /* SourceSeedLeech+CoreDataClass.swift */; }; 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 */; }; 0C79DC082899AF3C003F1C5A /* SourceSeedLeech+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C79DC062899AF3C003F1C5A /* SourceSeedLeech+CoreDataProperties.swift */; };
0C7B4A002CB051550048FA28 /* SwiftUIIntrospect in Frameworks */ = {isa = PBXBuildFile; productRef = 0C7B49FF2CB051550048FA28 /* SwiftUIIntrospect */; };
0C7C128628DAA3CD00381CD1 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C128528DAA3CD00381CD1 /* URL.swift */; }; 0C7C128628DAA3CD00381CD1 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C128528DAA3CD00381CD1 /* URL.swift */; };
0C7D11FE28AA03FE00ED92DB /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7D11FD28AA03FE00ED92DB /* View.swift */; }; 0C7D11FE28AA03FE00ED92DB /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7D11FD28AA03FE00ED92DB /* View.swift */; };
0C7ED14128D61BBA009E29AD /* BackupModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7ED14028D61BBA009E29AD /* BackupModels.swift */; }; 0C7ED14128D61BBA009E29AD /* BackupModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7ED14028D61BBA009E29AD /* BackupModels.swift */; };
@ -111,6 +112,7 @@
0CA148D6288903F000DE2211 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148BB288903F000DE2211 /* SettingsView.swift */; }; 0CA148D6288903F000DE2211 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148BB288903F000DE2211 /* SettingsView.swift */; };
0CA148D7288903F000DE2211 /* LoginWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148BC288903F000DE2211 /* LoginWebView.swift */; }; 0CA148D7288903F000DE2211 /* LoginWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148BC288903F000DE2211 /* LoginWebView.swift */; };
0CA148D8288903F000DE2211 /* ActionChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148BD288903F000DE2211 /* ActionChoiceView.swift */; }; 0CA148D8288903F000DE2211 /* ActionChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148BD288903F000DE2211 /* ActionChoiceView.swift */; };
0CA148DB288903F000DE2211 /* NavView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148C1288903F000DE2211 /* NavView.swift */; };
0CA148DC288903F000DE2211 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CA148C2288903F000DE2211 /* Assets.xcassets */; }; 0CA148DC288903F000DE2211 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CA148C2288903F000DE2211 /* Assets.xcassets */; };
0CA148DD288903F000DE2211 /* ScrapingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148C3288903F000DE2211 /* ScrapingViewModel.swift */; }; 0CA148DD288903F000DE2211 /* ScrapingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148C3288903F000DE2211 /* ScrapingViewModel.swift */; };
0CA148DF288903F000DE2211 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CA148C6288903F000DE2211 /* Preview Assets.xcassets */; }; 0CA148DF288903F000DE2211 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CA148C6288903F000DE2211 /* Preview Assets.xcassets */; };
@ -134,7 +136,9 @@
0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = 0CAF1C7A286F5C8600296F86 /* SwiftSoup */; }; 0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = 0CAF1C7A286F5C8600296F86 /* SwiftSoup */; };
0CB0115B29D36D9E009AFEDE /* SearchResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB0115A29D36D9E009AFEDE /* SearchResultsView.swift */; }; 0CB0115B29D36D9E009AFEDE /* SearchResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB0115A29D36D9E009AFEDE /* SearchResultsView.swift */; };
0CB0AB5F29BD2A200015422C /* KodiServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB0AB5E29BD2A200015422C /* KodiServerView.swift */; }; 0CB0AB5F29BD2A200015422C /* KodiServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB0AB5E29BD2A200015422C /* KodiServerView.swift */; };
0CB6516328C5A57300DCA721 /* ConditionalId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516228C5A57300DCA721 /* ConditionalId.swift */; };
0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516428C5A5D700DCA721 /* InlinedList.swift */; }; 0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516428C5A5D700DCA721 /* InlinedList.swift */; };
0CB6516A28C5B4A600DCA721 /* InlineHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516928C5B4A600DCA721 /* InlineHeader.swift */; };
0CB725322C123E6F0047FC0B /* CloudDownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */; }; 0CB725322C123E6F0047FC0B /* CloudDownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */; };
0CB725342C123E760047FC0B /* CloudMagnetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB725332C123E760047FC0B /* CloudMagnetView.swift */; }; 0CB725342C123E760047FC0B /* CloudMagnetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB725332C123E760047FC0B /* CloudMagnetView.swift */; };
0CBAB83628D12ED500AC903E /* DisableInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBAB83528D12ED500AC903E /* DisableInteraction.swift */; }; 0CBAB83628D12ED500AC903E /* DisableInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBAB83528D12ED500AC903E /* DisableInteraction.swift */; };
@ -223,6 +227,7 @@
0C6C7C9C29315292002DF910 /* AllDebridModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllDebridModels.swift; sourceTree = "<group>"; }; 0C6C7C9C29315292002DF910 /* AllDebridModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllDebridModels.swift; sourceTree = "<group>"; };
0C7075E329D374C50093DB2D /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; }; 0C7075E329D374C50093DB2D /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
0C7075E529D3845D0093DB2D /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; }; 0C7075E529D3845D0093DB2D /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = "<group>"; };
0C70E40128C3CE9C00A5C72D /* ConditionalContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionalContextMenu.swift; sourceTree = "<group>"; };
0C70E40528C40C4E00A5C72D /* NotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenter.swift; sourceTree = "<group>"; }; 0C70E40528C40C4E00A5C72D /* NotificationCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCenter.swift; sourceTree = "<group>"; };
0C733286289C4C820058D1FE /* SourceSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceSettingsView.swift; sourceTree = "<group>"; }; 0C733286289C4C820058D1FE /* SourceSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceSettingsView.swift; sourceTree = "<group>"; };
0C750742289B003E004B3906 /* SourceRssParser+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceRssParser+CoreDataClass.swift"; sourceTree = "<group>"; }; 0C750742289B003E004B3906 /* SourceRssParser+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SourceRssParser+CoreDataClass.swift"; sourceTree = "<group>"; };
@ -263,6 +268,7 @@
0CA148BB288903F000DE2211 /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; }; 0CA148BB288903F000DE2211 /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
0CA148BC288903F000DE2211 /* LoginWebView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginWebView.swift; sourceTree = "<group>"; }; 0CA148BC288903F000DE2211 /* LoginWebView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginWebView.swift; sourceTree = "<group>"; };
0CA148BD288903F000DE2211 /* ActionChoiceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionChoiceView.swift; sourceTree = "<group>"; }; 0CA148BD288903F000DE2211 /* ActionChoiceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionChoiceView.swift; sourceTree = "<group>"; };
0CA148C1288903F000DE2211 /* NavView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavView.swift; sourceTree = "<group>"; };
0CA148C2288903F000DE2211 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 0CA148C2288903F000DE2211 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0CA148C3288903F000DE2211 /* ScrapingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrapingViewModel.swift; sourceTree = "<group>"; }; 0CA148C3288903F000DE2211 /* ScrapingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrapingViewModel.swift; sourceTree = "<group>"; };
0CA148C6288903F000DE2211 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; }; 0CA148C6288903F000DE2211 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
@ -286,7 +292,9 @@
0CAF1C68286F5C0E00296F86 /* Ferrite.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ferrite.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0CAF1C68286F5C0E00296F86 /* Ferrite.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ferrite.app; sourceTree = BUILT_PRODUCTS_DIR; };
0CB0115A29D36D9E009AFEDE /* SearchResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsView.swift; sourceTree = "<group>"; }; 0CB0115A29D36D9E009AFEDE /* SearchResultsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsView.swift; sourceTree = "<group>"; };
0CB0AB5E29BD2A200015422C /* KodiServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KodiServerView.swift; sourceTree = "<group>"; }; 0CB0AB5E29BD2A200015422C /* KodiServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KodiServerView.swift; sourceTree = "<group>"; };
0CB6516228C5A57300DCA721 /* ConditionalId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConditionalId.swift; sourceTree = "<group>"; };
0CB6516428C5A5D700DCA721 /* InlinedList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlinedList.swift; sourceTree = "<group>"; }; 0CB6516428C5A5D700DCA721 /* InlinedList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlinedList.swift; sourceTree = "<group>"; };
0CB6516928C5B4A600DCA721 /* InlineHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineHeader.swift; sourceTree = "<group>"; };
0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudDownloadView.swift; sourceTree = "<group>"; }; 0CB725312C123E6F0047FC0B /* CloudDownloadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudDownloadView.swift; sourceTree = "<group>"; };
0CB725332C123E760047FC0B /* CloudMagnetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudMagnetView.swift; sourceTree = "<group>"; }; 0CB725332C123E760047FC0B /* CloudMagnetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudMagnetView.swift; sourceTree = "<group>"; };
0CBAB83528D12ED500AC903E /* DisableInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableInteraction.swift; sourceTree = "<group>"; }; 0CBAB83528D12ED500AC903E /* DisableInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableInteraction.swift; sourceTree = "<group>"; };
@ -321,13 +329,13 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
0C7506D728B1AC9A008BEE38 /* SwiftyJSON in Frameworks */, 0C7506D728B1AC9A008BEE38 /* SwiftyJSON in Frameworks */,
0C448BE929A135F100F4E266 /* Introspect-Static in Frameworks */,
0C64A4B4288903680079976D /* Base32 in Frameworks */, 0C64A4B4288903680079976D /* Base32 in Frameworks */,
0C4CFC462897030D00AD9FAD /* Regex in Frameworks */, 0C4CFC462897030D00AD9FAD /* Regex in Frameworks */,
0C64A4B7288903880079976D /* KeychainSwift in Frameworks */, 0C64A4B7288903880079976D /* KeychainSwift in Frameworks */,
0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */, 0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */,
0C748EDA29D9256D0049B8BE /* Yams in Frameworks */, 0C748EDA29D9256D0049B8BE /* Yams in Frameworks */,
0CDDDE052935235E006810B1 /* BetterSafariView in Frameworks */, 0CDDDE052935235E006810B1 /* BetterSafariView in Frameworks */,
0C7B4A002CB051550048FA28 /* SwiftUIIntrospect in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -477,6 +485,8 @@
0C44E2A928D4DFC4007711AE /* Modifiers */ = { 0C44E2A928D4DFC4007711AE /* Modifiers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0C70E40128C3CE9C00A5C72D /* ConditionalContextMenu.swift */,
0CB6516228C5A57300DCA721 /* ConditionalId.swift */,
0CD5E78828CD932B001BF684 /* DisabledAppearance.swift */, 0CD5E78828CD932B001BF684 /* DisabledAppearance.swift */,
0CBAB83528D12ED500AC903E /* DisableInteraction.swift */, 0CBAB83528D12ED500AC903E /* DisableInteraction.swift */,
0CB6516428C5A5D700DCA721 /* InlinedList.swift */, 0CB6516428C5A5D700DCA721 /* InlinedList.swift */,
@ -577,7 +587,9 @@
children = ( children = (
0C44E2A928D4DFC4007711AE /* Modifiers */, 0C44E2A928D4DFC4007711AE /* Modifiers */,
0CDCB91728C662640098B513 /* EmptyInstructionView.swift */, 0CDCB91728C662640098B513 /* EmptyInstructionView.swift */,
0CA148C1288903F000DE2211 /* NavView.swift */,
0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */, 0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */,
0CB6516928C5B4A600DCA721 /* InlineHeader.swift */,
0C32FB562890D1F2002BD219 /* ListRowViews.swift */, 0C32FB562890D1F2002BD219 /* ListRowViews.swift */,
0C2D9652299316CC00A504B6 /* Tag.swift */, 0C2D9652299316CC00A504B6 /* Tag.swift */,
0C6771FB29B3E0DB005D38D2 /* HybridSecureField.swift */, 0C6771FB29B3E0DB005D38D2 /* HybridSecureField.swift */,
@ -744,8 +756,8 @@
0C4CFC452897030D00AD9FAD /* Regex */, 0C4CFC452897030D00AD9FAD /* Regex */,
0C7506D628B1AC9A008BEE38 /* SwiftyJSON */, 0C7506D628B1AC9A008BEE38 /* SwiftyJSON */,
0CDDDE042935235E006810B1 /* BetterSafariView */, 0CDDDE042935235E006810B1 /* BetterSafariView */,
0C448BE829A135F100F4E266 /* Introspect-Static */,
0C748ED929D9256D0049B8BE /* Yams */, 0C748ED929D9256D0049B8BE /* Yams */,
0C7B49FF2CB051550048FA28 /* SwiftUIIntrospect */,
); );
productName = Torrenter; productName = Torrenter;
productReference = 0CAF1C68286F5C0E00296F86 /* Ferrite.app */; productReference = 0CAF1C68286F5C0E00296F86 /* Ferrite.app */;
@ -782,8 +794,8 @@
0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */, 0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */,
0C7506D528B1AC9A008BEE38 /* XCRemoteSwiftPackageReference "SwiftyJSON" */, 0C7506D528B1AC9A008BEE38 /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
0CDDDE032935235E006810B1 /* XCRemoteSwiftPackageReference "BetterSafariView" */, 0CDDDE032935235E006810B1 /* XCRemoteSwiftPackageReference "BetterSafariView" */,
0C448BE729A135F100F4E266 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */,
0C748ED829D9256D0049B8BE /* XCRemoteSwiftPackageReference "Yams" */, 0C748ED829D9256D0049B8BE /* XCRemoteSwiftPackageReference "Yams" */,
0C7B49FE2CB051550048FA28 /* XCRemoteSwiftPackageReference "swiftui-introspect" */,
); );
productRefGroup = 0CAF1C69286F5C0E00296F86 /* Products */; productRefGroup = 0CAF1C69286F5C0E00296F86 /* Products */;
projectDirPath = ""; projectDirPath = "";
@ -843,11 +855,13 @@
0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */, 0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */,
0C8DC35429CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift in Sources */, 0C8DC35429CE2AB5008A83AD /* SourceSettingsBaseUrlView.swift in Sources */,
0C32FB532890D19D002BD219 /* AboutView.swift in Sources */, 0C32FB532890D19D002BD219 /* AboutView.swift in Sources */,
0CB6516328C5A57300DCA721 /* ConditionalId.swift in Sources */,
0C70E40628C40C4E00A5C72D /* NotificationCenter.swift in Sources */, 0C70E40628C40C4E00A5C72D /* NotificationCenter.swift in Sources */,
0C84F4832895BFED0074B7C9 /* Source+CoreDataProperties.swift in Sources */, 0C84F4832895BFED0074B7C9 /* Source+CoreDataProperties.swift in Sources */,
0C2D9653299316CC00A504B6 /* Tag.swift in Sources */, 0C2D9653299316CC00A504B6 /* Tag.swift in Sources */,
0C84FCE129E4B41D00B0DFE4 /* SourceFilterView.swift in Sources */, 0C84FCE129E4B41D00B0DFE4 /* SourceFilterView.swift in Sources */,
0CD5E78928CD932B001BF684 /* DisabledAppearance.swift in Sources */, 0CD5E78928CD932B001BF684 /* DisabledAppearance.swift in Sources */,
0CA148DB288903F000DE2211 /* NavView.swift in Sources */,
0CA3B23C28C2AA5600616D3A /* Bookmark+CoreDataClass.swift in Sources */, 0CA3B23C28C2AA5600616D3A /* Bookmark+CoreDataClass.swift in Sources */,
0CD4030A29DA01B6008D9F03 /* PluginInfoMetaView.swift in Sources */, 0CD4030A29DA01B6008D9F03 /* PluginInfoMetaView.swift in Sources */,
0C750745289B003E004B3906 /* SourceRssParser+CoreDataProperties.swift in Sources */, 0C750745289B003E004B3906 /* SourceRssParser+CoreDataProperties.swift in Sources */,
@ -874,6 +888,7 @@
0C7D11FE28AA03FE00ED92DB /* View.swift in Sources */, 0C7D11FE28AA03FE00ED92DB /* View.swift in Sources */,
0CD0265729FEFBF900A83D25 /* FerriteKeychain.swift in Sources */, 0CD0265729FEFBF900A83D25 /* FerriteKeychain.swift in Sources */,
0CA3B23728C2660700616D3A /* HistoryView.swift in Sources */, 0CA3B23728C2660700616D3A /* HistoryView.swift in Sources */,
0C70E40228C3CE9C00A5C72D /* ConditionalContextMenu.swift in Sources */,
0C50B7D0299DF63C00A9FA3C /* UIDevice.swift in Sources */, 0C50B7D0299DF63C00A9FA3C /* UIDevice.swift in Sources */,
0C0D50E7288DFF850035ECC8 /* PluginAggregateView.swift in Sources */, 0C0D50E7288DFF850035ECC8 /* PluginAggregateView.swift in Sources */,
0CA3B23428C2658700616D3A /* LibraryView.swift in Sources */, 0CA3B23428C2658700616D3A /* LibraryView.swift in Sources */,
@ -900,6 +915,7 @@
0CA148DD288903F000DE2211 /* ScrapingViewModel.swift in Sources */, 0CA148DD288903F000DE2211 /* ScrapingViewModel.swift in Sources */,
0C445C62293F9A0B0060744D /* Bundle.swift in Sources */, 0C445C62293F9A0B0060744D /* Bundle.swift in Sources */,
0C0755C6293424A200ECA142 /* DebridLabelView.swift in Sources */, 0C0755C6293424A200ECA142 /* DebridLabelView.swift in Sources */,
0CB6516A28C5B4A600DCA721 /* InlineHeader.swift in Sources */,
0CA148D8288903F000DE2211 /* ActionChoiceView.swift in Sources */, 0CA148D8288903F000DE2211 /* ActionChoiceView.swift in Sources */,
0C41BC6528C2AEB900B47DD6 /* SearchModels.swift in Sources */, 0C41BC6528C2AEB900B47DD6 /* SearchModels.swift in Sources */,
0C68135028BC1A2D00FAD890 /* GithubWrapper.swift in Sources */, 0C68135028BC1A2D00FAD890 /* GithubWrapper.swift in Sources */,
@ -1125,7 +1141,7 @@
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportsDocumentBrowser = YES; INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.0; IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1161,7 +1177,7 @@
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportsDocumentBrowser = YES; INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.0; IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -1200,6 +1216,14 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
0C448BE729A135F100F4E266 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/siteline/SwiftUI-Introspect/";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.2.3;
};
};
0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */ = { 0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/sindresorhus/Regex"; repositoryURL = "https://github.com/sindresorhus/Regex";
@ -1240,14 +1264,6 @@
kind = branch; kind = branch;
}; };
}; };
0C7B49FE2CB051550048FA28 /* XCRemoteSwiftPackageReference "swiftui-introspect" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/siteline/swiftui-introspect";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.3.0;
};
};
0CAF1C79286F5C8600296F86 /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { 0CAF1C79286F5C8600296F86 /* XCRemoteSwiftPackageReference "SwiftSoup" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/scinfu/SwiftSoup.git"; repositoryURL = "https://github.com/scinfu/SwiftSoup.git";
@ -1267,6 +1283,11 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
0C448BE829A135F100F4E266 /* Introspect-Static */ = {
isa = XCSwiftPackageProductDependency;
package = 0C448BE729A135F100F4E266 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */;
productName = "Introspect-Static";
};
0C4CFC452897030D00AD9FAD /* Regex */ = { 0C4CFC452897030D00AD9FAD /* Regex */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */; package = 0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */;
@ -1292,11 +1313,6 @@
package = 0C7506D528B1AC9A008BEE38 /* XCRemoteSwiftPackageReference "SwiftyJSON" */; package = 0C7506D528B1AC9A008BEE38 /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
productName = SwiftyJSON; productName = SwiftyJSON;
}; };
0C7B49FF2CB051550048FA28 /* SwiftUIIntrospect */ = {
isa = XCSwiftPackageProductDependency;
package = 0C7B49FE2CB051550048FA28 /* XCRemoteSwiftPackageReference "swiftui-introspect" */;
productName = SwiftUIIntrospect;
};
0CAF1C7A286F5C8600296F86 /* SwiftSoup */ = { 0CAF1C7A286F5C8600296F86 /* SwiftSoup */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 0CAF1C79286F5C8600296F86 /* XCRemoteSwiftPackageReference "SwiftSoup" */; package = 0CAF1C79286F5C8600296F86 /* XCRemoteSwiftPackageReference "SwiftSoup" */;

View file

@ -9,6 +9,10 @@ import UIKit
extension UIDevice { extension UIDevice {
var hasNotch: Bool { var hasNotch: Bool {
UIApplication.shared.currentUIWindow?.safeAreaInsets.bottom ?? 0 > 0 if #available(iOS 11.0, *) {
return UIApplication.shared.currentUIWindow?.safeAreaInsets.bottom ?? 0 > 0
} else {
return false
}
} }
} }

View file

@ -5,6 +5,7 @@
// Created by Brian Dashore on 8/15/22. // Created by Brian Dashore on 8/15/22.
// //
import Introspect
import SwiftUI import SwiftUI
extension View { extension View {
@ -19,6 +20,16 @@ extension View {
// MARK: Modifiers // MARK: Modifiers
func conditionalContextMenu(id: some Hashable,
@ViewBuilder _ internalContent: @escaping () -> some View) -> some View
{
modifier(ConditionalContextMenuModifier(internalContent, id: id))
}
func conditionalId(_ id: some Hashable) -> some View {
modifier(ConditionalIdModifier(id: id))
}
func disabledAppearance(_ disabled: Bool, dimmedOpacity: Double? = nil, animation: Animation? = nil) -> some View { func disabledAppearance(_ disabled: Bool, dimmedOpacity: Double? = nil, animation: Animation? = nil) -> some View {
modifier(DisabledAppearanceModifier(disabled: disabled, dimmedOpacity: dimmedOpacity, animation: animation)) modifier(DisabledAppearanceModifier(disabled: disabled, dimmedOpacity: dimmedOpacity, animation: animation))
} }

View file

@ -0,0 +1,27 @@
//
// InlineHeader.swift
// Ferrite
//
// Created by Brian Dashore on 9/5/22.
//
// For iOS 15's weird defaults regarding sectioned list padding
//
import SwiftUI
struct InlineHeader: View {
let title: String
init(_ title: String) {
self.title = title
}
var body: some View {
if #available(iOS 16, *) {
Text(title)
} else {
Text(title)
.listRowInsets(EdgeInsets(top: 10, leading: 15, bottom: 0, trailing: 0))
}
}
}

View file

@ -0,0 +1,39 @@
//
// ConditionalContextMenu.swift
// Ferrite
//
// Created by Brian Dashore on 9/3/22.
//
// Used as a workaround for iOS 15 not updating context views with conditional variables
// A stateful ID is required for the contextMenu to update itself.
//
import SwiftUI
struct ConditionalContextMenuModifier<InternalContent: View, ID: Hashable>: ViewModifier {
let internalContent: () -> InternalContent
let id: ID
init(@ViewBuilder _ internalContent: @escaping () -> InternalContent, id: ID) {
self.internalContent = internalContent
self.id = id
}
func body(content: Content) -> some View {
if #available(iOS 16, *) {
content
.contextMenu {
internalContent()
}
} else {
content
.background {
Color.clear
.contextMenu {
internalContent()
}
.id(id)
}
}
}
}

View file

@ -0,0 +1,24 @@
//
// ConditionalId.swift
// Ferrite
//
// Created by Brian Dashore on 9/4/22.
//
// Applies an ID below iOS 16
// This is due to ID workarounds making iOS 16 apps crash
//
import SwiftUI
struct ConditionalIdModifier<ID: Hashable>: ViewModifier {
let id: ID
func body(content: Content) -> some View {
if #available(iOS 16, *) {
content
} else {
content
.id(id)
}
}
}

View file

@ -5,18 +5,26 @@
// Created by Brian Dashore on 9/4/22. // Created by Brian Dashore on 9/4/22.
// //
// Removes the top padding on unsectioned lists // Removes the top padding on unsectioned lists
// If a list is sectioned, see InlineHeader
// //
import Introspect
import SwiftUI import SwiftUI
import SwiftUIIntrospect
struct InlinedListModifier: ViewModifier { struct InlinedListModifier: ViewModifier {
let inset: CGFloat let inset: CGFloat
func body(content: Content) -> some View { func body(content: Content) -> some View {
content if #available(iOS 16, *) {
.introspect(.list, on: .iOS(.v16, .v17, .v18)) { collectionView in content
collectionView.contentInset.top = inset .introspectCollectionView { collectionView in
} collectionView.contentInset.top = inset
}
} else {
content
.introspectTableView { tableView in
tableView.contentInset.top = inset
}
}
} }
} }

View file

@ -0,0 +1,29 @@
//
// NavView.swift
// Ferrite
//
// Created by Brian Dashore on 7/4/22.
// Contributed by Mantton
//
// A wrapper that switches between NavigationStack and the legacy NavigationView
//
import SwiftUI
struct NavView<Content: View>: View {
@ViewBuilder var content: Content
var body: some View {
// NavigationStack issues are fixed on iOS 17
if #available(iOS 17, *) {
NavigationStack {
content
}
} else {
NavigationView {
content
}
.navigationViewStyle(.stack)
}
}
}

View file

@ -76,7 +76,7 @@ struct HistorySectionView: View {
var body: some View { var body: some View {
if compareGroup(historyGroup) > 0 { if compareGroup(historyGroup) > 0 {
Section(formatter.string(from: historyGroup[0].date ?? Date())) { Section(header: InlineHeader(formatter.string(from: historyGroup[0].date ?? Date()))) {
ForEach(historyGroup, id: \.self) { history in ForEach(historyGroup, id: \.self) { history in
ForEach(history.entryArray.filter { allEntries.contains($0) }, id: \.self) { entry in ForEach(history.entryArray.filter { allEntries.contains($0) }, id: \.self) { entry in
HistoryButtonView(entry: entry) HistoryButtonView(entry: entry)

View file

@ -11,7 +11,7 @@ struct PluginInfoAboutView<P: Plugin>: View {
@ObservedObject var selectedPlugin: P @ObservedObject var selectedPlugin: P
var body: some View { var body: some View {
Section("Description") { Section(header: InlineHeader("Description")) {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
if let pluginAbout = selectedPlugin.about { if let pluginAbout = selectedPlugin.about {
if pluginAbout.last == "\n" { if pluginAbout.last == "\n" {

View file

@ -16,7 +16,7 @@ struct PluginInfoMetaView<P: Plugin>: View {
) var pluginLists: FetchedResults<PluginList> ) var pluginLists: FetchedResults<PluginList>
var body: some View { var body: some View {
Section("Metadata") { Section(header: InlineHeader("Metadata")) {
VStack(alignment: .leading) { VStack(alignment: .leading) {
VStack(alignment: .leading, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
HStack(spacing: 5) { HStack(spacing: 5) {

View file

@ -39,7 +39,7 @@ struct PluginAggregateView<P: Plugin, PJ: PluginJson>: View {
searchText: searchText searchText: searchText
) )
if !filteredUpdatedPlugins.isEmpty { if !filteredUpdatedPlugins.isEmpty {
Section("Updates") { Section(header: InlineHeader("Updates")) {
ForEach(filteredUpdatedPlugins, id: \.self) { (updatedPlugin: PJ) in ForEach(filteredUpdatedPlugins, id: \.self) { (updatedPlugin: PJ) in
PluginCatalogButtonView(availablePlugin: updatedPlugin, needsUpdate: true) PluginCatalogButtonView(availablePlugin: updatedPlugin, needsUpdate: true)
} }
@ -47,7 +47,7 @@ struct PluginAggregateView<P: Plugin, PJ: PluginJson>: View {
} }
if !installedPlugins.isEmpty { if !installedPlugins.isEmpty {
Section("Installed") { Section(header: InlineHeader("Installed")) {
ForEach(installedPlugins, id: \.self) { installedPlugin in ForEach(installedPlugins, id: \.self) { installedPlugin in
InstalledPluginButtonView( InstalledPluginButtonView(
installedPlugin: installedPlugin, installedPlugin: installedPlugin,
@ -64,7 +64,7 @@ struct PluginAggregateView<P: Plugin, PJ: PluginJson>: View {
searchText: searchText searchText: searchText
) )
if !filteredAvailablePlugins.isEmpty { if !filteredAvailablePlugins.isEmpty {
Section("Catalog") { Section(header: InlineHeader("Catalog")) {
ForEach(filteredAvailablePlugins, id: \.self) { availablePlugin in ForEach(filteredAvailablePlugins, id: \.self) { availablePlugin in
PluginCatalogButtonView(availablePlugin: availablePlugin, needsUpdate: false) PluginCatalogButtonView(availablePlugin: availablePlugin, needsUpdate: false)
} }

View file

@ -13,7 +13,7 @@ struct PluginInfoView<P: Plugin>: View {
@Binding var selectedPlugin: P? @Binding var selectedPlugin: P?
var body: some View { var body: some View {
NavigationStack { NavView {
List { List {
if let selectedPlugin { if let selectedPlugin {
PluginInfoMetaView(selectedPlugin: selectedPlugin) PluginInfoMetaView(selectedPlugin: selectedPlugin)

View file

@ -19,7 +19,7 @@ struct SourceSettingsApiView: View {
var body: some View { var body: some View {
Section( Section(
header: Text("API credentials"), header: InlineHeader("API credentials"),
footer: Text("Grab the required API credentials from the website. A client secret can be an API token.") footer: Text("Grab the required API credentials from the website. A client secret can be an API token.")
) { ) {
if let clientId = selectedSourceApi.clientId, clientId.dynamic { if let clientId = selectedSourceApi.clientId, clientId.dynamic {

View file

@ -13,7 +13,7 @@ struct SourceSettingsBaseUrlView: View {
@State private var tempSite: String = "" @State private var tempSite: String = ""
var body: some View { var body: some View {
Section( Section(
header: Text("Base URL"), header: InlineHeader("Base URL"),
footer: Text("Enter the base URL of your server.") footer: Text("Enter the base URL of your server.")
) { ) {
TextField("https://...", text: $tempSite, onEditingChanged: { isFocused in TextField("https://...", text: $tempSite, onEditingChanged: { isFocused in

View file

@ -11,7 +11,7 @@ struct SourceSettingsMethodView: View {
@ObservedObject var selectedSource: Source @ObservedObject var selectedSource: Source
var body: some View { var body: some View {
Section("Fetch method") { Section(header: InlineHeader("Fetch method")) {
Picker("", selection: $selectedSource.preferredParser) { Picker("", selection: $selectedSource.preferredParser) {
if selectedSource.jsonParser != nil { if selectedSource.jsonParser != nil {
Text("Website API").tag(SourcePreferredParser.siteApi.rawValue) Text("Website API").tag(SourcePreferredParser.siteApi.rawValue)

View file

@ -68,7 +68,7 @@ struct SearchResultButtonView: View {
} }
.disableInteraction(navModel.currentChoiceSheet != nil) .disableInteraction(navModel.currentChoiceSheet != nil)
.tint(.primary) .tint(.primary)
.contextMenu { .conditionalContextMenu(id: existingBookmark) {
ZStack { ZStack {
if let bookmark = existingBookmark { if let bookmark = existingBookmark {
Button { Button {

View file

@ -25,11 +25,11 @@ struct KodiEditorView: View {
@State private var errorAlertText: String = "" @State private var errorAlertText: String = ""
var body: some View { var body: some View {
NavigationStack { NavView {
Form { Form {
Group { Group {
Section( Section(
header: Text("URL"), header: InlineHeader("URL"),
footer: Text("Must follow the format http(s)://<ip>:<port>") footer: Text("Must follow the format http(s)://<ip>:<port>")
) { ) {
TextField("Enter URL", text: $serverUrl) TextField("Enter URL", text: $serverUrl)
@ -37,14 +37,14 @@ struct KodiEditorView: View {
} }
Section( Section(
header: Text("Friendly name"), header: InlineHeader("Friendly name"),
footer: Text("Defaults to the URL if not provided") footer: Text("Defaults to the URL if not provided")
) { ) {
TextField("Friendly name", text: $friendlyName) TextField("Friendly name", text: $friendlyName)
} }
Section( Section(
header: Text("Credentials"), header: InlineHeader("Credentials"),
footer: Text("Only use for clients with authentication") footer: Text("Only use for clients with authentication")
) { ) {
TextField("Username", text: $username) TextField("Username", text: $username)

View file

@ -18,7 +18,7 @@ struct SettingsKodiView: View {
var body: some View { var body: some View {
List { List {
Section("Description") { Section(header: InlineHeader("Description")) {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
Text("Kodi is an external application that is used to manage a local media library and playback.") Text("Kodi is an external application that is used to manage a local media library and playback.")
@ -27,7 +27,7 @@ struct SettingsKodiView: View {
} }
Section( Section(
header: Text("Servers"), header: InlineHeader("Servers"),
footer: Text("Edit a server by holding it and accessing the context menu") footer: Text("Edit a server by holding it and accessing the context menu")
) { ) {
if kodiServers.isEmpty { if kodiServers.isEmpty {

View file

@ -25,7 +25,7 @@ struct PluginListEditorView: View {
@State private var loadedSelectedList = false @State private var loadedSelectedList = false
var body: some View { var body: some View {
NavigationStack { NavView {
Form { Form {
TextField("Enter URL", text: $pluginListUrl) TextField("Enter URL", text: $pluginListUrl)
.disableAutocorrection(true) .disableAutocorrection(true)

View file

@ -69,8 +69,12 @@ struct SettingsPluginListView: View {
} }
} }
.sheet(isPresented: $presentEditSheet) { .sheet(isPresented: $presentEditSheet) {
PluginListEditorView() if #available(iOS 16, *) {
.presentationDetents([.medium]) PluginListEditorView()
.presentationDetents([.medium])
} else {
PluginListEditorView()
}
} }
.navigationTitle("Plugin Lists") .navigationTitle("Plugin Lists")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)

View file

@ -20,7 +20,7 @@ struct SettingsAppVersionView: View {
ProgressView() ProgressView()
} else if !releases.isEmpty { } else if !releases.isEmpty {
List { List {
Section("GitHub links") { Section(header: InlineHeader("GitHub links")) {
ForEach(releases, id: \.self) { release in ForEach(releases, id: \.self) { release in
ListRowLinkView(text: release.tagName, link: release.htmlUrl) ListRowLinkView(text: release.tagName, link: release.htmlUrl)
} }

View file

@ -16,7 +16,7 @@ struct SettingsDebridInfoView: View {
var body: some View { var body: some View {
List { List {
Section("Description") { Section(header: InlineHeader("Description")) {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
Text(debridSource.description ?? Text(debridSource.description ??
"\(debridSource.id) is a debrid service that is used for downloads and media playback. You must pay to access the service." "\(debridSource.id) is a debrid service that is used for downloads and media playback. You must pay to access the service."
@ -27,7 +27,7 @@ struct SettingsDebridInfoView: View {
} }
Section( Section(
header: Text("Login status"), header: InlineHeader("Login status"),
footer: Text("A WebView will show up to prompt you for credentials") footer: Text("A WebView will show up to prompt you for credentials")
) { ) {
Button { Button {
@ -58,7 +58,7 @@ struct SettingsDebridInfoView: View {
} }
Section( Section(
header: Text("API key"), header: InlineHeader("API key"),
footer: Text("Add a permanent API key here. Only use this if web authentication does not work!") footer: Text("Add a permanent API key here. Only use this if web authentication does not work!")
) { ) {
HybridSecureField( HybridSecureField(

View file

@ -27,7 +27,7 @@ struct ContentView: View {
@State private var dismissAction: () -> Void = {} @State private var dismissAction: () -> Void = {}
var body: some View { var body: some View {
NavigationStack { NavView {
List { List {
SearchResultsView(searchText: $searchText) SearchResultsView(searchText: $searchText)
} }

View file

@ -30,7 +30,7 @@ struct LibraryView: View {
@State private var searchText: String = "" @State private var searchText: String = ""
var body: some View { var body: some View {
NavigationStack { NavView {
ZStack { ZStack {
switch navModel.libraryPickerSelection { switch navModel.libraryPickerSelection {
case .bookmarks: case .bookmarks:

View file

@ -12,7 +12,7 @@ struct LoginWebView: View {
var url: URL var url: URL
var body: some View { var body: some View {
NavigationStack { NavView {
WebView(url: url) WebView(url: url)
.navigationTitle("Sign in") .navigationTitle("Sign in")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)

View file

@ -54,8 +54,12 @@ struct MainView: View {
case .batch: case .batch:
BatchChoiceView() BatchChoiceView()
case .activity: case .activity:
ShareSheet(activityItems: navModel.activityItems) if #available(iOS 16, *) {
.presentationDetents([.medium, .large]) ShareSheet(activityItems: navModel.activityItems)
.presentationDetents([.medium, .large])
} else {
ShareSheet(activityItems: navModel.activityItems)
}
} }
} }
.onAppear { .onAppear {

View file

@ -30,7 +30,7 @@ struct PluginsView: View {
@State private var searchText: String = "" @State private var searchText: String = ""
var body: some View { var body: some View {
NavigationStack { NavView {
ZStack { ZStack {
if checkedForPlugins { if checkedForPlugins {
switch navModel.pluginPickerSelection { switch navModel.pluginPickerSelection {

View file

@ -212,7 +212,10 @@ struct SearchBar<ScopeContent: View>: UIViewControllerRepresentable {
private func setup() { private func setup() {
parent?.navigationItem.searchController = searchController parent?.navigationItem.searchController = searchController
parent?.navigationItem.hidesSearchBarWhenScrolling = false parent?.navigationItem.hidesSearchBarWhenScrolling = false
parent?.navigationItem.preferredSearchBarPlacement = .stacked
if #available(iOS 16, *) {
parent?.navigationItem.preferredSearchBarPlacement = .stacked
}
// Makes search bar appear when application starts // Makes search bar appear when application starts
parent?.navigationController?.navigationBar.sizeToFit() parent?.navigationController?.navigationBar.sizeToFit()

View file

@ -6,6 +6,7 @@
// //
import BetterSafariView import BetterSafariView
import Introspect
import SwiftUI import SwiftUI
import WebKit import WebKit
@ -42,15 +43,15 @@ struct SettingsView: View {
@FocusState private var focusedField: Field? @FocusState private var focusedField: Field?
var body: some View { var body: some View {
NavigationStack { NavView {
Form { Form {
Section("Debrid services") { Section(header: InlineHeader("Debrid services")) {
ForEach(debridManager.debridSources, id: \.id) { (debridSource: DebridSource) in ForEach(debridManager.debridSources, id: \.id) { (debridSource: DebridSource) in
SettingsDebridLinkView(debridSource: debridSource) SettingsDebridLinkView(debridSource: debridSource)
} }
} }
Section("Playback services") { Section(header: InlineHeader("Playback services")) {
NavigationLink { NavigationLink {
SettingsKodiView(kodiServers: kodiServers) SettingsKodiView(kodiServers: kodiServers)
} label: { } label: {
@ -64,7 +65,7 @@ struct SettingsView: View {
} }
Section( Section(
header: Text("Behavior"), header: InlineHeader("Behavior"),
footer: VStack(alignment: .leading, spacing: 8) { footer: VStack(alignment: .leading, spacing: 8) {
Text("Temporarily disable ephemeral auth if you cannot log into a service") Text("Temporarily disable ephemeral auth if you cannot log into a service")
Text("Only disable search timeout if results are slow to fetch") Text("Only disable search timeout if results are slow to fetch")
@ -111,13 +112,13 @@ struct SettingsView: View {
} }
} }
Section("Plugin management") { Section(header: InlineHeader("Plugin management")) {
NavigationLink("Plugin lists") { NavigationLink("Plugin lists") {
SettingsPluginListView() SettingsPluginListView()
} }
} }
Section("Default actions") { Section(header: InlineHeader("Default actions")) {
if !debridManager.enabledDebrids.isEmpty { if !debridManager.enabledDebrids.isEmpty {
NavigationLink { NavigationLink {
DefaultActionPickerView( DefaultActionPickerView(
@ -175,13 +176,13 @@ struct SettingsView: View {
} }
} }
Section("Backups") { Section(header: InlineHeader("Backups")) {
NavigationLink("Backups") { NavigationLink("Backups") {
BackupsView() BackupsView()
} }
} }
Section("Updates") { Section(header: InlineHeader("Updates")) {
Toggle(isOn: $autoUpdateNotifs) { Toggle(isOn: $autoUpdateNotifs) {
Text("Show update alerts") Text("Show update alerts")
} }
@ -191,7 +192,7 @@ struct SettingsView: View {
} }
} }
Section("Information") { Section(header: InlineHeader("Information")) {
ListRowLinkView(text: "Donate", link: "https://ko-fi.com/kingbri") ListRowLinkView(text: "Donate", link: "https://ko-fi.com/kingbri")
ListRowLinkView(text: "Report issues", link: "https://github.com/bdashore3/Ferrite/issues") ListRowLinkView(text: "Report issues", link: "https://github.com/bdashore3/Ferrite/issues")
@ -200,7 +201,7 @@ struct SettingsView: View {
} }
} }
Section("Debug") { Section(header: InlineHeader("Debug")) {
NavigationLink("Logs") { NavigationLink("Logs") {
SettingsLogView() SettingsLogView()
} }

View file

@ -29,9 +29,9 @@ struct ActionChoiceView: View {
@State private var showMagnetCopyAlert = false @State private var showMagnetCopyAlert = false
var body: some View { var body: some View {
NavigationStack { NavView {
Form { Form {
Section("Now Playing") { Section(header: InlineHeader("Now Playing")) {
VStack(alignment: .leading, spacing: 5) { VStack(alignment: .leading, spacing: 5) {
Text(navModel.selectedTitle) Text(navModel.selectedTitle)
.font(.callout) .font(.callout)
@ -46,7 +46,7 @@ struct ActionChoiceView: View {
} }
if !debridManager.downloadUrl.isEmpty { if !debridManager.downloadUrl.isEmpty {
Section("Debrid options") { Section(header: InlineHeader("Debrid options")) {
ForEach(actions, id: \.id) { action in ForEach(actions, id: \.id) { action in
if action.requires.contains(ActionRequirement.debrid.rawValue) { if action.requires.contains(ActionRequirement.debrid.rawValue) {
ListRowButtonView(action.name, systemImage: "arrow.up.forward.app.fill") { ListRowButtonView(action.name, systemImage: "arrow.up.forward.app.fill") {
@ -91,7 +91,7 @@ struct ActionChoiceView: View {
} }
if !navModel.resultFromCloud { if !navModel.resultFromCloud {
Section("Magnet options") { Section(header: InlineHeader("Magnet options")) {
ForEach(actions, id: \.id) { action in ForEach(actions, id: \.id) { action in
if action.requires.contains(ActionRequirement.magnet.rawValue) { if action.requires.contains(ActionRequirement.magnet.rawValue) {
ListRowButtonView(action.name, systemImage: "arrow.up.forward.app.fill") { ListRowButtonView(action.name, systemImage: "arrow.up.forward.app.fill") {
@ -123,8 +123,13 @@ struct ActionChoiceView: View {
} }
.tint(.primary) .tint(.primary)
.sheet(isPresented: $navModel.showLocalActivitySheet) { .sheet(isPresented: $navModel.showLocalActivitySheet) {
ShareSheet(activityItems: navModel.activityItems) // TODO: Fix share sheet
.presentationDetents([.medium, .large]) if #available(iOS 16, *) {
ShareSheet(activityItems: navModel.activityItems)
.presentationDetents([.medium, .large])
} else {
ShareSheet(activityItems: navModel.activityItems)
}
} }
.alert("Action successful", isPresented: $pluginManager.showActionSuccessAlert) { .alert("Action successful", isPresented: $pluginManager.showActionSuccessAlert) {
Button("OK", role: .cancel) {} Button("OK", role: .cancel) {}

View file

@ -19,8 +19,9 @@ struct BatchChoiceView: View {
@State private var searchText: String = "" @State private var searchText: String = ""
// TODO: Make this generic for an IA protocol
var body: some View { var body: some View {
NavigationStack { NavView {
List { List {
ForEach(debridManager.selectedDebridItem?.files ?? [], id: \.self) { file in ForEach(debridManager.selectedDebridItem?.files ?? [], id: \.self) { file in
if file.name.lowercased().contains(searchText.lowercased()) || searchText.isEmpty { if file.name.lowercased().contains(searchText.lowercased()) || searchText.isEmpty {