diff --git a/Ferrite.xcodeproj/project.pbxproj b/Ferrite.xcodeproj/project.pbxproj index cb07a28..414aeda 100644 --- a/Ferrite.xcodeproj/project.pbxproj +++ b/Ferrite.xcodeproj/project.pbxproj @@ -78,6 +78,7 @@ 0CBC76FD288D914F0054BE44 /* BatchChoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FC288D914F0054BE44 /* BatchChoiceView.swift */; }; 0CBC76FF288DAAD00054BE44 /* NavigationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */; }; 0CBC7705288DE7F40054BE44 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBC7704288DE7F40054BE44 /* PersistenceController.swift */; }; + 0CDCB91828C662640098B513 /* EmptyInstructionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CDCB91728C662640098B513 /* EmptyInstructionView.swift */; }; 0CFEFCFD288A006200B3F490 /* GroupBoxStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CFEFCFC288A006200B3F490 /* GroupBoxStyle.swift */; }; /* End PBXBuildFile section */ @@ -148,6 +149,7 @@ 0CBC76FE288DAAD00054BE44 /* NavigationViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewModel.swift; sourceTree = ""; }; 0CBC7704288DE7F40054BE44 /* PersistenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = ""; }; 0CC6E4D428A45BA000AF2BCC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 0CDCB91728C662640098B513 /* EmptyInstructionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyInstructionView.swift; sourceTree = ""; }; 0CFEFCFC288A006200B3F490 /* GroupBoxStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupBoxStyle.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -252,6 +254,7 @@ 0CB6516228C5A57300DCA721 /* ConditionalId.swift */, 0CB6516428C5A5D700DCA721 /* InlinedList.swift */, 0CB6516928C5B4A600DCA721 /* InlineHeader.swift */, + 0CDCB91728C662640098B513 /* EmptyInstructionView.swift */, ); path = CommonViews; sourceTree = ""; @@ -482,6 +485,7 @@ 0C794B67289DACB600DD1CC8 /* SourceUpdateButtonView.swift in Sources */, 0CA148E6288903F000DE2211 /* WebView.swift in Sources */, 0C4CFC4E28970C8B00AD9FAD /* SourceComplexQuery+CoreDataProperties.swift in Sources */, + 0CDCB91828C662640098B513 /* EmptyInstructionView.swift in Sources */, 0CA148E2288903F000DE2211 /* Data.swift in Sources */, 0C57D4CC289032ED008534E8 /* SearchResultRDView.swift in Sources */, 0C7D11FC28AA01E900ED92DB /* DynamicAccentColor.swift in Sources */, diff --git a/Ferrite/Extensions/View.swift b/Ferrite/Extensions/View.swift index c0290fd..d1dc471 100644 --- a/Ferrite/Extensions/View.swift +++ b/Ferrite/Extensions/View.swift @@ -5,14 +5,14 @@ // Created by Brian Dashore on 8/15/22. // -import SwiftUI import Introspect +import SwiftUI extension View { // MARK: Custom introspect functions - func introspectCollectionView(customize: @escaping (UICollectionView) -> ()) -> some View { - return inject(UIKitIntrospectionView( + func introspectCollectionView(customize: @escaping (UICollectionView) -> Void) -> some View { + inject(UIKitIntrospectionView( selector: { introspectionView in guard let viewHost = Introspect.findViewHost(from: introspectionView) else { return nil diff --git a/Ferrite/Views/AboutView.swift b/Ferrite/Views/AboutView.swift index 6ee081a..2933955 100644 --- a/Ferrite/Views/AboutView.swift +++ b/Ferrite/Views/AboutView.swift @@ -21,7 +21,7 @@ struct AboutView: View { Image("AppImage") .resizable() .frame(width: 100, height: 100) - .clipShape(RoundedRectangle(cornerRadius: 100*0.225, style: .continuous)) + .clipShape(RoundedRectangle(cornerRadius: 100 * 0.225, style: .continuous)) .padding(.top, 24) Text("Ferrite is a free and open source application developed by kingbri under the GNU-GPLv3 license.") diff --git a/Ferrite/Views/BatchChoiceView.swift b/Ferrite/Views/BatchChoiceView.swift index 54b6237..692855c 100644 --- a/Ferrite/Views/BatchChoiceView.swift +++ b/Ferrite/Views/BatchChoiceView.swift @@ -38,6 +38,7 @@ struct BatchChoiceView: View { presentationMode.wrappedValue.dismiss() } + .dynamicAccentColor(.primary) } } .listStyle(.insetGrouped) diff --git a/Ferrite/Views/CommonViews/EmptyInstructionView.swift b/Ferrite/Views/CommonViews/EmptyInstructionView.swift new file mode 100644 index 0000000..8cd0055 --- /dev/null +++ b/Ferrite/Views/CommonViews/EmptyInstructionView.swift @@ -0,0 +1,27 @@ +// +// EmptyInstructionView.swift +// Ferrite +// +// Created by Brian Dashore on 9/5/22. +// + +import SwiftUI + +struct EmptyInstructionView: View { + let title: String + let message: String + + var body: some View { + VStack(spacing: 5) { + Text(title) + .font(.system(size: 25, weight: .semibold)) + + Text(message) + .padding(.horizontal, 50) + } + .multilineTextAlignment(.center) + .foregroundColor(.secondaryLabel) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .ignoresSafeArea() + } +} diff --git a/Ferrite/Views/CommonViews/InlineHeader.swift b/Ferrite/Views/CommonViews/InlineHeader.swift index dbb70c4..faff7b7 100644 --- a/Ferrite/Views/CommonViews/InlineHeader.swift +++ b/Ferrite/Views/CommonViews/InlineHeader.swift @@ -4,6 +4,8 @@ // // Created by Brian Dashore on 9/5/22. // +// For iOS 15's weird defaults regarding sectioned list padding +// import SwiftUI @@ -15,16 +17,13 @@ struct InlineHeader: View { } var body: some View { - Group { - if #available(iOS 16, *) { - Text(title) - .padding(.vertical, 5) - } else { - Text(title) - .padding(.vertical, 10) - } + if #available(iOS 16, *) { + Text(title) + } else if #available(iOS 15, *) { + Text(title) + .listRowInsets(EdgeInsets(top: 10, leading: 15, bottom: 0, trailing: 0)) + } else { + Text(title) } - .padding(.horizontal, 20) - .listRowInsets(EdgeInsets()) } } diff --git a/Ferrite/Views/CommonViews/InlinedList.swift b/Ferrite/Views/CommonViews/InlinedList.swift index 572693e..a0eb034 100644 --- a/Ferrite/Views/CommonViews/InlinedList.swift +++ b/Ferrite/Views/CommonViews/InlinedList.swift @@ -8,8 +8,8 @@ // Use UITableView.appearance().contentInset.top = -20 for iOS 15 and below in the App file // -import SwiftUI import Introspect +import SwiftUI struct InlinedList: ViewModifier { func body(content: Content) -> some View { diff --git a/Ferrite/Views/SettingsView.swift b/Ferrite/Views/SettingsView.swift index 9d9c1d9..1531a9a 100644 --- a/Ferrite/Views/SettingsView.swift +++ b/Ferrite/Views/SettingsView.swift @@ -5,8 +5,8 @@ // Created by Brian Dashore on 7/11/22. // -import SwiftUI import Introspect +import SwiftUI struct SettingsView: View { @EnvironmentObject var debridManager: DebridManager @@ -41,11 +41,11 @@ struct SettingsView: View { } } - Section(header: InlineHeader("Source management")) { + Section(header: Text("Source management")) { NavigationLink("Source lists", destination: SettingsSourceListView()) } - Section(header: InlineHeader("Default actions")) { + Section(header: Text("Default actions")) { if debridManager.realDebridEnabled { NavigationLink( destination: DebridActionPickerView(), @@ -95,14 +95,14 @@ struct SettingsView: View { ) } - Section(header: InlineHeader("Updates")) { + Section(header: Text("Updates")) { Toggle(isOn: $autoUpdateNotifs) { Text("Show update alerts") } NavigationLink("Version history", destination: SettingsAppVersionView()) } - Section(header: InlineHeader("Information")) { + Section(header: Text("Information")) { ListRowLinkView(text: "Donate", link: "https://ko-fi.com/kingbri") ListRowLinkView(text: "Report issues", link: "https://github.com/bdashore3/Ferrite/issues") NavigationLink("About", destination: AboutView()) diff --git a/Ferrite/Views/SettingsViews/SettingsAppVersionView.swift b/Ferrite/Views/SettingsViews/SettingsAppVersionView.swift index be1d19f..f15f15d 100644 --- a/Ferrite/Views/SettingsViews/SettingsAppVersionView.swift +++ b/Ferrite/Views/SettingsViews/SettingsAppVersionView.swift @@ -41,6 +41,7 @@ struct SettingsAppVersionView: View { } catch { toastModel.updateToastDescription("Github error: \(error)") } + withAnimation { loadedReleases = true } diff --git a/Ferrite/Views/SettingsViews/SettingsSourceListView.swift b/Ferrite/Views/SettingsViews/SettingsSourceListView.swift index 320ab00..cc1032e 100644 --- a/Ferrite/Views/SettingsViews/SettingsSourceListView.swift +++ b/Ferrite/Views/SettingsViews/SettingsSourceListView.swift @@ -21,58 +21,60 @@ struct SettingsSourceListView: View { @State private var selectedSourceList: SourceList? var body: some View { - List { + ZStack { if sourceLists.isEmpty { - Text("No source lists") + EmptyInstructionView(title: "No Lists", message: "Add a source list using the + button in the top-right") } else { - ForEach(sourceLists, id: \.self) { sourceList in - VStack(alignment: .leading, spacing: 5) { - Text(sourceList.name) + List { + ForEach(sourceLists, id: \.self) { sourceList in + VStack(alignment: .leading, spacing: 5) { + Text(sourceList.name) - Text(sourceList.author) - .foregroundColor(.gray) + Text(sourceList.author) + .foregroundColor(.gray) - Text("ID: \(sourceList.id)") - .font(.caption) - .foregroundColor(.gray) - } - .padding(.vertical, 2) - .contextMenu { - Button { - navModel.selectedSourceList = sourceList - presentSourceSheet.toggle() - } label: { - Text("Edit") - Image(systemName: "pencil") + Text("ID: \(sourceList.id)") + .font(.caption) + .foregroundColor(.gray) } - - if #available(iOS 15.0, *) { - Button(role: .destructive) { - PersistenceController.shared.delete(sourceList, context: backgroundContext) - } label: { - Text("Remove") - Image(systemName: "trash") - } - } else { + .padding(.vertical, 2) + .contextMenu { Button { - PersistenceController.shared.delete(sourceList, context: backgroundContext) + navModel.selectedSourceList = sourceList + presentSourceSheet.toggle() } label: { - Text("Remove") - Image(systemName: "trash") + Text("Edit") + Image(systemName: "pencil") + } + + if #available(iOS 15.0, *) { + Button(role: .destructive) { + PersistenceController.shared.delete(sourceList, context: backgroundContext) + } label: { + Text("Remove") + Image(systemName: "trash") + } + } else { + Button { + PersistenceController.shared.delete(sourceList, context: backgroundContext) + } label: { + Text("Remove") + Image(systemName: "trash") + } } } } } + .listStyle(.insetGrouped) + .inlinedList() } } - .listStyle(.insetGrouped) - .inlinedList() .sheet(isPresented: $presentSourceSheet) { if #available(iOS 16, *) { - SourceListEditorView(sourceUrl: navModel.selectedSourceList?.urlString ?? "") + SourceListEditorView() .presentationDetents([.medium]) } else { - SourceListEditorView(sourceUrl: navModel.selectedSourceList?.urlString ?? "") + SourceListEditorView() } } .navigationTitle("Source Lists") diff --git a/Ferrite/Views/SettingsViews/SourceListEditorView.swift b/Ferrite/Views/SettingsViews/SourceListEditorView.swift index 4b9a728..5ddfae3 100644 --- a/Ferrite/Views/SettingsViews/SourceListEditorView.swift +++ b/Ferrite/Views/SettingsViews/SourceListEditorView.swift @@ -15,11 +15,9 @@ struct SourceListEditorView: View { let backgroundContext = PersistenceController.shared.backgroundContext - @State private var sourceUrl: String + @State private var sourceUrlSet = false - init(sourceUrl: String = "") { - _sourceUrl = State(initialValue: sourceUrl) - } + @State private var sourceUrl: String = "" var body: some View { NavView { @@ -28,9 +26,11 @@ struct SourceListEditorView: View { .disableAutocorrection(true) .keyboardType(.URL) .autocapitalization(.none) + .conditionalId(sourceUrlSet) } .onAppear { sourceUrl = navModel.selectedSourceList?.urlString ?? "" + sourceUrlSet = true } .alert(isPresented: $sourceManager.showUrlErrorAlert) { Alert( diff --git a/Ferrite/Views/SourcesView.swift b/Ferrite/Views/SourcesView.swift index 6a99021..2d1ab4b 100644 --- a/Ferrite/Views/SourcesView.swift +++ b/Ferrite/Views/SourcesView.swift @@ -5,13 +5,11 @@ // Created by Brian Dashore on 7/24/22. // +import Introspect import SwiftUI import SwiftUIX -import Introspect struct SourcesView: View { - @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass? - @EnvironmentObject var sourceManager: SourceManager @EnvironmentObject var navModel: NavigationViewModel @@ -53,15 +51,8 @@ struct SourcesView: View { ZStack { if !checkedForSources { ProgressView() - } else if sources.isEmpty && sourceManager.availableSources.isEmpty { - VStack { - Text("No Sources") - .font(.system(size: 25, weight: .semibold)) - .foregroundColor(.secondaryLabel) - Text("Add a source list in Settings") - .foregroundColor(.secondaryLabel) - } - .padding(.top, verticalSizeClass == .regular ? -50 : 0) + } else if sources.isEmpty, sourceManager.availableSources.isEmpty { + EmptyInstructionView(title: "No Sources", message: "Add a source list in Settings") } else { List { if !filteredUpdatedSources.isEmpty { @@ -80,12 +71,12 @@ struct SourcesView: View { } } - if !filteredAvailableSources.isEmpty && sourceManager.availableSources.contains(where: { availableSource in + if !filteredAvailableSources.isEmpty, sourceManager.availableSources.contains(where: { availableSource in !sources.contains( where: { availableSource.name == $0.name && - availableSource.listId == $0.listId && - availableSource.author == $0.author + availableSource.listId == $0.listId && + availableSource.author == $0.author } ) }) { @@ -94,8 +85,8 @@ struct SourcesView: View { if !sources.contains( where: { availableSource.name == $0.name && - availableSource.listId == $0.listId && - availableSource.author == $0.author + availableSource.listId == $0.listId && + availableSource.author == $0.author } ) { SourceCatalogButtonView(availableSource: availableSource) @@ -131,7 +122,7 @@ struct SourcesView: View { searchText = "" } } - .onChange(of: searchText) { newValue in + .onChange(of: searchText) { _ in filteredAvailableSources = sourceManager.availableSources.filter { searchText.isEmpty ? true : $0.name.contains(searchText) } filteredUpdatedSources = updatedSources.filter { searchText.isEmpty ? true : $0.name.contains(searchText) } if #available(iOS 15.0, *) {