Improved Onboarding Window+ License/buy buttons

This commit is contained in:
Beingpax 2025-06-05 14:51:41 +05:45
parent 73ac365ed4
commit b09443bc09
7 changed files with 62 additions and 26 deletions

View File

@ -3,6 +3,7 @@ import SwiftUI
struct TrialMessageView: View {
let message: String
let type: MessageType
var onAddLicenseKey: (() -> Void)? = nil
enum MessageType {
case warning
@ -26,14 +27,22 @@ struct TrialMessageView: View {
Spacer()
if type == .expired || type == .warning {
HStack(spacing: 12) {
Button(action: {
onAddLicenseKey?()
}) {
Text("Enter License")
.font(.system(size: 13, weight: .medium))
}
.buttonStyle(.bordered)
Button(action: {
if let url = URL(string: "https://tryvoiceink.com/buy") {
NSWorkspace.shared.open(url)
}
}) {
Text(type == .expired ? "Upgrade Now" : "Upgrade")
.font(.headline)
Text("Buy License")
.font(.system(size: 13, weight: .medium))
}
.buttonStyle(.borderedProminent)
}

View File

@ -190,8 +190,7 @@ struct ContentView: View {
.navigationTitle("")
}
.navigationSplitViewStyle(.balanced)
.frame(minWidth: 1100, minHeight: 750)
.background(Color(.controlBackgroundColor))
.frame(minWidth: 940, minHeight: 730)
.onAppear {
hasLoadedData = true
}

View File

@ -22,13 +22,29 @@ struct MetricsView: View {
if case .trial(let daysRemaining) = licenseViewModel.licenseState {
TrialMessageView(
message: "You have \(daysRemaining) days left in your trial",
type: daysRemaining <= 2 ? .warning : .info
type: daysRemaining <= 2 ? .warning : .info,
onAddLicenseKey: {
// Post notification to navigate to VoiceInk Pro tab
NotificationCenter.default.post(
name: .navigateToDestination,
object: nil,
userInfo: ["destination": "VoiceInk Pro"]
)
}
)
.padding()
} else if case .trialExpired = licenseViewModel.licenseState {
TrialMessageView(
message: "Your trial has expired. Upgrade to continue using VoiceInk",
type: .expired
type: .expired,
onAddLicenseKey: {
// Also allow navigation from expired state
NotificationCenter.default.post(
name: .navigateToDestination,
object: nil,
userInfo: ["destination": "VoiceInk Pro"]
)
}
)
.padding()
}

View File

@ -80,4 +80,4 @@ class MiniWindowManager: ObservableObject {
show()
}
}
}
}

View File

@ -4,7 +4,7 @@ import AppKit
class NotchWindowManager: ObservableObject {
@Published var isVisible = false
private var windowController: NSWindowController?
private var notchPanel: NotchRecorderPanel?
var notchPanel: NotchRecorderPanel?
private let whisperState: WhisperState
private let recorder: Recorder

View File

@ -114,8 +114,15 @@ struct VoiceInkApp: App {
.environmentObject(whisperState)
.environmentObject(aiService)
.environmentObject(enhancementService)
.frame(minWidth: 1200, minHeight: 800)
.frame(minWidth: 880, minHeight: 780)
.cornerRadius(16)
.clipped()
.background(WindowAccessor { window in
// Ensure this is called only once or is idempotent
if window.title != "VoiceInk Onboarding" { // Prevent re-configuration
WindowManager.shared.configureOnboardingPanel(window)
}
})
}
}
.commands {

View File

@ -7,29 +7,38 @@ class WindowManager {
private init() {}
func configureWindow(_ window: NSWindow) {
window.styleMask = [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView]
window.titlebarAppearsTransparent = true
window.titleVisibility = .hidden
window.styleMask.insert(.fullSizeContentView)
window.backgroundColor = .windowBackgroundColor
window.isReleasedWhenClosed = false
window.title = "VoiceInk"
// Add additional window configuration for better state management
window.collectionBehavior = [.fullScreenPrimary]
// Ensure proper window level and ordering
window.level = .normal
window.isOpaque = true
window.isMovableByWindowBackground = false
window.minSize = NSSize(width: 0, height: 0)
window.orderFrontRegardless()
}
func configureOnboardingPanel(_ window: NSWindow) {
window.styleMask = [.borderless, .fullSizeContentView, .resizable]
window.isMovableByWindowBackground = true
window.level = .floating
window.titlebarAppearsTransparent = true
window.titleVisibility = .hidden
window.backgroundColor = .clear
window.isReleasedWhenClosed = false
window.collectionBehavior = [.canJoinAllSpaces, .stationary, .ignoresCycle]
window.title = "VoiceInk Onboarding"
window.isOpaque = false
window.minSize = NSSize(width: 900, height: 780)
window.orderFrontRegardless()
}
func createMainWindow(contentView: NSView) -> NSWindow {
// Use a standard size that fits well on most displays
let defaultSize = NSSize(width: 1200, height: 800)
// Get the main screen frame to help with centering
let defaultSize = NSSize(width: 940, height: 780)
let screenFrame = NSScreen.main?.visibleFrame ?? NSRect(x: 0, y: 0, width: 1200, height: 800)
// Create window with centered position
let xPosition = (screenFrame.width - defaultSize.width) / 2 + screenFrame.minX
let yPosition = (screenFrame.height - defaultSize.height) / 2 + screenFrame.minY
@ -43,7 +52,6 @@ class WindowManager {
configureWindow(window)
window.contentView = contentView
// Set up window delegate to handle window state changes
let delegate = WindowStateDelegate()
window.delegate = delegate
@ -51,16 +59,13 @@ class WindowManager {
}
}
// Add window delegate to handle window state changes
class WindowStateDelegate: NSObject, NSWindowDelegate {
func windowWillClose(_ notification: Notification) {
guard let window = notification.object as? NSWindow else { return }
// Ensure window is properly hidden when closed
window.orderOut(nil)
}
func windowDidBecomeKey(_ notification: Notification) {
// Ensure window is properly activated
guard let _ = notification.object as? NSWindow else { return }
NSApp.activate(ignoringOtherApps: true)
}