So, here's solution I found.
The following code works partially. The Open Recent menu is populated properly without quiting the app.
But here's the issue:
If the user opens it when the player is playing music, the Open Recent menus closes.
I just found out that, apparently, it was linked to the fact that recentDiscsModel is a @StateObject. When the player is playing music, the PlayerView() is constantly updating.
However, I have no idea how to solve this...
(I use .fileImporter and not NSOpenPanel)
Here's the code :
@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()
}
.windowToolbarStyle(.unified)
.windowStyle(.hiddenTitleBar)
.windowResizability(.contentSize)
.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
class RecentDiscsModel: ObservableObject {
static let shared = RecentDiscsModel()
@Published private(set) var recentDocs: [URL] = []
private init() {
refresh()
}
func refresh() {
let newDocs = NSDocumentController.shared.recentDocumentURLs
if newDocs != recentDocs {
recentDocs = newDocs
}
}
}
class Globals: ObservableObject
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)
recentFilesViewModel.addRecentFile(path: url.path)
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()
}
}