Add player info and support links to UI

Extended TornResponse to include player name and ID, and updated API selections to fetch basic info. StatusView now displays the player's name and ID if available. SettingsView adds a 'Tip Me' section for developer support and a GitHub source link.
This commit is contained in:
Paweł Orzech 2026-01-17 19:29:13 +00:00
parent 802fdfa1a3
commit 974556b24c
No known key found for this signature in database
3 changed files with 104 additions and 17 deletions

View file

@ -2,6 +2,8 @@ import Foundation
// MARK: - Root Response // MARK: - Root Response
struct TornResponse: Codable { struct TornResponse: Codable {
let name: String?
let playerId: Int?
let energy: Bar? let energy: Bar?
let nerve: Bar? let nerve: Bar?
let life: Bar? let life: Bar?
@ -10,6 +12,13 @@ struct TornResponse: Codable {
let travel: Travel? let travel: Travel?
let error: TornError? let error: TornError?
enum CodingKeys: String, CodingKey {
case name
case playerId = "player_id"
case energy, nerve, life, happy
case cooldowns, travel, error
}
// Convenience computed property // Convenience computed property
var bars: Bars? { var bars: Bars? {
guard let energy = energy, guard let energy = energy,
@ -90,7 +99,7 @@ struct TornError: Codable {
// MARK: - API Configuration // MARK: - API Configuration
enum TornAPI { enum TornAPI {
static let baseURL = "https://api.torn.com/user/" static let baseURL = "https://api.torn.com/user/"
static let selections = "bars,cooldowns,travel" static let selections = "basic,bars,cooldowns,travel"
static func url(for apiKey: String) -> URL? { static func url(for apiKey: String) -> URL? {
URL(string: "\(baseURL)?selections=\(selections)&key=\(apiKey)") URL(string: "\(baseURL)?selections=\(selections)&key=\(apiKey)")

View file

@ -4,6 +4,9 @@ struct SettingsView: View {
@EnvironmentObject var appState: AppState @EnvironmentObject var appState: AppState
@State private var inputKey: String = "" @State private var inputKey: String = ""
// Developer ID for tip feature (bombel)
private let developerID = 2362436
var body: some View { var body: some View {
VStack(spacing: 16) { VStack(spacing: 16) {
// Header // Header
@ -52,10 +55,73 @@ struct SettingsView: View {
} }
.toggleStyle(.switch) .toggleStyle(.switch)
.padding(.horizontal) .padding(.horizontal)
Divider()
.padding(.vertical, 4)
// Tip Me section
tipMeSection
// GitHub link
githubSection
} }
.padding() .padding()
.onAppear { .onAppear {
inputKey = appState.apiKey inputKey = appState.apiKey
} }
} }
// MARK: - Tip Me Section
private var tipMeSection: some View {
VStack(spacing: 8) {
HStack {
Image(systemName: "gift.fill")
.foregroundColor(.purple)
Text("Support the Developer")
.font(.caption.bold())
}
Text("Send me some Xanax or cash :)")
.font(.caption2)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
Button {
openTornProfile()
} label: {
HStack {
Image(systemName: "paperplane.fill")
Text("Send Xanax to bombel")
}
.font(.caption)
.padding(.vertical, 8)
.padding(.horizontal, 16)
.background(Color.purple.opacity(0.15))
.cornerRadius(8)
}
.buttonStyle(.plain)
}
.padding()
.background(Color.purple.opacity(0.05))
.cornerRadius(8)
}
// MARK: - GitHub Section
private var githubSection: some View {
HStack {
Image(systemName: "chevron.left.forwardslash.chevron.right")
.foregroundColor(.gray)
Link("View Source on GitHub",
destination: URL(string: "https://github.com/pawelorzech/MacTorn")!)
.font(.caption)
}
}
// MARK: - Helpers
private func openTornProfile() {
let url = "https://www.torn.com/profiles.php?XID=\(developerID)"
if let url = URL(string: url) {
NSWorkspace.shared.open(url)
}
}
} }

View file

@ -39,23 +39,35 @@ struct StatusView: View {
// MARK: - Header // MARK: - Header
private var headerSection: some View { private var headerSection: some View {
HStack { VStack(alignment: .leading, spacing: 4) {
Text("Torn Status") HStack {
.font(.headline) if let name = appState.data?.name, let id = appState.data?.playerId {
VStack(alignment: .leading, spacing: 2) {
Spacer() Text(name)
.font(.headline)
if appState.isLoading { Text("[\(String(id))]")
ProgressView() .font(.caption2.monospacedDigit())
.scaleEffect(0.6) .foregroundColor(.secondary)
} else { }
Button { } else {
appState.refreshNow() Text("Torn Status")
} label: { .font(.headline)
Image(systemName: "arrow.clockwise") }
Spacer()
if appState.isLoading {
ProgressView()
.scaleEffect(0.6)
} else {
Button {
appState.refreshNow()
} label: {
Image(systemName: "arrow.clockwise")
}
.buttonStyle(.plain)
.foregroundColor(.secondary)
} }
.buttonStyle(.plain)
.foregroundColor(.secondary)
} }
} }
} }