I'm creating a MacOS SwiftUI application that uses a WindowGroup
and a MenuBarExtra
and the MenuBarExtra
has a menu option to launch my application. It utilises deep linking to allow a URL
to load the WindowGroup
and my ContentView
appears. However, if I launch the app multiple times from my menu bar item I get multiple WindowGroups
appearing.
I'd like to stop launching more than one view and simply launch the view if it's closed or bring the existing view to the front if it's already open.
Does anyone have any tips please?
I'd prefer not to use AppKit
, so whatever solution you suggest it would be great if it was created in SwiftUI only.
This is what I have tried so far:
//
// MyApp.swift
// Power Schedule
//
// Created by Paul Randall on 10/07/2023.
//
// Importing necessary frameworks
// MyApp.swift
import SwiftUI
// MyApp.swift
class AppState: ObservableObject {
@Published var isMainWindowActive: Bool = false
}
@main
struct Power_ScheduleApp: App {
@State private var menuBarExtraShown = true
@State var isMainWindowOpen = false
var body: some Scene {
MenuBarExtra(isInserted: $menuBarExtraShown) {
AppMenu()
} label: {
Label("", image: "psl")
}
.menuBarExtraStyle(.menu)
WindowGroup {
ContentView()
.frame(width: 450, height: 948) // Set the desired width and height
.fixedSize()
.onAppear {
print("Main window appeared")
self.isMainWindowOpen = true
}
.onDisappear {
print("Main window disappeared")
self.isMainWindowOpen = false
}
}
.handlesExternalEvents(matching: ["main"])
.windowResizability(.contentSize)
.commands {
if isMainWindowOpen {
CommandGroup(replacing: .newItem) {
Button("New Window", action: {})
.disabled(true)
// This is the same keyboard shortcut as the default New Window option.
// We're just doing this so that our disabled dummy option shows
// the same shortcut visually.
.keyboardShortcut(KeyboardShortcut("n", modifiers: [.command]))
}
} else {
// By doing nothing here, we let the default
// "File -> New Window" item display and handle input.
EmptyCommands()
}
}
}
}
struct AppMenu: View {
@Environment(\.openURL) var openUrl
@Environment(\.dismiss) var dismiss
func launchAppMenu() {
// Launch the window from a URL
guard let url = URL(string: "launchps://main") else {return}
openUrl(url)
}
func importMenu() {
dismiss()
}
func quitAppMenu() {
// func 3 code
}
var body: some View {
Button(action: launchAppMenu, label: { Text("Launch My App") }).keyboardShortcut("n")
Button(action: importMenu, label: { Text("Import Configs") }).keyboardShortcut("i")
Divider()
Button(action: quitAppMenu, label: { Text("Quit My App") }).keyboardShortcut("q")
}
}
For macOS 13+
Use
Window
instead ofWindowGroup
Window
In your code: