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
This commit is contained in:
parent
3540e0bcd3
commit
f7e1b87c73
6 changed files with 111 additions and 60 deletions
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<Void, Never>? = 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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue