modernize mac code

This commit is contained in:
Peter Steinberger 2025-06-20 12:40:29 +02:00
parent 26413645b3
commit a314fe8bf0
9 changed files with 86 additions and 19 deletions

View file

@ -0,0 +1,61 @@
import SwiftUI
// MARK: - Environment Keys
private struct ServerManagerKey: EnvironmentKey {
static let defaultValue: ServerManager? = nil
}
private struct NgrokServiceKey: EnvironmentKey {
static let defaultValue: NgrokService? = nil
}
private struct AppleScriptPermissionManagerKey: EnvironmentKey {
static let defaultValue: AppleScriptPermissionManager? = nil
}
private struct TerminalLauncherKey: EnvironmentKey {
static let defaultValue: TerminalLauncher? = nil
}
// MARK: - Environment Values Extensions
extension EnvironmentValues {
var serverManager: ServerManager {
get { self[ServerManagerKey.self] }
set { self[ServerManagerKey.self] = newValue }
}
var ngrokService: NgrokService {
get { self[NgrokServiceKey.self] }
set { self[NgrokServiceKey.self] = newValue }
}
var appleScriptPermissionManager: AppleScriptPermissionManager {
get { self[AppleScriptPermissionManagerKey.self] }
set { self[AppleScriptPermissionManagerKey.self] = newValue }
}
var terminalLauncher: TerminalLauncher {
get { self[TerminalLauncherKey.self] }
set { self[TerminalLauncherKey.self] = newValue }
}
}
// MARK: - View Extensions
extension View {
/// Injects all VibeTunnel services into the environment
func withVibeTunnelServices(
serverManager: ServerManager = .shared,
ngrokService: NgrokService = .shared,
appleScriptPermissionManager: AppleScriptPermissionManager = .shared,
terminalLauncher: TerminalLauncher = .shared
) -> some View {
self
.environment(\.serverManager, serverManager)
.environment(\.ngrokService, ngrokService)
.environment(\.appleScriptPermissionManager, appleScriptPermissionManager)
.environment(\.terminalLauncher, terminalLauncher)
}
}

View file

@ -1,6 +1,7 @@
import AppKit
import Foundation
import OSLog
import Observation
/// Manages AppleScript automation permissions for VibeTunnel.
///
@ -8,11 +9,12 @@ import OSLog
/// terminal applications via AppleScript. It provides continuous monitoring
/// and user-friendly permission request flows.
@MainActor
final class AppleScriptPermissionManager: ObservableObject {
@Observable
final class AppleScriptPermissionManager {
static let shared = AppleScriptPermissionManager()
@Published private(set) var hasPermission = false
@Published private(set) var isChecking = false
private(set) var hasPermission = false
private(set) var isChecking = false
private let logger = Logger(
subsystem: Bundle.main.bundleIdentifier ?? "VibeTunnel",
@ -30,7 +32,7 @@ final class AppleScriptPermissionManager: ObservableObject {
}
deinit {
monitoringTask?.cancel()
// Task will be cancelled automatically when the object is deallocated
}
/// Checks if we have AppleScript automation permissions.

View file

@ -104,8 +104,8 @@ final class NgrokService: NgrokTunnelProtocol {
/// The ngrok process if using CLI mode
private var ngrokProcess: Process?
/// Timer for periodic status updates
private var statusTimer: Timer?
/// Task for periodic status updates
private var statusTask: Task<Void, Never>?
private let logger = Logger(subsystem: "sh.vibetunnel.vibetunnel", category: "NgrokService")
@ -136,8 +136,8 @@ final class NgrokService: NgrokTunnelProtocol {
ngrokProcess = nil
}
statusTimer?.invalidate()
statusTimer = nil
statusTask?.cancel()
statusTask = nil
isActive = false
publicUrl = nil
@ -257,11 +257,12 @@ final class NgrokService: NgrokTunnelProtocol {
/// Monitors tunnel status periodically
private func startStatusMonitoring() {
statusTimer?.invalidate()
statusTask?.cancel()
statusTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { _ in
Task { @MainActor in
statusTask = Task { @MainActor in
while !Task.isCancelled {
await self.updateTunnelStatus()
try? await Task.sleep(nanoseconds: 5_000_000_000) // 5 seconds
}
}
}

View file

@ -1,4 +1,3 @@
import Combine
import Foundation
import Logging

View file

@ -21,7 +21,7 @@ struct DashboardSettingsView: View {
@State private var passwordError: String?
@State private var passwordSaved = false
@StateObject private var permissionManager = AppleScriptPermissionManager.shared
@State private var permissionManager = AppleScriptPermissionManager.shared
@State private var ngrokAuthToken = ""
@State private var ngrokStatus: NgrokTunnelStatus?

View file

@ -1,4 +1,3 @@
import Combine
import SwiftUI
/// General settings tab for basic app preferences
@ -128,7 +127,7 @@ struct GeneralSettingsView: View {
// MARK: - Permissions Section
private struct PermissionsSection: View {
@StateObject private var appleScriptManager = AppleScriptPermissionManager.shared
@State private var appleScriptManager = AppleScriptPermissionManager.shared
@State private var accessibilityUpdateTrigger = 0
private var hasAccessibilityPermission: Bool {

View file

@ -20,7 +20,7 @@ import SwiftUI
/// - ``AccessibilityPermissionManager`` for accessibility permissions
/// - Terminal selection stored in UserDefaults
struct RequestPermissionsPageView: View {
@StateObject private var appleScriptManager = AppleScriptPermissionManager.shared
@State private var appleScriptManager = AppleScriptPermissionManager.shared
@State private var accessibilityUpdateTrigger = 0
private var hasAccessibilityPermission: Bool {

View file

@ -24,7 +24,7 @@ struct WelcomeView: View {
@AppStorage(AppConstants.UserDefaultsKeys.welcomeVersion)
private var welcomeVersion = 0
@State private var cliInstaller = CLIInstaller()
@StateObject private var permissionManager = AppleScriptPermissionManager.shared
@State private var permissionManager = AppleScriptPermissionManager.shared
var body: some View {
VStack(spacing: 0) {

View file

@ -9,6 +9,10 @@ struct VibeTunnelApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self)
var appDelegate
@State private var sessionMonitor = SessionMonitor.shared
@State private var serverManager = ServerManager.shared
@State private var ngrokService = NgrokService.shared
@State private var appleScriptPermissionManager = AppleScriptPermissionManager.shared
@State private var terminalLauncher = TerminalLauncher.shared
init() {
// No special initialization needed
@ -28,6 +32,7 @@ struct VibeTunnelApp: App {
// Welcome Window
WindowGroup("Welcome", id: "welcome") {
WelcomeView()
.withVibeTunnelServices()
}
.windowResizability(.contentSize)
.defaultSize(width: 580, height: 480)
@ -35,6 +40,7 @@ struct VibeTunnelApp: App {
Settings {
SettingsView()
.withVibeTunnelServices()
}
.commands {
CommandGroup(after: .appInfo) {
@ -55,7 +61,7 @@ struct VibeTunnelApp: App {
MenuBarExtra {
MenuBarView()
.environment(sessionMonitor)
.environment(serverMonitor)
.withVibeTunnelServices()
} label: {
Image("menubar")
.renderingMode(.template)
@ -159,7 +165,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate, @preconcurrency UNUser
// Check if server actually started
if serverManager.isRunning {
logger.info("HTTP server started successfully on port \(self.serverManager.port)")
logger.info("Server mode: \(self.serverManager.serverMode.displayName)")
// Start monitoring sessions after server starts
sessionMonitor.startMonitoring()