- 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.
67 lines
2.2 KiB
Swift
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)
|
|
}
|
|
}
|