Ferrite: Properly inline lists
The inset grouped list style has a top inset that adds extra space between the navigation bar title and the list rows. Use introspect to remove this space on UITableView and UICollectionView (for iOS 16). Sections completely ignore the introspect changes, so add a section header which removes the list row insets. Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
parent
b4fe3807d6
commit
16a39c3a58
13 changed files with 158 additions and 19 deletions
|
|
@ -71,6 +71,10 @@
|
||||||
0CA148EC288903F000DE2211 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148D4288903F000DE2211 /* ContentView.swift */; };
|
0CA148EC288903F000DE2211 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA148D4288903F000DE2211 /* ContentView.swift */; };
|
||||||
0CA3FB2028B91D9500FA10A8 /* IndeterminateProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */; };
|
0CA3FB2028B91D9500FA10A8 /* IndeterminateProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */; };
|
||||||
0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = 0CAF1C7A286F5C8600296F86 /* SwiftSoup */; };
|
0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = 0CAF1C7A286F5C8600296F86 /* SwiftSoup */; };
|
||||||
|
0CB6516328C5A57300DCA721 /* ConditionalId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516228C5A57300DCA721 /* ConditionalId.swift */; };
|
||||||
|
0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516428C5A5D700DCA721 /* InlinedList.swift */; };
|
||||||
|
0CB6516828C5A5EC00DCA721 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = 0CB6516728C5A5EC00DCA721 /* Introspect */; };
|
||||||
|
0CB6516A28C5B4A600DCA721 /* InlineHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB6516928C5B4A600DCA721 /* InlineHeader.swift */; };
|
||||||
0CBC76FD288D914F0054BE44 /* BatchChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */; };
|
0CBC76FD288D914F0054BE44 /* BatchChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */; };
|
||||||
0CBC76FF288DAAD00054BE44 /* NavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */; };
|
0CBC76FF288DAAD00054BE44 /* NavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */; };
|
||||||
0CBC7705288DE7F40054BE44 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC7704288DE7F40054BE44 /* PersistenceController.swift */; };
|
0CBC7705288DE7F40054BE44 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC7704288DE7F40054BE44 /* PersistenceController.swift */; };
|
||||||
|
|
@ -137,6 +141,9 @@
|
||||||
0CA148D4288903F000DE2211 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
0CA148D4288903F000DE2211 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndeterminateProgressView.swift; sourceTree = "<group>"; };
|
0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndeterminateProgressView.swift; sourceTree = "<group>"; };
|
||||||
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; };
|
||||||
|
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>"; };
|
||||||
|
0CB6516928C5B4A600DCA721 /* InlineHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InlineHeader.swift; sourceTree = "<group>"; };
|
||||||
0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchChoiceView.swift; sourceTree = "<group>"; };
|
0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchChoiceView.swift; sourceTree = "<group>"; };
|
||||||
0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewModel.swift; sourceTree = "<group>"; };
|
0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewModel.swift; sourceTree = "<group>"; };
|
||||||
0CBC7704288DE7F40054BE44 /* PersistenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = "<group>"; };
|
0CBC7704288DE7F40054BE44 /* PersistenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -153,6 +160,7 @@
|
||||||
0C64A4B4288903680079976D /* Base32 in Frameworks */,
|
0C64A4B4288903680079976D /* Base32 in Frameworks */,
|
||||||
0C4CFC462897030D00AD9FAD /* Regex in Frameworks */,
|
0C4CFC462897030D00AD9FAD /* Regex in Frameworks */,
|
||||||
0C7376F028A97D1400D60918 /* SwiftUIX in Frameworks */,
|
0C7376F028A97D1400D60918 /* SwiftUIX in Frameworks */,
|
||||||
|
0CB6516828C5A5EC00DCA721 /* Introspect in Frameworks */,
|
||||||
0C64A4B7288903880079976D /* KeychainSwift in Frameworks */,
|
0C64A4B7288903880079976D /* KeychainSwift in Frameworks */,
|
||||||
0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */,
|
0CAF1C7B286F5C8600296F86 /* SwiftSoup in Frameworks */,
|
||||||
);
|
);
|
||||||
|
|
@ -241,6 +249,9 @@
|
||||||
0C32FB562890D1F2002BD219 /* ListRowViews.swift */,
|
0C32FB562890D1F2002BD219 /* ListRowViews.swift */,
|
||||||
0C7D11FB28AA01E900ED92DB /* DynamicAccentColor.swift */,
|
0C7D11FB28AA01E900ED92DB /* DynamicAccentColor.swift */,
|
||||||
0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */,
|
0CA3FB1F28B91D9500FA10A8 /* IndeterminateProgressView.swift */,
|
||||||
|
0CB6516228C5A57300DCA721 /* ConditionalId.swift */,
|
||||||
|
0CB6516428C5A5D700DCA721 /* InlinedList.swift */,
|
||||||
|
0CB6516928C5B4A600DCA721 /* InlineHeader.swift */,
|
||||||
);
|
);
|
||||||
path = CommonViews;
|
path = CommonViews;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -366,6 +377,7 @@
|
||||||
0C4CFC452897030D00AD9FAD /* Regex */,
|
0C4CFC452897030D00AD9FAD /* Regex */,
|
||||||
0C7376EF28A97D1400D60918 /* SwiftUIX */,
|
0C7376EF28A97D1400D60918 /* SwiftUIX */,
|
||||||
0C7506D628B1AC9A008BEE38 /* SwiftyJSON */,
|
0C7506D628B1AC9A008BEE38 /* SwiftyJSON */,
|
||||||
|
0CB6516728C5A5EC00DCA721 /* Introspect */,
|
||||||
);
|
);
|
||||||
productName = Torrenter;
|
productName = Torrenter;
|
||||||
productReference = 0CAF1C68286F5C0E00296F86 /* Ferrite.app */;
|
productReference = 0CAF1C68286F5C0E00296F86 /* Ferrite.app */;
|
||||||
|
|
@ -402,6 +414,7 @@
|
||||||
0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */,
|
0C4CFC442897030D00AD9FAD /* XCRemoteSwiftPackageReference "Regex" */,
|
||||||
0C7376EE28A97D1400D60918 /* XCRemoteSwiftPackageReference "SwiftUIX" */,
|
0C7376EE28A97D1400D60918 /* XCRemoteSwiftPackageReference "SwiftUIX" */,
|
||||||
0C7506D528B1AC9A008BEE38 /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
0C7506D528B1AC9A008BEE38 /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
||||||
|
0CB6516628C5A5EC00DCA721 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 0CAF1C69286F5C0E00296F86 /* Products */;
|
productRefGroup = 0CAF1C69286F5C0E00296F86 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
|
@ -431,8 +444,10 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
0C0D50E5288DFE7F0035ECC8 /* SourceModels.swift in Sources */,
|
0C0D50E5288DFE7F0035ECC8 /* SourceModels.swift in Sources */,
|
||||||
|
0CB6516528C5A5D700DCA721 /* InlinedList.swift in Sources */,
|
||||||
0C60B1EF28A1A00000E3FD7E /* SearchProgressView.swift in Sources */,
|
0C60B1EF28A1A00000E3FD7E /* SearchProgressView.swift in Sources */,
|
||||||
0C32FB532890D19D002BD219 /* AboutView.swift in Sources */,
|
0C32FB532890D19D002BD219 /* AboutView.swift in Sources */,
|
||||||
|
0CB6516328C5A57300DCA721 /* ConditionalId.swift in Sources */,
|
||||||
0C84F4832895BFED0074B7C9 /* Source+CoreDataProperties.swift in Sources */,
|
0C84F4832895BFED0074B7C9 /* Source+CoreDataProperties.swift in Sources */,
|
||||||
0CA148DB288903F000DE2211 /* NavView.swift in Sources */,
|
0CA148DB288903F000DE2211 /* NavView.swift in Sources */,
|
||||||
0C750745289B003E004B3906 /* SourceRssParser+CoreDataProperties.swift in Sources */,
|
0C750745289B003E004B3906 /* SourceRssParser+CoreDataProperties.swift in Sources */,
|
||||||
|
|
@ -454,6 +469,7 @@
|
||||||
0C794B69289DACC800DD1CC8 /* InstalledSourceView.swift in Sources */,
|
0C794B69289DACC800DD1CC8 /* InstalledSourceView.swift in Sources */,
|
||||||
0C79DC082899AF3C003F1C5A /* SourceSeedLeech+CoreDataProperties.swift in Sources */,
|
0C79DC082899AF3C003F1C5A /* SourceSeedLeech+CoreDataProperties.swift in Sources */,
|
||||||
0CA148DD288903F000DE2211 /* ScrapingViewModel.swift in Sources */,
|
0CA148DD288903F000DE2211 /* ScrapingViewModel.swift in Sources */,
|
||||||
|
0CB6516A28C5B4A600DCA721 /* InlineHeader.swift in Sources */,
|
||||||
0CA148D8288903F000DE2211 /* MagnetChoiceView.swift in Sources */,
|
0CA148D8288903F000DE2211 /* MagnetChoiceView.swift in Sources */,
|
||||||
0C84F4862895BFED0074B7C9 /* SourceList+CoreDataClass.swift in Sources */,
|
0C84F4862895BFED0074B7C9 /* SourceList+CoreDataClass.swift in Sources */,
|
||||||
0C68135028BC1A2D00FAD890 /* GithubWrapper.swift in Sources */,
|
0C68135028BC1A2D00FAD890 /* GithubWrapper.swift in Sources */,
|
||||||
|
|
@ -747,6 +763,14 @@
|
||||||
minimumVersion = 2.0.0;
|
minimumVersion = 2.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
0CB6516628C5A5EC00DCA721 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/siteline/SwiftUI-Introspect";
|
||||||
|
requirement = {
|
||||||
|
branch = master;
|
||||||
|
kind = branch;
|
||||||
|
};
|
||||||
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
|
@ -780,6 +804,11 @@
|
||||||
package = 0CAF1C79286F5C8600296F86 /* XCRemoteSwiftPackageReference "SwiftSoup" */;
|
package = 0CAF1C79286F5C8600296F86 /* XCRemoteSwiftPackageReference "SwiftSoup" */;
|
||||||
productName = SwiftSoup;
|
productName = SwiftSoup;
|
||||||
};
|
};
|
||||||
|
0CB6516728C5A5EC00DCA721 /* Introspect */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 0CB6516628C5A5EC00DCA721 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */;
|
||||||
|
productName = Introspect;
|
||||||
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
|
|
||||||
/* Begin XCVersionGroup section */
|
/* Begin XCVersionGroup section */
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,34 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Introspect
|
||||||
|
|
||||||
extension View {
|
extension View {
|
||||||
|
// MARK: Custom introspect functions
|
||||||
|
|
||||||
|
func introspectCollectionView(customize: @escaping (UICollectionView) -> ()) -> some View {
|
||||||
|
return inject(UIKitIntrospectionView(
|
||||||
|
selector: { introspectionView in
|
||||||
|
guard let viewHost = Introspect.findViewHost(from: introspectionView) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return Introspect.previousSibling(containing: UICollectionView.self, from: viewHost)
|
||||||
|
},
|
||||||
|
customize: customize
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Modifiers
|
// MARK: Modifiers
|
||||||
|
|
||||||
func dynamicAccentColor(_ color: Color) -> some View {
|
func dynamicAccentColor(_ color: Color) -> some View {
|
||||||
modifier(DynamicAccentColor(color: color))
|
modifier(DynamicAccentColor(color: color))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func conditionalId<ID: Hashable>(_ id: ID) -> some View {
|
||||||
|
modifier(ConditionalId(id: id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func inlinedList() -> some View {
|
||||||
|
modifier(InlinedList())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
Ferrite/Views/CommonViews/ConditionalId.swift
Normal file
24
Ferrite/Views/CommonViews/ConditionalId.swift
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
//
|
||||||
|
// ConditionalId.swift
|
||||||
|
// Ferrite
|
||||||
|
//
|
||||||
|
// Created by Brian Dashore on 9/4/22.
|
||||||
|
//
|
||||||
|
// Only applies an ID for below iOS 16
|
||||||
|
// This is due to ID workarounds making iOS 16 apps crash
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ConditionalId<ID: Hashable>: ViewModifier {
|
||||||
|
let id: ID
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
if #available(iOS 16, *) {
|
||||||
|
content
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
.id(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
Ferrite/Views/CommonViews/InlineHeader.swift
Normal file
30
Ferrite/Views/CommonViews/InlineHeader.swift
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// InlineHeader.swift
|
||||||
|
// Ferrite
|
||||||
|
//
|
||||||
|
// Created by Brian Dashore on 9/5/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct InlineHeader: View {
|
||||||
|
let title: String
|
||||||
|
|
||||||
|
init(_ title: String) {
|
||||||
|
self.title = title
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Group {
|
||||||
|
if #available(iOS 16, *) {
|
||||||
|
Text(title)
|
||||||
|
.padding(.vertical, 5)
|
||||||
|
} else {
|
||||||
|
Text(title)
|
||||||
|
.padding(.vertical, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 20)
|
||||||
|
.listRowInsets(EdgeInsets())
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Ferrite/Views/CommonViews/InlinedList.swift
Normal file
28
Ferrite/Views/CommonViews/InlinedList.swift
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// InlinedList.swift
|
||||||
|
// Ferrite
|
||||||
|
//
|
||||||
|
// Created by Brian Dashore on 9/4/22.
|
||||||
|
//
|
||||||
|
// Removes the top padding on lists for iOS 16
|
||||||
|
// Use UITableView.appearance().contentInset.top = -20 for iOS 15 and below in the App file
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import Introspect
|
||||||
|
|
||||||
|
struct InlinedList: ViewModifier {
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
if #available(iOS 16, *) {
|
||||||
|
content
|
||||||
|
.introspectCollectionView { collectionView in
|
||||||
|
collectionView.contentInset.top = -20
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
.introspectTableView { tableView in
|
||||||
|
tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 20))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,6 +54,7 @@ struct SearchResultsView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.insetGrouped)
|
.listStyle(.insetGrouped)
|
||||||
|
.inlinedList()
|
||||||
.overlay {
|
.overlay {
|
||||||
if scrapingModel.searchResults.isEmpty {
|
if scrapingModel.searchResults.isEmpty {
|
||||||
if navModel.showSearchProgress {
|
if navModel.showSearchProgress {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Introspect
|
||||||
|
|
||||||
struct SettingsView: View {
|
struct SettingsView: View {
|
||||||
@EnvironmentObject var debridManager: DebridManager
|
@EnvironmentObject var debridManager: DebridManager
|
||||||
|
|
@ -21,7 +22,7 @@ struct SettingsView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavView {
|
NavView {
|
||||||
Form {
|
Form {
|
||||||
Section(header: "Debrid services") {
|
Section(header: InlineHeader("Debrid Services")) {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Real Debrid")
|
Text("Real Debrid")
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
@ -40,11 +41,11 @@ struct SettingsView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(header: "Source management") {
|
Section(header: InlineHeader("Source management")) {
|
||||||
NavigationLink("Source lists", destination: SettingsSourceListView())
|
NavigationLink("Source lists", destination: SettingsSourceListView())
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(header: "Default actions") {
|
Section(header: InlineHeader("Default actions")) {
|
||||||
if debridManager.realDebridEnabled {
|
if debridManager.realDebridEnabled {
|
||||||
NavigationLink(
|
NavigationLink(
|
||||||
destination: DebridActionPickerView(),
|
destination: DebridActionPickerView(),
|
||||||
|
|
@ -94,14 +95,14 @@ struct SettingsView: View {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(header: Text("Updates")) {
|
Section(header: InlineHeader("Updates")) {
|
||||||
Toggle(isOn: $autoUpdateNotifs) {
|
Toggle(isOn: $autoUpdateNotifs) {
|
||||||
Text("Show update alerts")
|
Text("Show update alerts")
|
||||||
}
|
}
|
||||||
NavigationLink("Version history", destination: SettingsAppVersionView())
|
NavigationLink("Version history", destination: SettingsAppVersionView())
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(header: Text("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")
|
||||||
NavigationLink("About", destination: AboutView())
|
NavigationLink("About", destination: AboutView())
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ struct MagnetActionPickerView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.insetGrouped)
|
.listStyle(.insetGrouped)
|
||||||
|
.inlinedList()
|
||||||
.navigationTitle("Default magnet action")
|
.navigationTitle("Default magnet action")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
}
|
}
|
||||||
|
|
@ -67,6 +68,7 @@ struct DebridActionPickerView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.insetGrouped)
|
.listStyle(.insetGrouped)
|
||||||
|
.inlinedList()
|
||||||
.navigationTitle("Default debrid action")
|
.navigationTitle("Default debrid action")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ struct SettingsAppVersionView: View {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
} else if !releases.isEmpty {
|
} else if !releases.isEmpty {
|
||||||
List {
|
List {
|
||||||
Section(header: Text("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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ struct SettingsSourceListView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.insetGrouped)
|
.listStyle(.insetGrouped)
|
||||||
|
.inlinedList()
|
||||||
.sheet(isPresented: $presentSourceSheet) {
|
.sheet(isPresented: $presentSourceSheet) {
|
||||||
if #available(iOS 16, *) {
|
if #available(iOS 16, *) {
|
||||||
SourceListEditorView(sourceUrl: navModel.selectedSourceList?.urlString ?? "")
|
SourceListEditorView(sourceUrl: navModel.selectedSourceList?.urlString ?? "")
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,10 @@ struct SourceListEditorView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavView {
|
NavView {
|
||||||
Form {
|
Form {
|
||||||
Section {
|
TextField("Enter URL", text: $sourceUrl)
|
||||||
TextField("Enter URL", text: $sourceUrl)
|
.disableAutocorrection(true)
|
||||||
.disableAutocorrection(true)
|
.keyboardType(.URL)
|
||||||
.keyboardType(.URL)
|
.autocapitalization(.none)
|
||||||
.autocapitalization(.none)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
sourceUrl = navModel.selectedSourceList?.urlString ?? ""
|
sourceUrl = navModel.selectedSourceList?.urlString ?? ""
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ struct SourceSettingsView: View {
|
||||||
NavView {
|
NavView {
|
||||||
List {
|
List {
|
||||||
if let selectedSource = navModel.selectedSource {
|
if let selectedSource = navModel.selectedSource {
|
||||||
Section(header: "Info") {
|
Section(header: InlineHeader("Info")) {
|
||||||
VStack(alignment: .leading, spacing: 5) {
|
VStack(alignment: .leading, spacing: 5) {
|
||||||
HStack {
|
HStack {
|
||||||
Text(selectedSource.name)
|
Text(selectedSource.name)
|
||||||
|
|
@ -78,7 +78,7 @@ struct SourceSettingsBaseUrlView: View {
|
||||||
@State private var tempBaseUrl: String = ""
|
@State private var tempBaseUrl: 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: $tempBaseUrl, onEditingChanged: { isFocused in
|
TextField("https://...", text: $tempBaseUrl, onEditingChanged: { isFocused in
|
||||||
|
|
@ -110,7 +110,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 {
|
||||||
|
|
@ -146,7 +146,7 @@ struct SourceSettingsMethodView: View {
|
||||||
@ObservedObject var selectedSource: Source
|
@ObservedObject var selectedSource: Source
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Section(header: Text("Fetch method")) {
|
Section(header: InlineHeader("Fetch method")) {
|
||||||
if selectedSource.api != nil, selectedSource.jsonParser != nil {
|
if selectedSource.api != nil, selectedSource.jsonParser != nil {
|
||||||
Button {
|
Button {
|
||||||
selectedSource.preferredParser = SourcePreferredParser.siteApi.rawValue
|
selectedSource.preferredParser = SourcePreferredParser.siteApi.rawValue
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftUIX
|
import SwiftUIX
|
||||||
|
import Introspect
|
||||||
|
|
||||||
struct SourcesView: View {
|
struct SourcesView: View {
|
||||||
@Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
|
@Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
|
||||||
|
|
@ -65,7 +66,7 @@ struct SourcesView: View {
|
||||||
} else {
|
} else {
|
||||||
List {
|
List {
|
||||||
if !filteredUpdatedSources.isEmpty {
|
if !filteredUpdatedSources.isEmpty {
|
||||||
Section(header: "Updates") {
|
Section(header: InlineHeader("Updates")) {
|
||||||
ForEach(filteredUpdatedSources, id: \.self) { source in
|
ForEach(filteredUpdatedSources, id: \.self) { source in
|
||||||
SourceUpdateButtonView(updatedSource: source)
|
SourceUpdateButtonView(updatedSource: source)
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +74,7 @@ struct SourcesView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !sources.isEmpty {
|
if !sources.isEmpty {
|
||||||
Section(header: "Installed") {
|
Section(header: InlineHeader("Installed")) {
|
||||||
ForEach(sources, id: \.self) { source in
|
ForEach(sources, id: \.self) { source in
|
||||||
InstalledSourceView(installedSource: source)
|
InstalledSourceView(installedSource: source)
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +90,7 @@ struct SourcesView: View {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}) {
|
}) {
|
||||||
Section(header: "Catalog") {
|
Section(header: InlineHeader("Catalog")) {
|
||||||
ForEach(filteredAvailableSources, id: \.self) { availableSource in
|
ForEach(filteredAvailableSources, id: \.self) { availableSource in
|
||||||
if !sources.contains(
|
if !sources.contains(
|
||||||
where: {
|
where: {
|
||||||
|
|
@ -104,6 +105,7 @@ struct SourcesView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.conditionalId(UUID())
|
||||||
.listStyle(.insetGrouped)
|
.listStyle(.insetGrouped)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue