From 14439f50ff67b8edc0ab3937962f24c288a57c0a Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Jan 2026 16:28:52 +0000 Subject: [PATCH 1/2] feat: Add Credits page accessible from Settings - Create CreditsView with placeholder contributors - Contributors can have Torn profile links (auto-generated from ID) - Support for multiple sections (Special Thanks, Beta Testers) - Navigate to Credits via heart icon button in Settings footer --- MacTorn/MacTorn/Views/CreditsView.swift | 173 +++++++++++++++++++++++ MacTorn/MacTorn/Views/SettingsView.swift | 45 ++++-- 2 files changed, 208 insertions(+), 10 deletions(-) create mode 100644 MacTorn/MacTorn/Views/CreditsView.swift diff --git a/MacTorn/MacTorn/Views/CreditsView.swift b/MacTorn/MacTorn/Views/CreditsView.swift new file mode 100644 index 0000000..976d85d --- /dev/null +++ b/MacTorn/MacTorn/Views/CreditsView.swift @@ -0,0 +1,173 @@ +import SwiftUI + +struct CreditsView: View { + @Binding var showCredits: Bool + + // MARK: - Contributors Data + // Format: (name: "Username", tornID: 123456) + // The tornID will automatically link to the Torn profile + + private let specialThanks: [TornContributor] = [ + // TODO: Add contributors here + // Example: TornContributor(name: "bombel", tornID: 2362436), + TornContributor(name: "Placeholder1", tornID: nil), + TornContributor(name: "Placeholder2", tornID: nil), + TornContributor(name: "Placeholder3", tornID: nil), + ] + + private let testers: [TornContributor] = [ + // TODO: Add testers here + TornContributor(name: "TesterPlaceholder1", tornID: nil), + TornContributor(name: "TesterPlaceholder2", tornID: nil), + ] + + var body: some View { + VStack(spacing: 16) { + // Header + VStack(spacing: 8) { + Image(systemName: "heart.fill") + .font(.system(size: 36)) + .foregroundStyle( + LinearGradient( + colors: [.pink, .red], + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + ) + + Text("Credits") + .font(.title2.bold()) + + Text("Thank you for your support!") + .font(.caption) + .foregroundColor(.secondary) + } + + Divider() + + ScrollView { + VStack(spacing: 16) { + // Special Thanks Section + if !specialThanks.isEmpty { + contributorSection( + title: "Special Thanks", + icon: "star.fill", + iconColor: .yellow, + contributors: specialThanks + ) + } + + // Testers Section + if !testers.isEmpty { + contributorSection( + title: "Beta Testers", + icon: "checkmark.seal.fill", + iconColor: .green, + contributors: testers + ) + } + } + .padding(.horizontal) + } + .frame(maxHeight: 200) + + Spacer() + + // Back Button + Button { + showCredits = false + } label: { + HStack(spacing: 4) { + Image(systemName: "chevron.left") + Text("Back to Settings") + } + .font(.caption) + } + .buttonStyle(.plain) + .foregroundColor(.accentColor) + } + .padding() + .frame(width: 320) + } + + // MARK: - Section View + @ViewBuilder + private func contributorSection( + title: String, + icon: String, + iconColor: Color, + contributors: [TornContributor] + ) -> some View { + VStack(alignment: .leading, spacing: 8) { + HStack(spacing: 6) { + Image(systemName: icon) + .foregroundColor(iconColor) + Text(title) + .font(.subheadline.bold()) + } + + VStack(spacing: 4) { + ForEach(contributors) { contributor in + contributorRow(contributor) + } + } + .padding(10) + .frame(maxWidth: .infinity) + .background(Color.secondary.opacity(0.1)) + .cornerRadius(8) + } + } + + // MARK: - Contributor Row + @ViewBuilder + private func contributorRow(_ contributor: TornContributor) -> some View { + if let tornID = contributor.tornID { + Button { + openTornProfile(tornID) + } label: { + HStack { + Text(contributor.name) + .font(.caption) + Spacer() + Image(systemName: "arrow.up.right.square") + .font(.caption2) + .foregroundColor(.secondary) + } + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + .foregroundColor(.accentColor) + } else { + HStack { + Text(contributor.name) + .font(.caption) + .foregroundColor(.primary) + Spacer() + } + } + } + + // MARK: - Helper + private func openTornProfile(_ tornID: Int) { + let urlString = "https://www.torn.com/profiles.php?XID=\(tornID)" + if let url = URL(string: urlString) { + NSWorkspace.shared.open(url) + } + } +} + +// MARK: - Contributor Model +struct TornContributor: Identifiable { + let id = UUID() + let name: String + let tornID: Int? + + init(name: String, tornID: Int?) { + self.name = name + self.tornID = tornID + } +} + +#Preview { + CreditsView(showCredits: .constant(true)) +} diff --git a/MacTorn/MacTorn/Views/SettingsView.swift b/MacTorn/MacTorn/Views/SettingsView.swift index 935c34e..b28f42d 100644 --- a/MacTorn/MacTorn/Views/SettingsView.swift +++ b/MacTorn/MacTorn/Views/SettingsView.swift @@ -3,11 +3,20 @@ import SwiftUI struct SettingsView: View { @EnvironmentObject var appState: AppState @State private var inputKey: String = "" - + @State private var showCredits: Bool = false + // Developer ID for tip feature (bombel) private let developerID = 2362436 - + var body: some View { + if showCredits { + CreditsView(showCredits: $showCredits) + } else { + settingsContent + } + } + + private var settingsContent: some View { VStack(spacing: 20) { // Header Image(systemName: "bolt.circle.fill") @@ -143,15 +152,31 @@ struct SettingsView: View { // GitHub & Version VStack(spacing: 4) { - HStack(spacing: 4) { - Image(systemName: "chevron.left.forwardslash.chevron.right") - .font(.caption2) - .foregroundColor(.gray) - Link("View on GitHub", - destination: URL(string: "https://github.com/pawelorzech/MacTorn")!) - .font(.caption) + HStack(spacing: 12) { + HStack(spacing: 4) { + Image(systemName: "chevron.left.forwardslash.chevron.right") + .font(.caption2) + .foregroundColor(.gray) + Link("View on GitHub", + destination: URL(string: "https://github.com/pawelorzech/MacTorn")!) + .font(.caption) + } + + Button { + showCredits = true + } label: { + HStack(spacing: 4) { + Image(systemName: "heart.fill") + .font(.caption2) + .foregroundColor(.pink) + Text("Credits") + .font(.caption) + } + } + .buttonStyle(.plain) + .foregroundColor(.accentColor) } - + if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { Text("v\(version)") .font(.caption2) From bab929df98cd9e7a8749ef11aa125d99bebc1810 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Jan 2026 19:43:35 +0000 Subject: [PATCH 2/2] feat: Populate Credits page with real data - Add bombel as developer/creator with highlighted section - Add Special Thanks: kaszmir, dylanwishop, constanziagatta - Add faction link: The Masters - Add company link: Glory Holes Productions - All entries link to respective Torn pages --- MacTorn/MacTorn/Views/CreditsView.swift | 180 +++++++++++++++++++----- 1 file changed, 141 insertions(+), 39 deletions(-) diff --git a/MacTorn/MacTorn/Views/CreditsView.swift b/MacTorn/MacTorn/Views/CreditsView.swift index 976d85d..0614c3c 100644 --- a/MacTorn/MacTorn/Views/CreditsView.swift +++ b/MacTorn/MacTorn/Views/CreditsView.swift @@ -3,23 +3,23 @@ import SwiftUI struct CreditsView: View { @Binding var showCredits: Bool - // MARK: - Contributors Data - // Format: (name: "Username", tornID: 123456) - // The tornID will automatically link to the Torn profile + // MARK: - Developer + private let developer = TornContributor(name: "bombel", tornID: 2362436) + // MARK: - Special Thanks private let specialThanks: [TornContributor] = [ - // TODO: Add contributors here - // Example: TornContributor(name: "bombel", tornID: 2362436), - TornContributor(name: "Placeholder1", tornID: nil), - TornContributor(name: "Placeholder2", tornID: nil), - TornContributor(name: "Placeholder3", tornID: nil), + TornContributor(name: "kaszmir", tornID: 3913934), + TornContributor(name: "dylanwishop", tornID: 3918903), + TornContributor(name: "constanziagatta", tornID: 3961012), ] - private let testers: [TornContributor] = [ - // TODO: Add testers here - TornContributor(name: "TesterPlaceholder1", tornID: nil), - TornContributor(name: "TesterPlaceholder2", tornID: nil), - ] + // MARK: - Faction + private let factionName = "The Masters" + private let factionID = 11559 + + // MARK: - Company + private let companyName = "Glory Holes Productions" + private let companyOwnerID = 2362436 var body: some View { VStack(spacing: 16) { @@ -37,39 +37,31 @@ struct CreditsView: View { Text("Credits") .font(.title2.bold()) - - Text("Thank you for your support!") - .font(.caption) - .foregroundColor(.secondary) } Divider() ScrollView { - VStack(spacing: 16) { - // Special Thanks Section - if !specialThanks.isEmpty { - contributorSection( - title: "Special Thanks", - icon: "star.fill", - iconColor: .yellow, - contributors: specialThanks - ) - } + VStack(spacing: 14) { + // Developer Section + developerSection - // Testers Section - if !testers.isEmpty { - contributorSection( - title: "Beta Testers", - icon: "checkmark.seal.fill", - iconColor: .green, - contributors: testers - ) - } + // Special Thanks Section + contributorSection( + title: "Special Thanks", + icon: "star.fill", + iconColor: .yellow, + contributors: specialThanks + ) + + // Faction Section + factionSection + + // Company Section + companySection } .padding(.horizontal) } - .frame(maxHeight: 200) Spacer() @@ -90,7 +82,103 @@ struct CreditsView: View { .frame(width: 320) } - // MARK: - Section View + // MARK: - Developer Section + private var developerSection: some View { + VStack(alignment: .leading, spacing: 8) { + HStack(spacing: 6) { + Image(systemName: "hammer.fill") + .foregroundColor(.orange) + Text("Created by") + .font(.subheadline.bold()) + } + + Button { + openTornProfile(developer.tornID!) + } label: { + HStack { + Text(developer.name) + .font(.caption.bold()) + Spacer() + Image(systemName: "arrow.up.right.square") + .font(.caption2) + .foregroundColor(.secondary) + } + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + .foregroundColor(.accentColor) + .padding(10) + .frame(maxWidth: .infinity) + .background(Color.orange.opacity(0.1)) + .cornerRadius(8) + } + } + + // MARK: - Faction Section + private var factionSection: some View { + VStack(alignment: .leading, spacing: 8) { + HStack(spacing: 6) { + Image(systemName: "shield.fill") + .foregroundColor(.blue) + Text("Faction") + .font(.subheadline.bold()) + } + + Button { + openFaction(factionID) + } label: { + HStack { + Text(factionName) + .font(.caption) + Spacer() + Image(systemName: "arrow.up.right.square") + .font(.caption2) + .foregroundColor(.secondary) + } + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + .foregroundColor(.accentColor) + .padding(10) + .frame(maxWidth: .infinity) + .background(Color.secondary.opacity(0.1)) + .cornerRadius(8) + } + } + + // MARK: - Company Section + private var companySection: some View { + VStack(alignment: .leading, spacing: 8) { + HStack(spacing: 6) { + Image(systemName: "building.2.fill") + .foregroundColor(.purple) + Text("Company") + .font(.subheadline.bold()) + } + + Button { + openCompany(companyOwnerID) + } label: { + HStack { + Text(companyName) + .font(.caption) + Spacer() + Image(systemName: "arrow.up.right.square") + .font(.caption2) + .foregroundColor(.secondary) + } + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + .foregroundColor(.accentColor) + .padding(10) + .frame(maxWidth: .infinity) + .background(Color.secondary.opacity(0.1)) + .cornerRadius(8) + } + } + + // MARK: - Contributors Section @ViewBuilder private func contributorSection( title: String, @@ -147,13 +235,27 @@ struct CreditsView: View { } } - // MARK: - Helper + // MARK: - URL Helpers private func openTornProfile(_ tornID: Int) { let urlString = "https://www.torn.com/profiles.php?XID=\(tornID)" if let url = URL(string: urlString) { NSWorkspace.shared.open(url) } } + + private func openFaction(_ factionID: Int) { + let urlString = "https://www.torn.com/factions.php?step=profile&ID=\(factionID)" + if let url = URL(string: urlString) { + NSWorkspace.shared.open(url) + } + } + + private func openCompany(_ ownerID: Int) { + let urlString = "https://www.torn.com/joblist.php#/p=corpinfo&userID=\(ownerID)" + if let url = URL(string: urlString) { + NSWorkspace.shared.open(url) + } + } } // MARK: - Contributor Model