mirror of
https://github.com/pawelorzech/MacTorn.git
synced 2026-01-30 04:04:27 +00:00
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
This commit is contained in:
parent
e781a767b3
commit
14439f50ff
2 changed files with 208 additions and 10 deletions
173
MacTorn/MacTorn/Views/CreditsView.swift
Normal file
173
MacTorn/MacTorn/Views/CreditsView.swift
Normal file
|
|
@ -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))
|
||||||
|
}
|
||||||
|
|
@ -3,11 +3,20 @@ import SwiftUI
|
||||||
struct SettingsView: View {
|
struct SettingsView: View {
|
||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
@State private var inputKey: String = ""
|
@State private var inputKey: String = ""
|
||||||
|
@State private var showCredits: Bool = false
|
||||||
|
|
||||||
// Developer ID for tip feature (bombel)
|
// Developer ID for tip feature (bombel)
|
||||||
private let developerID = 2362436
|
private let developerID = 2362436
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
if showCredits {
|
||||||
|
CreditsView(showCredits: $showCredits)
|
||||||
|
} else {
|
||||||
|
settingsContent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var settingsContent: some View {
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: 20) {
|
||||||
// Header
|
// Header
|
||||||
Image(systemName: "bolt.circle.fill")
|
Image(systemName: "bolt.circle.fill")
|
||||||
|
|
@ -143,6 +152,7 @@ struct SettingsView: View {
|
||||||
|
|
||||||
// GitHub & Version
|
// GitHub & Version
|
||||||
VStack(spacing: 4) {
|
VStack(spacing: 4) {
|
||||||
|
HStack(spacing: 12) {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
Image(systemName: "chevron.left.forwardslash.chevron.right")
|
Image(systemName: "chevron.left.forwardslash.chevron.right")
|
||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
|
|
@ -152,6 +162,21 @@ struct SettingsView: View {
|
||||||
.font(.caption)
|
.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 {
|
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
|
||||||
Text("v\(version)")
|
Text("v\(version)")
|
||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue