Note
This project is no longer maintained. Dvandva is an alternative supporting multiple platforms.
PigeonApp contains two structures, PigeonApp
and PigeonDocumentApp
for replacing SwiftUI’s WindowGroup
and DocumentGroup
for the main window of an app. It adds commands and a settings window while being fully customizable.
- Open your Swift package in Xcode.
- Navigate to
File > Add Packages
. - Paste this URL into the search field:
https://github.com/david-swift/PigeonApp-macOS
- Click on
Copy Dependency
. - Navigate to the
Package.swift
file. - In the
Package
initializer, underdependencies
, paste the dependency into the array.
- Open your Xcode project in Xcode.
- Navigate to
File > Add Packages
. - Paste this URL into the search field:
https://github.com/david-swift/PigeonApp-macOS
- Click on
Add Package
.
Replace WindowGroup
with PigeonApp
and DocumentGroup
with PigeonDocumentApp
in the body of your app’s main structure.
@main
struct YourApp: App {
var body: some Scene {
PigeonApp(appName: "YourApp", appIcon: .init(nsImage: .init(named: "AppIcon")!)) { iconFill, theme, templates in
Text("Your App")
.toolbar(id: "toolbar") {
Button("Toolbar") { }
}
}
}
}
There are several elements added to your app.
- The app window.
- A settings window.
- The tab “General” in the settings window.
- The tab “About” in the tab “General” with the app icon and name.
- The tab “Appearance” in the tab “General” with options for customizing the color scheme behavior, icon fill and toolbar appearance. You can access the icon fill via the first closure parameter of the sidebar, content, or detail content view. Note that a PigeonApp has to have a customizable toolbar in order to work properly. If that is not the case, hide the “General” settings tab.
- The tab “Updates” in the settings window that only shows “You’re up-to-date!” at the moment.
- The tab “General” in the settings window.
YourApp > About YourApp
that opens the “About” tab in the “General” settings tab.YourApp > Updates
that opens the “Updates” settings tab.YourApp > Settings
, a menu from which you can open all the available settings tabs and subtabs.View > Hide Toolbar
andView > Customize Toolbar
for hiding and customizing your main window’s toolbar.- All the commands that a
WindowGroup
orDocumentGroup
adds.
Use those functions as you would use SwiftUI modifiers, that means, by calling them one after another on your PigeonApp
or PigeonDocumentApp
.
Add a description, links, contributors and acknowledgements to the “About” tab in the “General” settings tab. The links will also appear under Help
in the menu bar.
// ...
.information(description: "Description") {
("Repository", .string("https://github.com/user/repository"))
("Another Link", .string("https://example.com/"))
} contributors: {
("david-swift", .string("https://github.com/david-swift"))
} acknowledgements: {
("GitHub", .string("https://github.com/"))
}
// ...
Add a link to your app’s help. It will appear under Help > _
where _
is the help’s label and in the About
tab in the General
settings tab.
// ...
.help("YourApp Help", link: .string("https://example.com/"))
// ...
Access the newest version of your app in an asynchronous function. If the newest version does not match the newest version in the version history, a button for updating is presented in the “Updates” settings tab.
// ...
.newestVersion { try await getVersions()[0] }
// ...
If you’re using GitHub releases and marking the latest version, use newestVersion(gitHubUser:gitHubRepo:)
instead.
Add a version history to the “Updates” tab and the newest version to the “About” tab in the “General” settings tab. Note that the newest version is the highest in the result builder.
// ...
.versions {
Version("1.0.2", date: .now) {
Version.Feature("Cooler App Icon", description: "Update the app icon design.", icon: .app)
}
Version("1.0.1", date: .distantPast) {
Version.Feature("Nicer Settings", description: "Add some settings tabs.", icon: .gearshape)
Version.Feature("Updated Design", description: "Add rounded corners to every button.", icon: .rectangle)
}
Version("1.0.0", date: .distantPast) {
Version.Feature("Initial Release", description: "YourApp is here!", icon: .partyPopper)
}
}
// ...
Specify the default templates and thereby activate the templates settings tab. You are responsible for providing user interfaces for using the templates in your app and adding templates, while the settings provide a user interface for deleting and managing the templates and also saves them.
// ...
.templates {
TemplateFolder(title: "Hello", icon: .handWave) {
Template(title: "Teddy", icon: .teddybear, content: .init())
}
}
// ...
To access the templates in your app, use the third closure parameter in the definition of your detail content, content, or sidebar view. Add a folder using the PigeonAppAction.add(_:)
function and add a template to a folder using the PigeonAppAction.add(_:to:)
function anywhere in your app.
Add the “Themes” settings tab by providing a preview for the themes. The preview should represent your application’s main UI. You can access the active theme using the second closure parameter in the definition of your sidebar, content, or detail content view.
// ...
.themes { theme in
Text("That's the preview!")
.padding()
.foregroundColor(theme.activeTheme(scheme: scheme).primaryAccent)
.background(theme.activeTheme(scheme: scheme).background)
}
// ...
Add the “Advanced” settings tab by defining the subtabs.
// ...
.advancedSettings {
SettingsSubtab(.init("Location", systemSymbol: .location), id: "location") {
Text("Location")
}
}
// ...
Add the “Behaviors” settings tab by providing behaviors titles and their function editors. You are responsible for managing the behaviors, find more information here.
// ...
.behaviors {
("Added Task", .init($addedTask))
("Edited Task", .init($editedTask))
}
// ...
Let the user specify a Supabase project and table row for synchronization. Local changes are automatically written into the table row and changes on the database observed and the local value updated.
// ...
.supabase(data: $data, table: "table")
// ...
Add custom settings tabs. Do not use settings(symbolVariant:_:)
, instead, use pigeonSettings(_:)
. Learn here more about how to define settings or extend existing tabs.
// ...
.pigeonSettings {
SettingsTab(.init("Cool", systemSymbol: .hare), id: "cool") {
SettingsSubtab(.noSelection, id: "tab") {
Text("The default tab.")
}
}
}
// ...
Use the modifiers extendAboutView(content:)
, extendAppearanceView(content:)
and extendShortcutsView(content:)
for extending (or adding) these subtabs.
Hide settings tabs.
// ...
.hide(tab: .general)
// ...
- Supabase licensed under the MIT license
- ActionKit licensed under the MIT license
- SettingsKit licensed under the MIT license
- SwiftLintPlugin licensed under the MIT license
- The contributors
- SourceDocs used for generating the docs
- SwiftLint for checking whether code style conventions are violated
- The programming language Swift