Improved Onboarding Window+ License/buy buttons
This commit is contained in:
parent
73ac365ed4
commit
b09443bc09
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -80,4 +80,4 @@ class MiniWindowManager: ObservableObject {
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user