Files
swiftapp/swift/Sources/App/AppControlService.swift
Jürgen Kunz ad059e9b8d Add MailRootView and related components for mail functionality
- Implement MailRootView with navigation and sidebar for mail management.
- Create MailSidebarView, ThreadListView, and ThreadDetailView for displaying mail content.
- Introduce ComposeView for composing new messages.
- Add MailTheme for consistent styling across mail components.
- Implement adaptive layouts for iOS and macOS.
- Create unit tests for AppNavigationCommand and AppViewModel to ensure correct functionality.
2026-04-19 01:00:32 +02:00

67 lines
2.2 KiB
Swift

import Foundation
protocol AppControlServicing {
func commands() -> AsyncStream<AppNavigationCommand>
}
struct MockBackendControlService: AppControlServicing {
static let controlFileEnvironmentKey = "SOCIALIO_CONTROL_FILE"
static let pollingIntervalEnvironmentKey = "SOCIALIO_CONTROL_POLL_MS"
private let environment: [String: String]
init(environment: [String: String] = ProcessInfo.processInfo.environment) {
self.environment = environment
}
func commands() -> AsyncStream<AppNavigationCommand> {
guard let controlFilePath = environment[Self.controlFileEnvironmentKey]?
.trimmingCharacters(in: .whitespacesAndNewlines),
!controlFilePath.isEmpty else {
return AsyncStream { continuation in
continuation.finish()
}
}
let controlFileURL = URL(fileURLWithPath: controlFilePath)
let pollingInterval = pollingIntervalDuration
return AsyncStream { continuation in
let task = Task.detached(priority: .background) {
var lastAppliedPayload: String?
while !Task.isCancelled {
if let payload = try? String(contentsOf: controlFileURL, encoding: .utf8) {
let trimmedPayload = payload.trimmingCharacters(in: .whitespacesAndNewlines)
if !trimmedPayload.isEmpty,
trimmedPayload != lastAppliedPayload,
let command = AppNavigationCommand.parse(trimmedPayload) {
lastAppliedPayload = trimmedPayload
continuation.yield(command)
}
}
try? await Task.sleep(for: pollingInterval)
}
continuation.finish()
}
continuation.onTermination = { _ in
task.cancel()
}
}
}
private var pollingIntervalDuration: Duration {
guard let rawValue = environment[Self.pollingIntervalEnvironmentKey],
let milliseconds = Int(rawValue),
milliseconds > 0 else {
return .milliseconds(600)
}
return .milliseconds(milliseconds)
}
}