aboutsummaryrefslogtreecommitdiff
path: root/Hotline/macOS/AboutView.swift
diff options
context:
space:
mode:
authorDustin Mierau <dustin@mierau.me>2024-05-06 14:07:20 -0700
committerDustin Mierau <dustin@mierau.me>2024-05-06 14:07:20 -0700
commit3a4e4a1822d9f091a5df8e5259a24ce6f39e943e (patch)
treec92af0fb911554fec64923a8f3327e48f2addc59 /Hotline/macOS/AboutView.swift
parent379a95f09cd1b9c9e42c6db0f3937879ab17616e (diff)
Add list of contributors to About Box (automatically pulled from GitHub)
Diffstat (limited to 'Hotline/macOS/AboutView.swift')
-rw-r--r--Hotline/macOS/AboutView.swift220
1 files changed, 169 insertions, 51 deletions
diff --git a/Hotline/macOS/AboutView.swift b/Hotline/macOS/AboutView.swift
index acf79b5..7bd1c54 100644
--- a/Hotline/macOS/AboutView.swift
+++ b/Hotline/macOS/AboutView.swift
@@ -7,73 +7,191 @@ enum VersionCheckState {
case updateAvailable(version: String)
}
+struct AboutContributor: Identifiable {
+ let id: UUID = UUID()
+ let username: String
+ let webURL: URL
+ let pictureURL: URL?
+}
+
struct AboutView: View {
@Environment(\.openURL) private var openURL
@State private var versionCheck: VersionCheckState = .needToCheck
@State private var downloadURL: String = "https://github.com/mierau/hotline/releases/latest"
+ @State private var contributors: [AboutContributor] = []
var body: some View {
- VStack(alignment: .center, spacing: 0) {
- Spacer()
-
- Image("About Hotline")
- .padding(.top, 32)
-
- Text("Hotline")
- .font(.title)
- .fontWeight(.semibold)
- .padding(.top, 16)
- .foregroundColor(.white)
-
- let appDetails = getAppVersionAndBuild()
- Text("\(String(format: "%.1f", appDetails.version))b\(appDetails.build)")
- .fontWeight(.semibold)
- .foregroundColor(.white)
- .opacity(0.6)
-
- HStack(alignment: .center) {
- switch versionCheck {
- case .needToCheck:
- Button("Check for Updates") {
- Task {
- await checkForUpdate()
+ HStack(alignment: .center, spacing: 0) {
+ VStack(alignment: .center, spacing: 0) {
+ Spacer()
+
+ Image("About Hotline")
+ .padding(.top, 44)
+
+ Text("Hotline")
+ .font(.system(size: 28))
+ .fontWeight(.bold)
+ .padding(.top, 12)
+ .kerning(-1.0)
+ .foregroundColor(.white)
+
+ let appDetails = getAppVersionAndBuild()
+ Text("Version \(String(format: "%.1f", appDetails.version))b\(appDetails.build)")
+ .foregroundColor(.white)
+ .opacity(0.4)
+
+ HStack(alignment: .center) {
+ switch versionCheck {
+ case .needToCheck:
+ Button("Check for Updates") {
+ Task {
+ await checkForUpdate()
+ }
+ }
+ .controlSize(.small)
+ case .checking:
+ HStack(spacing: 8) {
+ ProgressView()
+ .controlSize(.small)
+ Text("Checking for updates...")
+ .fontWeight(.semibold)
}
- }
- .controlSize(.regular)
- case .checking:
- HStack(spacing: 8) {
- ProgressView()
- .controlSize(.small)
- .tint(.white)
- Text("Checking for updates...")
- .fontWeight(.semibold)
- .foregroundStyle(.white)
- }
- case .upToDate:
- Label("Hotline is up to date.", systemImage: "checkmark.circle.fill")
.foregroundStyle(.white)
- .fontWeight(.semibold)
.tint(.white)
- .onTapGesture {
- versionCheck = .needToCheck
+ case .upToDate:
+ Label("Hotline is up to date.", systemImage: "checkmark.circle.fill")
+ .foregroundStyle(.white)
+ .fontWeight(.semibold)
+ .tint(.white)
+ .onTapGesture {
+ versionCheck = .needToCheck
+ }
+ case .updateAvailable(let version):
+ Button("Download Latest \(version)") {
+ if let url = URL(string: downloadURL) {
+ openURL(url)
+ }
}
- case .updateAvailable(let version):
- Button("Download Latest \(version)") {
- if let url = URL(string: downloadURL) {
- openURL(url)
+ .controlSize(.small)
+ }
+ }
+ .frame(height: 40)
+// .padding(.top, 4)
+
+ Spacer()
+ }
+ .frame(width: 270)
+
+ ScrollView(.vertical) {
+ VStack(alignment: .leading, spacing: 16) {
+
+ VStack(alignment: .leading, spacing: 4) {
+ Link(destination: URL(string: "https://github.com/mierau/hotline")!) {
+ HStack(alignment: .center) {
+ Text("GitHub Contributors")
+ .lineLimit(1)
+ .font(.system(size: 16))
+ .fontWeight(.semibold)
+ .foregroundStyle(.black)
+ .opacity(0.5)
+
+ Image(systemName: "arrow.forward.circle.fill")
+ .resizable()
+ .scaledToFit()
+ .frame(width: 16, height: 16)
+ .foregroundStyle(.black)
+ .opacity(0.5)
+ }
+ }
+ .padding(.top, 24)
+
+ Text("Hotline is an open source project made possible by its contributors.")
+ .font(.system(size: 11))
+ .foregroundStyle(.black)
+ .blendMode(.overlay)
+ .padding(.trailing, 32)
+ }
+ .padding(.bottom, 8)
+
+ ForEach(contributors) { contributor in
+ Link(destination: contributor.webURL) {
+ HStack {
+ if let pictureURL = contributor.pictureURL {
+ AsyncImage(url: pictureURL) { img in
+ img
+ .interpolation(.high)
+ .resizable()
+ .scaledToFit()
+ .background(.white)
+ } placeholder: {
+ Color.white.opacity(0.2)
+ }
+ .frame(width: 32, height: 32)
+ .clipShape(Circle())
+ }
+
+ VStack(alignment: .leading, spacing: 2) {
+ Text(contributor.username)
+ .fontWeight(.semibold)
+ .foregroundStyle(.white)
+ .lineLimit(1)
+
+ Text(contributor.webURL.absoluteString)
+ .lineLimit(1)
+ .truncationMode(.middle)
+ .font(.system(size: 11))
+ .foregroundStyle(.white.opacity(0.4))
+ }
+
+ Spacer()
+ }
}
}
- .controlSize(.regular)
}
}
- .frame(height: 40)
- .padding(.top, 8)
-
- Spacer()
+ .ignoresSafeArea()
+ .scrollClipDisabled()
+ .padding(.leading, 24)
}
- .frame(width: 300, height: 400)
- .ignoresSafeArea()
+ .frame(width: 570, height: 330)
+ .background(
+ VStack(alignment: .leading, spacing: 0) {
+ HStack(alignment: .center, spacing: 0) {
+ Divider()
+ Spacer()
+ }
+ .frame(height: 330 + 100)
+ .offset(x: 270)
+ }
+ )
+ .background(Color.hotlineRed)
+ .task {
+ await loadContributors()
+ }
+ }
+
+ func loadContributors() async {
+ var newContributors: [AboutContributor] = []
+
+ if let url = URL(string: "https://api.github.com/repos/mierau/hotline/contributors"),
+ let (data, _) = try? await URLSession.shared.data(from: url) {
+ if let jsonContributors = try? JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] {
+ for contributor in jsonContributors {
+ if let username = contributor["login"] as? String,
+ let webURLString = contributor["html_url"] as? String,
+ let webURL = URL(string: webURLString) {
+ var pictureURL: URL? = nil
+ if let pictureURLString = contributor["avatar_url"] as? String {
+ pictureURL = URL(string: pictureURLString)
+ }
+ newContributors.append(AboutContributor(username: username, webURL: webURL, pictureURL: pictureURL))
+ }
+ }
+ }
+ }
+
+ contributors = newContributors
}
func checkForUpdate() async {