Redline: OneDrive folder transport as alternative to AirDrop (MMDB-2631) #23
@@ -132,6 +132,13 @@ public final class AppModel {
|
|||||||
}
|
}
|
||||||
func setTransport(_ value: SendTransport) { transport = value }
|
func setTransport(_ value: SendTransport) { transport = value }
|
||||||
func setResolvedOneDriveFolder(_ value: URL?) { resolvedOneDriveFolder = value }
|
func setResolvedOneDriveFolder(_ value: URL?) { resolvedOneDriveFolder = value }
|
||||||
|
|
||||||
|
/// Bumped by chooseTransport/chooseOneDriveFolder (SettingsView.swift) before each
|
||||||
|
/// spawns its async watcher-reconcile Task; that Task checks its own snapshot
|
||||||
|
/// against the live value before every mutating step, so rapid toggling always
|
||||||
|
/// lets the LAST choice win instead of applying stale, superseded work. Not
|
||||||
|
/// `@Observable`-relevant state — pure internal bookkeeping, never read by a View.
|
||||||
|
var reconcileGeneration = 0
|
||||||
func rememberLastComposedPDF(_ url: URL) { lastComposedPDFURL = url }
|
func rememberLastComposedPDF(_ url: URL) { lastComposedPDFURL = url }
|
||||||
|
|
||||||
/// True when a last-composed PDF path is known this run, or the newest
|
/// True when a last-composed PDF path is known this run, or the newest
|
||||||
@@ -211,6 +218,17 @@ public final class AppModel {
|
|||||||
await watcher.setRecordUncommented(transport == .airDrop)
|
await watcher.setRecordUncommented(transport == .airDrop)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
// BLOCKER fix: reconcile the watcher's internal watchFolder with the live
|
||||||
|
// watchFolderURL UNCONDITIONALLY, before it ever starts. `paths` (and so the
|
||||||
|
// watcher's initial folder, set in its own init) now comes from the same
|
||||||
|
// transport-aware TransportSettings.effectiveFolders() as watchFolderURL, so
|
||||||
|
// in the normal case this is a no-op — but it is the only thing that would
|
||||||
|
// have caught the old bug (launch paths built AirDrop-only while OneDrive was
|
||||||
|
// the persisted transport, leaving the watcher's FSEvents stream pointed at a
|
||||||
|
// stale folder for the whole session) and it stays cheap insurance against
|
||||||
|
// that class of drift ever recurring. Calling it before start() only updates
|
||||||
|
// the stored folder — no FSEvents stream exists yet to restart.
|
||||||
|
try await watcher.updateWatchFolder(watchFolderURL)
|
||||||
try await watcher.start { [weak self] _ in
|
try await watcher.start { [weak self] _ in
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|||||||
@@ -50,9 +50,18 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
Task { await model.bootstrap() }
|
Task { await model.bootstrap() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func makeLaunchModel() -> AppModel {
|
/// Builds the model exactly the way the real app launches: paths come from
|
||||||
|
/// `TransportSettings.resolvedAppSupportPaths()` — transport-aware, so the watcher
|
||||||
|
/// this feeds is never seeded with a stale AirDrop folder while OneDrive is the
|
||||||
|
/// persisted transport (that was the BLOCKER this function used to have, when it
|
||||||
|
/// called the AirDrop-only `FolderSettings.resolvedAppSupportPaths()` instead).
|
||||||
|
/// `appSupportRoot` exists only so PickerSelfTest's relaunch-simulation sub-step can
|
||||||
|
/// point this at a temp directory instead of the real
|
||||||
|
/// ~/Library/Application Support/Shotdeck — production always calls this with no
|
||||||
|
/// argument (the real root). Internal, not private, for that same reason.
|
||||||
|
static func makeLaunchModel(appSupportRoot: URL? = nil) -> AppModel {
|
||||||
do {
|
do {
|
||||||
let paths = try FolderSettings.resolvedAppSupportPaths()
|
let paths = try TransportSettings.resolvedAppSupportPaths(root: appSupportRoot)
|
||||||
return try makeModel(paths: paths)
|
return try makeModel(paths: paths)
|
||||||
} catch {
|
} catch {
|
||||||
Log.ui.critical(
|
Log.ui.critical(
|
||||||
|
|||||||
Reference in New Issue
Block a user