warning fixes

This commit is contained in:
Peter Steinberger 2025-07-31 02:21:18 +02:00
parent fe2f30ed73
commit e9a1ce0555
11 changed files with 92 additions and 81 deletions

View file

@ -13,9 +13,9 @@ extension Notification.Name {
// MARK: - Welcome // MARK: - Welcome
static let showWelcomeScreen = Notification.Name("showWelcomeScreen") static let showWelcomeScreen = Notification.Name("showWelcomeScreen")
// MARK: - Services // MARK: - Services
static let notificationServiceConnectionChanged = Notification.Name("notificationServiceConnectionChanged") static let notificationServiceConnectionChanged = Notification.Name("notificationServiceConnectionChanged")
} }

View file

@ -60,9 +60,9 @@ final class EventSource: NSObject {
// MARK: - Connection Management // MARK: - Connection Management
func connect() { func connect() {
guard !isConnected else { guard !isConnected else {
logger.warning("Already connected, ignoring connect request") logger.warning("Already connected, ignoring connect request")
return return
} }
var request = URLRequest(url: url) var request = URLRequest(url: url)
@ -84,7 +84,7 @@ final class EventSource: NSObject {
dataTask = urlSession?.dataTask(with: request) dataTask = urlSession?.dataTask(with: request)
dataTask?.resume() dataTask?.resume()
logger.info("📡 EventSource dataTask started") logger.info("📡 EventSource dataTask started")
} }
@ -136,7 +136,8 @@ final class EventSource: NSObject {
} }
// Dispatch event // Dispatch event
logger.debug("🎯 Dispatching event - type: \(event.event ?? "default"), data: \(event.data ?? "none")") logger
.debug("🎯 Dispatching event - type: \(event.event ?? "default"), data: \(event.data ?? "none")")
DispatchQueue.main.async { DispatchQueue.main.async {
self.onMessage?(event) self.onMessage?(event)
} }
@ -197,7 +198,7 @@ extension EventSource: URLSessionDataDelegate {
completionHandler: @escaping (URLSession.ResponseDisposition) -> Void completionHandler: @escaping (URLSession.ResponseDisposition) -> Void
) { ) {
logger.info("📥 URLSession didReceive response") logger.info("📥 URLSession didReceive response")
guard let httpResponse = response as? HTTPURLResponse else { guard let httpResponse = response as? HTTPURLResponse else {
logger.error("Response is not HTTPURLResponse") logger.error("Response is not HTTPURLResponse")
completionHandler(.cancel) completionHandler(.cancel)
@ -224,19 +225,19 @@ extension EventSource: URLSessionDataDelegate {
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
logger.debug("📨 EventSource received \(data.count) bytes of data") logger.debug("📨 EventSource received \(data.count) bytes of data")
// Check if data might be compressed // Check if data might be compressed
if data.count > 2 { if data.count > 2 {
let header = [UInt8](data.prefix(2)) let header = [UInt8](data.prefix(2))
if header[0] == 0x1f && header[1] == 0x8b { if header[0] == 0x1F && header[1] == 0x8B {
logger.error("❌ Received gzip compressed data! SSE should not be compressed.") logger.error("❌ Received gzip compressed data! SSE should not be compressed.")
return return
} }
} }
guard let text = String(data: data, encoding: .utf8) else { guard let text = String(data: data, encoding: .utf8) else {
logger.error("Failed to decode data as UTF-8. First 20 bytes: \(data.prefix(20).hexString)") logger.error("Failed to decode data as UTF-8. First 20 bytes: \(data.prefix(20).hexString)")
return return
} }
logger.debug("📨 EventSource received text: \(text)") logger.debug("📨 EventSource received text: \(text)")

View file

@ -21,7 +21,7 @@ final class NotificationService: NSObject {
private var isConnected = false private var isConnected = false
private var recentlyNotifiedSessions = Set<String>() private var recentlyNotifiedSessions = Set<String>()
private var notificationCleanupTimer: Timer? private var notificationCleanupTimer: Timer?
/// Public property to check SSE connection status /// Public property to check SSE connection status
var isSSEConnected: Bool { isConnected } var isSSEConnected: Bool { isConnected }
@ -67,13 +67,13 @@ final class NotificationService: NSObject {
/// Start monitoring server events /// Start monitoring server events
func start() async { func start() async {
logger.info("🚀 NotificationService.start() called") logger.info("🚀 NotificationService.start() called")
// Check if notifications are enabled in config // Check if notifications are enabled in config
guard configManager.notificationsEnabled else { guard configManager.notificationsEnabled else {
logger.info("📴 Notifications are disabled in config, skipping SSE connection") logger.info("📴 Notifications are disabled in config, skipping SSE connection")
return return
} }
guard serverManager.isRunning else { guard serverManager.isRunning else {
logger.warning("🔴 Server not running, cannot start notification service") logger.warning("🔴 Server not running, cannot start notification service")
return return
@ -87,18 +87,18 @@ final class NotificationService: NSObject {
waitForUnixSocketAndConnect() waitForUnixSocketAndConnect()
} }
} }
/// Wait for Unix socket ready notification then connect /// Wait for Unix socket ready notification then connect
private func waitForUnixSocketAndConnect() { private func waitForUnixSocketAndConnect() {
logger.info("⏳ Waiting for Unix socket ready notification...") logger.info("⏳ Waiting for Unix socket ready notification...")
// Check if Unix socket is already connected // Check if Unix socket is already connected
if SharedUnixSocketManager.shared.isConnected { if SharedUnixSocketManager.shared.isConnected {
logger.info("✅ Unix socket already connected, connecting to SSE immediately") logger.info("✅ Unix socket already connected, connecting to SSE immediately")
connect() connect()
return return
} }
// Listen for Unix socket ready notification // Listen for Unix socket ready notification
NotificationCenter.default.addObserver( NotificationCenter.default.addObserver(
forName: SharedUnixSocketManager.unixSocketReadyNotification, forName: SharedUnixSocketManager.unixSocketReadyNotification,
@ -108,7 +108,7 @@ final class NotificationService: NSObject {
Task { @MainActor [weak self] in Task { @MainActor [weak self] in
self?.logger.info("✅ Unix socket ready notification received, connecting to SSE") self?.logger.info("✅ Unix socket ready notification received, connecting to SSE")
self?.connect() self?.connect()
// Remove observer after first notification to prevent duplicate connections // Remove observer after first notification to prevent duplicate connections
NotificationCenter.default.removeObserver( NotificationCenter.default.removeObserver(
self as Any, self as Any,
@ -423,7 +423,6 @@ final class NotificationService: NSObject {
// This prevents dual-path connection attempts // This prevents dual-path connection attempts
} }
private func connect() { private func connect() {
logger.info("🔌 NotificationService.connect() called - isConnected: \(self.isConnected)") logger.info("🔌 NotificationService.connect() called - isConnected: \(self.isConnected)")
guard !isConnected else { guard !isConnected else {
@ -434,13 +433,14 @@ final class NotificationService: NSObject {
// When auth mode is "none", we can connect without a token. // When auth mode is "none", we can connect without a token.
// In any other auth mode, a token is required for the local Mac app to connect. // In any other auth mode, a token is required for the local Mac app to connect.
if serverManager.authMode != "none", serverManager.localAuthToken == nil { if serverManager.authMode != "none", serverManager.localAuthToken == nil {
logger.error("No auth token available for notification service in auth mode '\(self.serverManager.authMode)'") logger
.error("No auth token available for notification service in auth mode '\(self.serverManager.authMode)'")
return return
} }
let eventsURL = "http://localhost:\(self.serverManager.port)/api/events" let eventsURL = "http://localhost:\(self.serverManager.port)/api/events"
logger.info("📡 Attempting to connect to SSE endpoint: \(eventsURL)") logger.info("📡 Attempting to connect to SSE endpoint: \(eventsURL)")
guard let url = URL(string: eventsURL) else { guard let url = URL(string: eventsURL) else {
logger.error("Invalid events URL: \(eventsURL)") logger.error("Invalid events URL: \(eventsURL)")
return return
@ -489,7 +489,10 @@ final class NotificationService: NSObject {
eventSource?.onMessage = { [weak self] event in eventSource?.onMessage = { [weak self] event in
Task { @MainActor in Task { @MainActor in
self?.logger.info("🎯 EventSource onMessage fired! Event type: \(event.event ?? "default"), Has data: \(event.data != nil)") self?.logger
.info(
"🎯 EventSource onMessage fired! Event type: \(event.event ?? "default"), Has data: \(event.data != nil)"
)
self?.handleEvent(event) self?.handleEvent(event)
} }
} }
@ -507,9 +510,9 @@ final class NotificationService: NSObject {
} }
private func handleEvent(_ event: Event) { private func handleEvent(_ event: Event) {
guard let data = event.data else { guard let data = event.data else {
logger.warning("Received event with no data") logger.warning("Received event with no data")
return return
} }
// Log event details for debugging // Log event details for debugging
@ -725,25 +728,25 @@ final class NotificationService: NSObject {
private func handleTestNotification(_ json: [String: Any]) { private func handleTestNotification(_ json: [String: Any]) {
logger.info("🧪 Handling test notification from server") logger.info("🧪 Handling test notification from server")
let title = json["title"] as? String ?? "VibeTunnel Test" let title = json["title"] as? String ?? "VibeTunnel Test"
let body = json["body"] as? String ?? "Server-side notifications are working correctly!" let body = json["body"] as? String ?? "Server-side notifications are working correctly!"
let message = json["message"] as? String let message = json["message"] as? String
let content = UNMutableNotificationContent() let content = UNMutableNotificationContent()
content.title = title content.title = title
content.body = body content.body = body
if let message = message { if let message {
content.subtitle = message content.subtitle = message
} }
content.sound = getNotificationSound() content.sound = getNotificationSound()
content.categoryIdentifier = "TEST" content.categoryIdentifier = "TEST"
content.userInfo = ["type": "test-notification"] content.userInfo = ["type": "test-notification"]
logger.info("📤 Delivering test notification: \(title) - \(body)") logger.info("📤 Delivering test notification: \(title) - \(body)")
deliverNotification(content, identifier: "test-\(UUID().uuidString)") deliverNotification(content, identifier: "test-\(UUID().uuidString)")
} }
private func handleClaudeTurn(_ json: [String: Any]) { private func handleClaudeTurn(_ json: [String: Any]) {
guard let sessionId = json["sessionId"] as? String else { guard let sessionId = json["sessionId"] as? String else {
logger.error("Claude turn event missing sessionId") logger.error("Claude turn event missing sessionId")
@ -803,13 +806,13 @@ final class NotificationService: NSObject {
/// Send a test notification through the server to verify the full flow /// Send a test notification through the server to verify the full flow
func sendServerTestNotification() async { func sendServerTestNotification() async {
logger.info("🧪 Sending test notification through server...") logger.info("🧪 Sending test notification through server...")
// Check if server is running // Check if server is running
guard serverManager.isRunning else { guard serverManager.isRunning else {
logger.error("❌ Cannot send test notification - server is not running") logger.error("❌ Cannot send test notification - server is not running")
return return
} }
// If not connected to SSE, try to connect first // If not connected to SSE, try to connect first
if !isConnected { if !isConnected {
logger.warning("⚠️ Not connected to SSE endpoint, attempting to connect...") logger.warning("⚠️ Not connected to SSE endpoint, attempting to connect...")
@ -819,33 +822,36 @@ final class NotificationService: NSObject {
// Give it a moment to connect // Give it a moment to connect
try? await Task.sleep(nanoseconds: 500_000_000) // 0.5 seconds try? await Task.sleep(nanoseconds: 500_000_000) // 0.5 seconds
} }
// Log server info // Log server info
logger.info("Server info - Port: \(self.serverManager.port), Running: \(self.serverManager.isRunning), SSE Connected: \(self.isConnected)") logger
.info(
"Server info - Port: \(self.serverManager.port), Running: \(self.serverManager.isRunning), SSE Connected: \(self.isConnected)"
)
guard let url = serverManager.buildURL(endpoint: "/api/test-notification") else { guard let url = serverManager.buildURL(endpoint: "/api/test-notification") else {
logger.error("❌ Failed to build test notification URL") logger.error("❌ Failed to build test notification URL")
return return
} }
logger.info("📤 Sending POST request to: \(url)") logger.info("📤 Sending POST request to: \(url)")
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// Add auth token if available // Add auth token if available
if let authToken = serverManager.localAuthToken { if let authToken = serverManager.localAuthToken {
request.setValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization") request.setValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization")
logger.debug("Added auth token to request") logger.debug("Added auth token to request")
} }
do { do {
let (data, response) = try await URLSession.shared.data(for: request) let (data, response) = try await URLSession.shared.data(for: request)
if let httpResponse = response as? HTTPURLResponse { if let httpResponse = response as? HTTPURLResponse {
logger.info("📥 Received response - Status: \(httpResponse.statusCode)") logger.info("📥 Received response - Status: \(httpResponse.statusCode)")
if httpResponse.statusCode == 200 { if httpResponse.statusCode == 200 {
logger.info("✅ Server test notification sent successfully") logger.info("✅ Server test notification sent successfully")
if let responseData = String(data: data, encoding: .utf8) { if let responseData = String(data: data, encoding: .utf8) {
@ -870,4 +876,3 @@ final class NotificationService: NSObject {
// NotificationCenter observers are automatically removed on deinit in modern Swift // NotificationCenter observers are automatically removed on deinit in modern Swift
} }
} }

View file

@ -134,7 +134,7 @@ final class SessionMonitor {
private func fetchSessions() async { private func fetchSessions() async {
do { do {
// Snapshot previous sessions for exit notifications // Snapshot previous sessions for exit notifications
let _ = sessions _ = sessions
let sessionsArray = try await serverManager.performRequest( let sessionsArray = try await serverManager.performRequest(
endpoint: APIEndpoints.sessions, endpoint: APIEndpoints.sessions,
@ -233,4 +233,4 @@ final class SessionMonitor {
"Pre-caching Git data for \(uniqueDirectoriesToCheck.count) unique directories (from \(sessions.count) sessions)" "Pre-caching Git data for \(uniqueDirectoriesToCheck.count) unique directories (from \(sessions.count) sessions)"
) )
} }
} }

View file

@ -22,9 +22,9 @@ final class SharedUnixSocketManager {
private init() { private init() {
logger.info("🚀 SharedUnixSocketManager initialized") logger.info("🚀 SharedUnixSocketManager initialized")
} }
// MARK: - Notifications // MARK: - Notifications
static let unixSocketReadyNotification = Notification.Name("unixSocketReady") static let unixSocketReadyNotification = Notification.Name("unixSocketReady")
// MARK: - Public Methods // MARK: - Public Methods
@ -45,7 +45,7 @@ final class SharedUnixSocketManager {
self?.distributeMessage(data) self?.distributeMessage(data)
} }
} }
// Set up state change handler to notify when socket is ready // Set up state change handler to notify when socket is ready
socket.onStateChange = { [weak self] state in socket.onStateChange = { [weak self] state in
Task { @MainActor [weak self] in Task { @MainActor [weak self] in
@ -56,7 +56,7 @@ final class SharedUnixSocketManager {
unixSocket = socket unixSocket = socket
return socket return socket
} }
/// Handle socket state changes and notify when ready /// Handle socket state changes and notify when ready
private func handleSocketStateChange(_ state: UnixSocketConnection.ConnectionState) { private func handleSocketStateChange(_ state: UnixSocketConnection.ConnectionState) {
switch state { switch state {

View file

@ -74,11 +74,13 @@ final class TailscaleServeStatusService {
let decoder = JSONDecoder() let decoder = JSONDecoder()
// Use custom date decoder to handle ISO8601 with fractional seconds // Use custom date decoder to handle ISO8601 with fractional seconds
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
decoder.dateDecodingStrategy = .custom { decoder in decoder.dateDecodingStrategy = .custom { decoder in
let container = try decoder.singleValueContainer() let container = try decoder.singleValueContainer()
let dateString = try container.decode(String.self) let dateString = try container.decode(String.self)
// Create formatter inside the closure to avoid Sendable warning
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
if let date = formatter.date(from: dateString) { if let date = formatter.date(from: dateString) {
return date return date
} }
@ -87,7 +89,10 @@ final class TailscaleServeStatusService {
if let date = formatter.date(from: dateString) { if let date = formatter.date(from: dateString) {
return date return date
} }
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Cannot decode date string \(dateString)") throw DecodingError.dataCorruptedError(
in: container,
debugDescription: "Cannot decode date string \(dateString)"
)
} }
let status = try decoder.decode(TailscaleServeStatus.self, from: data) let status = try decoder.decode(TailscaleServeStatus.self, from: data)
@ -98,7 +103,6 @@ final class TailscaleServeStatusService {
startTime = status.startTime startTime = status.startTime
logger.debug("Tailscale Serve status - Running: \(status.isRunning), Error: \(status.lastError ?? "none")") logger.debug("Tailscale Serve status - Running: \(status.isRunning), Error: \(status.lastError ?? "none")")
} catch { } catch {
logger.error("Failed to fetch Tailscale Serve status: \(error.localizedDescription)") logger.error("Failed to fetch Tailscale Serve status: \(error.localizedDescription)")
// On error, assume not running // On error, assume not running

View file

@ -1,6 +1,6 @@
import SwiftUI
import AppKit import AppKit
import os.log import os.log
import SwiftUI
/// Authentication configuration section for remote access settings /// Authentication configuration section for remote access settings
struct AuthenticationSection: View { struct AuthenticationSection: View {
@ -8,7 +8,7 @@ struct AuthenticationSection: View {
@Binding var enableSSHKeys: Bool @Binding var enableSSHKeys: Bool
let logger: Logger let logger: Logger
let serverManager: ServerManager let serverManager: ServerManager
var body: some View { var body: some View {
Section { Section {
VStack(alignment: .leading, spacing: 16) { VStack(alignment: .leading, spacing: 16) {
@ -45,7 +45,7 @@ struct AuthenticationSection: View {
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
} }
// Additional info based on selected mode // Additional info based on selected mode
if authMode == .osAuth || authMode == .both { if authMode == .osAuth || authMode == .both {
HStack(alignment: .center, spacing: 6) { HStack(alignment: .center, spacing: 6) {
@ -59,7 +59,7 @@ struct AuthenticationSection: View {
Spacer() Spacer()
} }
} }
if authMode == .sshKeys || authMode == .both { if authMode == .sshKeys || authMode == .both {
HStack(alignment: .center, spacing: 6) { HStack(alignment: .center, spacing: 6) {
Image(systemName: "key.fill") Image(systemName: "key.fill")
@ -105,7 +105,7 @@ struct AuthenticationSection: View {
struct PreviewWrapper: View { struct PreviewWrapper: View {
@State var authMode = AuthenticationMode.osAuth @State var authMode = AuthenticationMode.osAuth
@State var enableSSHKeys = false @State var enableSSHKeys = false
var body: some View { var body: some View {
AuthenticationSection( AuthenticationSection(
authMode: $authMode, authMode: $authMode,
@ -117,6 +117,6 @@ struct AuthenticationSection: View {
.padding() .padding()
} }
} }
return PreviewWrapper() return PreviewWrapper()
} }

View file

@ -27,7 +27,7 @@ struct NotificationSettingsView: View {
var body: some View { var body: some View {
NavigationStack { NavigationStack {
@Bindable var bindableConfig = configManager @Bindable var bindableConfig = configManager
Form { Form {
// Master toggle section // Master toggle section
Section { Section {
@ -37,7 +37,7 @@ struct NotificationSettingsView: View {
.onChange(of: showNotifications) { _, newValue in .onChange(of: showNotifications) { _, newValue in
// Update ConfigManager's notificationsEnabled to match // Update ConfigManager's notificationsEnabled to match
configManager.notificationsEnabled = newValue configManager.notificationsEnabled = newValue
// Ensure NotificationService starts/stops based on the toggle // Ensure NotificationService starts/stops based on the toggle
if newValue { if newValue {
Task { Task {
@ -63,7 +63,7 @@ struct NotificationSettingsView: View {
Text("Display native macOS notifications for session and command events") Text("Display native macOS notifications for session and command events")
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
// SSE Connection Status Row // SSE Connection Status Row
HStack(spacing: 6) { HStack(spacing: 6) {
Circle() Circle()
@ -78,10 +78,11 @@ struct NotificationSettingsView: View {
.fontWeight(.medium) .fontWeight(.medium)
Spacer() Spacer()
} }
.help(sseConnectionStatus .help(sseConnectionStatus
? "Real-time notification stream is connected" ? "Real-time notification stream is connected"
: "Real-time notification stream is disconnected. Check if the server is running.") : "Real-time notification stream is disconnected. Check if the server is running."
)
// Show warning when disconnected // Show warning when disconnected
if showNotifications && !sseConnectionStatus { if showNotifications && !sseConnectionStatus {
HStack(spacing: 6) { HStack(spacing: 6) {
@ -198,7 +199,7 @@ struct NotificationSettingsView: View {
.scaleEffect(0.7) .scaleEffect(0.7)
.frame(width: 16, height: 16) .frame(width: 16, height: 16)
} }
Spacer() Spacer()
} }
@ -207,7 +208,7 @@ struct NotificationSettingsView: View {
notificationService.openNotificationSettings() notificationService.openNotificationSettings()
} }
.buttonStyle(.link) .buttonStyle(.link)
Spacer() Spacer()
} }
} }
@ -223,7 +224,7 @@ struct NotificationSettingsView: View {
.onAppear { .onAppear {
// Sync the AppStorage value with ConfigManager on first load // Sync the AppStorage value with ConfigManager on first load
showNotifications = configManager.notificationsEnabled showNotifications = configManager.notificationsEnabled
// Update initial connection status // Update initial connection status
sseConnectionStatus = notificationService.isSSEConnected sseConnectionStatus = notificationService.isSSEConnected
} }

View file

@ -5,7 +5,7 @@ struct PermissionsSection: View {
let hasAppleScriptPermission: Bool let hasAppleScriptPermission: Bool
let hasAccessibilityPermission: Bool let hasAccessibilityPermission: Bool
let permissionManager: SystemPermissionManager let permissionManager: SystemPermissionManager
var body: some View { var body: some View {
Section { Section {
// Automation permission // Automation permission
@ -17,9 +17,9 @@ struct PermissionsSection: View {
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} }
Spacer() Spacer()
if hasAppleScriptPermission { if hasAppleScriptPermission {
HStack { HStack {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
@ -47,7 +47,7 @@ struct PermissionsSection: View {
.controlSize(.small) .controlSize(.small)
} }
} }
// Accessibility permission // Accessibility permission
HStack { HStack {
VStack(alignment: .leading, spacing: 4) { VStack(alignment: .leading, spacing: 4) {
@ -57,9 +57,9 @@ struct PermissionsSection: View {
.font(.caption) .font(.caption)
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} }
Spacer() Spacer()
if hasAccessibilityPermission { if hasAccessibilityPermission {
HStack { HStack {
Image(systemName: "checkmark.circle.fill") Image(systemName: "checkmark.circle.fill")
@ -115,7 +115,7 @@ struct PermissionsSection: View {
struct PreviewWrapper: View { struct PreviewWrapper: View {
@State var hasAppleScript = true @State var hasAppleScript = true
@State var hasAccessibility = false @State var hasAccessibility = false
var body: some View { var body: some View {
PermissionsSection( PermissionsSection(
hasAppleScriptPermission: hasAppleScript, hasAppleScriptPermission: hasAppleScript,
@ -126,6 +126,6 @@ struct PermissionsSection: View {
.padding() .padding()
} }
} }
return PreviewWrapper() return PreviewWrapper()
} }

View file

@ -94,7 +94,8 @@ struct RemoteAccessSettingsView: View {
onAppearSetup() onAppearSetup()
updateLocalIPAddress() updateLocalIPAddress()
// Initialize authentication mode from stored value // Initialize authentication mode from stored value
let storedMode = UserDefaults.standard.string(forKey: AppConstants.UserDefaultsKeys.authenticationMode) ?? "os" let storedMode = UserDefaults.standard
.string(forKey: AppConstants.UserDefaultsKeys.authenticationMode) ?? "os"
authMode = AuthenticationMode(rawValue: storedMode) ?? .osAuth authMode = AuthenticationMode(rawValue: storedMode) ?? .osAuth
// Start monitoring Tailscale Serve status // Start monitoring Tailscale Serve status
tailscaleServeStatus.startMonitoring() tailscaleServeStatus.startMonitoring()
@ -628,7 +629,6 @@ private struct ErrorView: View {
} }
} }
// MARK: - Previews // MARK: - Previews
#Preview("Remote Access Settings") { #Preview("Remote Access Settings") {

View file

@ -299,7 +299,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, @preconcurrency UNUser
statusBarController?.updateStatusItemDisplay() statusBarController?.updateStatusItemDisplay()
// Session monitoring starts automatically // Session monitoring starts automatically
// NotificationService is started by ServerManager when the server is ready // NotificationService is started by ServerManager when the server is ready
} else { } else {
logger.error("HTTP server failed to start") logger.error("HTTP server failed to start")