vOOice/VoiceInk/Views/LicenseManagementView.swift
2025-02-22 11:52:41 +05:45

250 lines
9.7 KiB
Swift

import SwiftUI
struct LicenseManagementView: View {
@StateObject private var licenseViewModel = LicenseViewModel()
@Environment(\.colorScheme) private var colorScheme
var body: some View {
ScrollView {
VStack(spacing: 0) {
// Hero Section
heroSection
// Main Content
VStack(spacing: 32) {
if case .licensed = licenseViewModel.licenseState {
activatedContent
} else {
purchaseContent
}
}
.padding(32)
}
}
.background(Color(NSColor.controlBackgroundColor))
}
private var heroSection: some View {
VStack(spacing: 24) {
// App Icon
if let appIcon = NSImage(named: "AppIcon") {
Image(nsImage: appIcon)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 96, height: 96)
.cornerRadius(24)
.shadow(color: .black.opacity(0.1), radius: 20, x: 0, y: 10)
}
// Title Section
VStack(spacing: 16) {
HStack(spacing: 16) {
Image(systemName: "checkmark.seal.fill")
.font(.system(size: 32))
.foregroundStyle(.blue)
Text(licenseViewModel.licenseState == .licensed ? "VoiceInk Pro" : "Upgrade to Pro")
.font(.system(size: 32, weight: .bold))
}
Text(licenseViewModel.licenseState == .licensed ?
"Thank you for supporting VoiceInk" :
"Transform your voice into text with advanced features")
.font(.title3)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
if case .licensed = licenseViewModel.licenseState {
HStack(spacing: 40) {
Button {
if let url = URL(string: "https://voiceink.featurebase.app/changelog") {
NSWorkspace.shared.open(url)
}
} label: {
featureItem(icon: "list.bullet.clipboard.fill", title: "Changelog", color: .blue)
}
.buttonStyle(.plain)
Button {
if let url = URL(string: "https://discord.gg/xryDy57nYD") {
NSWorkspace.shared.open(url)
}
} label: {
featureItem(icon: "bubble.left.and.bubble.right.fill", title: "Discord", color: .purple)
}
.buttonStyle(.plain)
Button {
if let url = URL(string: "mailto:prakashjoshipax@gmail.com") {
NSWorkspace.shared.open(url)
}
} label: {
featureItem(icon: "envelope.fill", title: "Email Support", color: .orange)
}
.buttonStyle(.plain)
Button {
if let url = URL(string: "https://voiceink.featurebase.app") {
NSWorkspace.shared.open(url)
}
} label: {
featureItem(icon: "map.fill", title: "Roadmap", color: .green)
}
.buttonStyle(.plain)
}
.padding(.top, 8)
}
}
}
.padding(.vertical, 60)
}
private var purchaseContent: some View {
VStack(spacing: 40) {
// Purchase Card
VStack(spacing: 24) {
// Lifetime Access Badge
HStack {
Image(systemName: "infinity.circle.fill")
.font(.system(size: 20))
.foregroundStyle(.blue)
Text("Buy Once, Own Forever")
.font(.headline)
}
.padding(.vertical, 8)
.padding(.horizontal, 16)
.background(Color.blue.opacity(0.1))
.cornerRadius(12)
// Purchase Button
Button(action: {
if let url = URL(string: "https://tryvoiceink.com/buy") {
NSWorkspace.shared.open(url)
}
}) {
Text("Upgrade to VoiceInk Pro")
.font(.headline)
.frame(maxWidth: .infinity)
.padding(.vertical, 12)
}
.buttonStyle(.borderedProminent)
// Features Grid
HStack(spacing: 40) {
featureItem(icon: "bubble.left.and.bubble.right.fill", title: "Priority Support", color: .purple)
featureItem(icon: "infinity.circle.fill", title: "Lifetime Access", color: .blue)
featureItem(icon: "arrow.up.circle.fill", title: "Free Updates", color: .green)
featureItem(icon: "macbook.and.iphone", title: "All Devices", color: .orange)
}
.frame(maxWidth: .infinity, alignment: .center)
}
.padding(32)
.background(Color(.windowBackgroundColor).opacity(0.4))
.cornerRadius(16)
.shadow(color: .black.opacity(0.05), radius: 10)
// License Activation
VStack(spacing: 20) {
Text("Already have a license?")
.font(.headline)
HStack(spacing: 12) {
TextField("Enter your license key", text: $licenseViewModel.licenseKey)
.textFieldStyle(.roundedBorder)
.font(.system(.body, design: .monospaced))
.textCase(.uppercase)
Button(action: {
Task { await licenseViewModel.validateLicense() }
}) {
if licenseViewModel.isValidating {
ProgressView()
.controlSize(.small)
} else {
Text("Activate")
.frame(width: 80)
}
}
.buttonStyle(.borderedProminent)
.disabled(licenseViewModel.isValidating)
}
if let message = licenseViewModel.validationMessage {
Text(message)
.foregroundColor(.red)
.font(.callout)
}
}
.padding(32)
.background(Color(.windowBackgroundColor).opacity(0.4))
.cornerRadius(16)
.shadow(color: .black.opacity(0.05), radius: 10)
}
}
private var activatedContent: some View {
VStack(spacing: 32) {
// Status Card
VStack(spacing: 24) {
HStack {
Image(systemName: "checkmark.circle.fill")
.font(.system(size: 24))
.foregroundStyle(.green)
Text("License Active")
.font(.headline)
Spacer()
Text("Active")
.font(.caption)
.padding(.horizontal, 12)
.padding(.vertical, 4)
.background(Capsule().fill(.green))
.foregroundStyle(.white)
}
Divider()
Text("You can use VoiceInk Pro on all your personal devices")
.font(.subheadline)
.foregroundStyle(.secondary)
}
.padding(32)
.background(Color(.windowBackgroundColor).opacity(0.4))
.cornerRadius(16)
.shadow(color: .black.opacity(0.05), radius: 10)
// Deactivation Card
VStack(alignment: .leading, spacing: 16) {
Text("License Management")
.font(.headline)
Button(role: .destructive, action: {
licenseViewModel.removeLicense()
}) {
Label("Deactivate License", systemImage: "xmark.circle.fill")
.frame(maxWidth: .infinity)
.padding(.vertical, 8)
}
.buttonStyle(.bordered)
}
.padding(32)
.background(Color(.windowBackgroundColor).opacity(0.4))
.cornerRadius(16)
.shadow(color: .black.opacity(0.05), radius: 10)
}
}
private func featureItem(icon: String, title: String, color: Color) -> some View {
HStack(spacing: 8) {
Image(systemName: icon)
.font(.system(size: 16, weight: .medium))
.foregroundStyle(color)
Text(title)
.font(.system(size: 13, weight: .medium))
.foregroundStyle(.primary)
}
}
}