// // AboutView.swift // oAI // // About modal with app icon and version info // // SPDX-License-Identifier: AGPL-3.0-or-later // Copyright (C) 2026 Rune Olsen // // This file is part of oAI. // // oAI is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // oAI is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General // Public License for more details. // // You should have received a copy of the GNU Affero General Public // License along with oAI. If not, see . import SwiftUI struct AboutView: View { @Environment(\.dismiss) var dismiss private var appVersion: String { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0" } private var buildNumber: String { Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "1" } var body: some View { VStack(spacing: 16) { Spacer().frame(height: 8) Image("AppLogo") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 128, height: 128) .clipShape(RoundedRectangle(cornerRadius: 24)) .shadow(color: .cyan.opacity(0.3), radius: 12) Text("oAI") .font(.system(size: 28, weight: .bold)) Text("Version \(appVersion) (\(buildNumber))") .font(.callout) .foregroundStyle(.secondary) Text("Multi-provider AI chat client") .font(.subheadline) .foregroundStyle(.secondary) Divider() .padding(.horizontal, 40) VStack(spacing: 4) { Text("© 2026 [Rune Olsen](https://blog.rune.pm)") .font(.caption) .foregroundStyle(.secondary) Text("[GNU Affero General Public License v3.0](https://www.gnu.org/licenses/agpl-3.0.html)") .font(.caption) .foregroundStyle(.secondary) Text("Built with SwiftUI") .font(.caption) .foregroundStyle(.tertiary) } Spacer().frame(height: 4) Button("OK") { dismiss() } .keyboardShortcut(.return, modifiers: []) .keyboardShortcut(.escape, modifiers: []) .buttonStyle(.borderedProminent) .controlSize(.regular) Spacer().frame(height: 20) } .frame(width: 320, height: 390) } } #Preview { AboutView() }