From f7e1b87c73009b142ca35c5839a2dfdc4d7bd9f4 Mon Sep 17 00:00:00 2001 From: Skitty Date: Sun, 4 Sep 2022 14:14:34 -0500 Subject: [PATCH] Various UI tweaks - Make about header scrollable - Add no sources text - Add no source lists text - Make edit source list start with current url - Add loading indicator for versions --- Ferrite/Views/AboutView.swift | 29 ++++--- Ferrite/Views/ContentView.swift | 8 +- .../SettingsAppVersionView.swift | 21 +++-- .../SettingsSourceListView.swift | 27 +++++-- .../SettingsViews/SourceListEditorView.swift | 6 +- Ferrite/Views/SourcesView.swift | 80 ++++++++++++------- 6 files changed, 111 insertions(+), 60 deletions(-) diff --git a/Ferrite/Views/AboutView.swift b/Ferrite/Views/AboutView.swift index b2285aa..70e8934 100644 --- a/Ferrite/Views/AboutView.swift +++ b/Ferrite/Views/AboutView.swift @@ -9,24 +9,31 @@ import SwiftUI struct AboutView: View { var body: some View { - VStack { - Image("AppImage") - .resizable() - .frame(width: 100, height: 100) - .cornerRadius(25) - - Text("Ferrite is a free and open source application developed by kingbri under the GNU-GPLv3 license.") - .padding() - - List { + List { + Section { ListRowTextView(leftText: "Version", rightText: UIApplication.shared.appVersion) ListRowTextView(leftText: "Build number", rightText: UIApplication.shared.appBuild) ListRowTextView(leftText: "Build type", rightText: UIApplication.shared.buildType) ListRowLinkView(text: "Discord server", link: "https://discord.gg/sYQxnuD7Fj") ListRowLinkView(text: "GitHub repository", link: "https://github.com/bdashore3/Ferrite") + } header: { + VStack(alignment: .center) { + Image("AppImage") + .resizable() + .frame(width: 100, height: 100) + .clipShape(RoundedRectangle(cornerRadius: 100*0.225, style: .continuous)) + + Text("Ferrite is a free and open source application developed by kingbri under the GNU-GPLv3 license.") + .textCase(.none) + .foregroundColor(.label) + .font(.body) + .padding(.top, 8) + .padding(.bottom, 20) + } + .listRowInsets(EdgeInsets(top: 0, leading: 7, bottom: 0, trailing: 0)) } - .listStyle(.insetGrouped) } + .listStyle(.insetGrouped) .navigationTitle("About") } } diff --git a/Ferrite/Views/ContentView.swift b/Ferrite/Views/ContentView.swift index 6f92f4f..1d9a60f 100644 --- a/Ferrite/Views/ContentView.swift +++ b/Ferrite/Views/ContentView.swift @@ -30,7 +30,7 @@ struct ContentView: View { var body: some View { NavView { VStack(spacing: 10) { - HStack { + HStack(spacing: 6) { Text("Filter") .foregroundColor(.secondary) @@ -50,10 +50,10 @@ struct ContentView: View { Button { selectedSource = source } label: { - Text(name) - if selectedSource == source { - Image(systemName: "checkmark") + Label(name, systemImage: "checkmark") + } else { + Text(name) } } } diff --git a/Ferrite/Views/SettingsViews/SettingsAppVersionView.swift b/Ferrite/Views/SettingsViews/SettingsAppVersionView.swift index eaf87eb..1a31c91 100644 --- a/Ferrite/Views/SettingsViews/SettingsAppVersionView.swift +++ b/Ferrite/Views/SettingsViews/SettingsAppVersionView.swift @@ -6,6 +6,7 @@ // import SwiftUI +import SwiftUIX struct SettingsAppVersionView: View { @EnvironmentObject var toastModel: ToastViewModel @@ -14,18 +15,27 @@ struct SettingsAppVersionView: View { @State private var releases: [GithubRelease] = [] var body: some View { - List { - Section(header: Text("GitHub links")) { - ForEach(releases, id: \.self) { release in - ListRowLinkView(text: release.tagName, link: release.htmlUrl) + ZStack { + if releases.isEmpty { + ActivityIndicator() + } else { + List { + Section(header: Text("GitHub links")) { + ForEach(releases, id: \.self) { release in + ListRowLinkView(text: release.tagName, link: release.htmlUrl) + } + } } + .listStyle(.insetGrouped) } } .onAppear { viewTask = Task { do { if let fetchedReleases = try await Github().fetchReleases() { - releases = fetchedReleases + withAnimation { + releases = fetchedReleases + } } else { toastModel.updateToastDescription("Github error: No releases found") } @@ -37,7 +47,6 @@ struct SettingsAppVersionView: View { .onDisappear { viewTask?.cancel() } - .listStyle(.insetGrouped) .navigationTitle("Version history") .navigationBarTitleDisplayMode(.inline) } diff --git a/Ferrite/Views/SettingsViews/SettingsSourceListView.swift b/Ferrite/Views/SettingsViews/SettingsSourceListView.swift index 38f3618..42f7995 100644 --- a/Ferrite/Views/SettingsViews/SettingsSourceListView.swift +++ b/Ferrite/Views/SettingsViews/SettingsSourceListView.swift @@ -22,7 +22,9 @@ struct SettingsSourceListView: View { var body: some View { List { - Section(header: Text("List information")) { + if sourceLists.isEmpty { + Text("No source lists") + } else { ForEach(sourceLists, id: \.self) { sourceList in VStack(alignment: .leading, spacing: 5) { Text(sourceList.name) @@ -43,11 +45,20 @@ struct SettingsSourceListView: View { Image(systemName: "pencil") } - Button { - PersistenceController.shared.delete(sourceList, context: backgroundContext) - } label: { - Text("Remove") - Image(systemName: "trash") + 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") + } } } } @@ -56,10 +67,10 @@ struct SettingsSourceListView: View { .listStyle(.insetGrouped) .sheet(isPresented: $presentSourceSheet) { if #available(iOS 16, *) { - SourceListEditorView() + SourceListEditorView(sourceUrl: navModel.selectedSourceList?.urlString ?? "") .presentationDetents([.medium]) } else { - SourceListEditorView() + SourceListEditorView(sourceUrl: navModel.selectedSourceList?.urlString ?? "") } } .navigationTitle("Source lists") diff --git a/Ferrite/Views/SettingsViews/SourceListEditorView.swift b/Ferrite/Views/SettingsViews/SourceListEditorView.swift index 9db11c7..d82d367 100644 --- a/Ferrite/Views/SettingsViews/SourceListEditorView.swift +++ b/Ferrite/Views/SettingsViews/SourceListEditorView.swift @@ -15,7 +15,11 @@ struct SourceListEditorView: View { let backgroundContext = PersistenceController.shared.backgroundContext - @State private var sourceUrl = "" + @State private var sourceUrl: String + + init(sourceUrl: String = "") { + _sourceUrl = State(initialValue: sourceUrl) + } var body: some View { NavView { diff --git a/Ferrite/Views/SourcesView.swift b/Ferrite/Views/SourcesView.swift index 570c92b..283bbf7 100644 --- a/Ferrite/Views/SourcesView.swift +++ b/Ferrite/Views/SourcesView.swift @@ -6,8 +6,11 @@ // import SwiftUI +import SwiftUIX struct SourcesView: View { + @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass? + @EnvironmentObject var sourceManager: SourceManager @EnvironmentObject var navModel: NavigationViewModel @@ -37,51 +40,67 @@ struct SourcesView: View { } @State private var viewTask: Task? = nil + @State private var checkedForSources = false var body: some View { NavView { - List { - if !updatedSources.isEmpty { - Section(header: "Updates") { - ForEach(updatedSources, id: \.self) { source in - SourceUpdateButtonView(updatedSource: source) - } + ZStack { + if !checkedForSources { + ActivityIndicator() + } 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) } - } - - if !sources.isEmpty { - Section(header: "Installed") { - ForEach(sources, id: \.self) { source in - InstalledSourceView(installedSource: source) + .padding(.top, verticalSizeClass == .regular ? -50 : 0) + } else { + List { + if !updatedSources.isEmpty { + Section(header: "Updates") { + ForEach(updatedSources, id: \.self) { source in + SourceUpdateButtonView(updatedSource: source) + } + } } - } - } - if sourceManager.availableSources.contains(where: { availableSource in - !sources.contains( - where: { - availableSource.name == $0.name && - availableSource.listId == $0.listId && - availableSource.author == $0.author + if !sources.isEmpty { + Section(header: "Installed") { + ForEach(sources, id: \.self) { source in + InstalledSourceView(installedSource: source) + } + } } - ) - }) { - Section(header: "Catalog") { - ForEach(sourceManager.availableSources, id: \.self) { availableSource in - if !sources.contains( + + if 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 + } + ) + }) { + Section(header: "Catalog") { + ForEach(sourceManager.availableSources, id: \.self) { availableSource in + if !sources.contains( + where: { + availableSource.name == $0.name && + availableSource.listId == $0.listId && + availableSource.author == $0.author + } + ) { + SourceCatalogButtonView(availableSource: availableSource) + } } - ) { - SourceCatalogButtonView(availableSource: availableSource) } } } + .listStyle(.insetGrouped) } } - .listStyle(.insetGrouped) .sheet(isPresented: $navModel.showSourceSettings) { SourceSettingsView() .environmentObject(navModel) @@ -89,6 +108,7 @@ struct SourcesView: View { .onAppear { viewTask = Task { await sourceManager.fetchSourcesFromUrl() + checkedForSources = true } } .onDisappear {