I reposted this issue from my previous post since I have a partial solution to it, and now have a more precise question. The previous post title was too broad.
My app is not Document-based, the UI is written with SwiftUI and I had to implement the 'Open Recent' menu myself. The class RecentDiscsModel has a refresh() function that forces the new opened file to be seen in the menu. Without that, the app needed to be restarted to see them. (The files were appearing in the Dock menu, however.)
My problem is, that when we open this 'Open Recent' menu, it closes when the UI is updating. My app being a Disc Player, the main and unique window UI is updating every second or more through many @Published properties from my AudioDiscPlayer class.
I have no idea how to prevent this issue.
@main struct MyApp: App
@main
struct MyApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject private var recentDiscsModel = RecentDiscsModel.shared
var body: some Scene {
Window("Player", id: "main-window") {
PlayerView()
}
.commands {
CommandGroup(replacing: .newItem) { }
CommandGroup(after: .newItem) {
Button("Open...") {
NotificationCenter.default.post(name: .openDocumentRequested, object: nil)
}
.keyboardShortcut("O", modifiers: .command)
if recentDiscsModel.recentDocs.isEmpty == false {
Menu("Open Recent") {
ForEach(NSDocumentController.shared.recentDocumentURLs, id: \.self) { url in
Button(url.lastPathComponent) {
global.insertDisc(at: url)
}
}
Divider()
Button("Clear Menu") {
NSDocumentController.shared.clearRecentDocuments(nil)
recentDiscsModel.refresh()
}
}
}
}
PlayBackMenu()
}
}
}
class RecentDiscsModel: ObservableObject | The class that handles the live refresh of the 'Open Recent' menu
class RecentDiscsModel: ObservableObject {
static let shared = RecentDiscsModel()
@Published private(set) var recentFiles: [URL] = []
private init() {
refresh()
}
func refresh() {
let newDocs = NSDocumentController.shared.recentDocumentURLs
if newDocs != recentDocs {
recentDocs = newDocs
}
}
}
class Globals: ObservableObject | This is the class that handling opening cueSheet file:
class Globals: ObservableObject {
static let shared = MCGlobals()
init() {}
@Published var errorMessage = ""
@Published var errorDetails = ""
@Published var showingErrorAlert = false
func handleFileImport(result: Result<URL, Error>) {
switch result {
case .success(let url):
guard url.startAccessingSecurityScopedResource() else {
errorMessage = "Unable to access file"
errorDetails = "Permission denied"
showingErrorAlert = true
return
}
defer { url.stopAccessingSecurityScopedResource() }
insertDisc(at: url)
case .failure(let error):
errorMessage = "Failed to import file"
errorDetails = error.localizedDescription
showingErrorAlert = true
}
}
func insertDisc(at url: URL, startPlayback: Bool = false) {
do {
try AudioDiscPlayer.shared.insertDisc(at: url, startPlayback: startPlayback)
NSDocumentController.shared.noteNewRecentDocumentURL(url)
} catch {
let nsError = error as NSError
errorMessage = nsError.localizedDescription
let reason = nsError.localizedFailureReason ?? ""
let recovery = nsError.localizedRecoverySuggestion ?? ""
errorDetails = "\n\n\(reason)\n\n\(recovery)".trimmingCharacters(in: .whitespacesAndNewlines)
showingErrorAlert = true
}
RecentDiscsModel.shared.refresh()
}
}