Skip to content

Commit

Permalink
Merge pull request #42 from boscojwho/bosco/open-at-login
Browse files Browse the repository at this point in the history
Bosco/open at login
  • Loading branch information
boscojwho authored Dec 5, 2023
2 parents 294d55b + 8518d40 commit 1c6a2bf
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 44 deletions.
8 changes: 8 additions & 0 deletions Chinotto.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
E4205D582B020F390026D4A0 /* DirectoriesStorageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4205D572B020F390026D4A0 /* DirectoriesStorageView.swift */; };
E4205D5A2B02211D0026D4A0 /* UnifiedStorageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4205D592B02211D0026D4A0 /* UnifiedStorageView.swift */; };
E4205D5C2B0227890026D4A0 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = E4205D5B2B0227890026D4A0 /* Localizable.xcstrings */; };
E44DD0FA2B1DCE4A0066487D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E44DD0F92B1DCE4A0066487D /* AppDelegate.swift */; };
E45A70A92B04CD6200AC8C3B /* CoreSimulatorTools in Frameworks */ = {isa = PBXBuildFile; productRef = E45A70A82B04CD6200AC8C3B /* CoreSimulatorTools */; };
E46674182B04BF3300782359 /* _CoreSimulatorDevicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E46674172B04BF3300782359 /* _CoreSimulatorDevicesView.swift */; };
E475191D2B03A2E800C360DD /* Subdirectories.swift in Sources */ = {isa = PBXBuildFile; fileRef = E475191C2B03A2E800C360DD /* Subdirectories.swift */; };
Expand All @@ -22,6 +23,7 @@
E47519292B03AB1800C360DD /* _CoreSimulatorUserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47519282B03AB1800C360DD /* _CoreSimulatorUserView.swift */; };
E4934CDE2B0D9BE000B4A527 /* AppPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4934CDD2B0D9BE000B4A527 /* AppPreferencesView.swift */; };
E4934CE02B0D9BEE00B4A527 /* GeneralPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4934CDF2B0D9BEE00B4A527 /* GeneralPreferencesView.swift */; };
E49397AC2B1EB880001204B6 /* LoginItemBehaviour.swift in Sources */ = {isa = PBXBuildFile; fileRef = E49397AB2B1EB880001204B6 /* LoginItemBehaviour.swift */; };
E49C418F2B0C551E001100EC /* FileSystemUI in Frameworks */ = {isa = PBXBuildFile; productRef = E49C418E2B0C551E001100EC /* FileSystemUI */; };
E49C41922B0C5616001100EC /* FileSystem in Frameworks */ = {isa = PBXBuildFile; productRef = E49C41912B0C5616001100EC /* FileSystem */; };
E4A30A892B00D24700BE5444 /* ChinottoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A30A882B00D24700BE5444 /* ChinottoApp.swift */; };
Expand Down Expand Up @@ -66,6 +68,7 @@
E4205D572B020F390026D4A0 /* DirectoriesStorageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoriesStorageView.swift; sourceTree = "<group>"; };
E4205D592B02211D0026D4A0 /* UnifiedStorageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedStorageView.swift; sourceTree = "<group>"; };
E4205D5B2B0227890026D4A0 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
E44DD0F92B1DCE4A0066487D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
E46674172B04BF3300782359 /* _CoreSimulatorDevicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _CoreSimulatorDevicesView.swift; sourceTree = "<group>"; };
E466741E2B04CCC100782359 /* CoreSimulatorTools */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = CoreSimulatorTools; path = Packages/CoreSimulatorTools; sourceTree = "<group>"; };
E475191C2B03A2E800C360DD /* Subdirectories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subdirectories.swift; sourceTree = "<group>"; };
Expand All @@ -79,6 +82,7 @@
E4934CDF2B0D9BEE00B4A527 /* GeneralPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralPreferencesView.swift; sourceTree = "<group>"; };
E49397852B194E29001204B6 /* Chinotto.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Chinotto.xcconfig; sourceTree = "<group>"; };
E49397862B194ED5001204B6 /* Chinotto-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Chinotto-release.xcconfig"; sourceTree = "<group>"; };
E49397AB2B1EB880001204B6 /* LoginItemBehaviour.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginItemBehaviour.swift; sourceTree = "<group>"; };
E49C418D2B0C54D5001100EC /* FileSystemUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FileSystemUI; path = Packages/FileSystemUI; sourceTree = "<group>"; };
E49C41902B0C55CB001100EC /* FileSystem */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FileSystem; path = Packages/FileSystem; sourceTree = "<group>"; };
E4A30A852B00D24700BE5444 /* Chinotto.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Chinotto.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -203,6 +207,8 @@
isa = PBXGroup;
children = (
E4A30A882B00D24700BE5444 /* ChinottoApp.swift */,
E44DD0F92B1DCE4A0066487D /* AppDelegate.swift */,
E49397AB2B1EB880001204B6 /* LoginItemBehaviour.swift */,
E4E10D3B2B16CE7A00126C53 /* ChinottoMenuBarApp.swift */,
E4F8ECCC2B083F440075AB04 /* XcodeVersion.swift */,
E4A30A8A2B00D24700BE5444 /* ContentView.swift */,
Expand Down Expand Up @@ -430,8 +436,10 @@
E475191F2B03A8ED00C360DD /* CachesView.swift in Sources */,
E4205D582B020F390026D4A0 /* DirectoriesStorageView.swift in Sources */,
E4F8ECBB2B0453220075AB04 /* DeveloperDiskImagesView.swift in Sources */,
E44DD0FA2B1DCE4A0066487D /* AppDelegate.swift in Sources */,
E4F8ECCD2B083F440075AB04 /* XcodeVersion.swift in Sources */,
E4E10D3C2B16CE7A00126C53 /* ChinottoMenuBarApp.swift in Sources */,
E49397AC2B1EB880001204B6 /* LoginItemBehaviour.swift in Sources */,
E4F8ECC12B0453DF0075AB04 /* XCPGDevicesView.swift in Sources */,
E475191D2B03A2E800C360DD /* Subdirectories.swift in Sources */,
E47519212B03AA5F00C360DD /* _CoreSimulatorUserCachesView.swift in Sources */,
Expand Down
19 changes: 19 additions & 0 deletions Chinotto/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// AppDelegate.swift
// Chinotto
//
// Created by Bosco Ho on 2023-12-04.
//

import Foundation
import AppKit

class AppDelegate: NSObject, NSApplicationDelegate {

func applicationDidFinishLaunching(_ notification: Notification) {
LoginItemBehaviour.hideWindowsOnDidFinishLaunching(
NSApplication.shared.windows,
notification
)
}
}
3 changes: 2 additions & 1 deletion Chinotto/ChinottoApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import CoreSimulatorUI

@main
struct ChinottoApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@AppStorage("showMenuBarExtra") private var showMenuBarExtra = true

var body: some Scene {
Expand Down Expand Up @@ -56,6 +57,6 @@ struct ChinottoApp: App {
}
.defaultPosition(.center)
.defaultSize(width: 480, height: 720)
.windowResizability(.contentSize)
.windowResizability(.contentMinSize)
}
}
8 changes: 8 additions & 0 deletions Chinotto/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ struct ContentView: View {
}
}
.navigationSplitViewColumnWidth(min: 200, ideal: 240)
.toolbar {
ToolbarItem {
SettingsLink {
Image(systemName: "gear")
.buttonBorderShape(.roundedRectangle)
}
}
}
} detail: {
if let selectedDir {
makeSelectedDirectoryView(selectedDir)
Expand Down
21 changes: 21 additions & 0 deletions Chinotto/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,9 @@
}
}
}
},
"Dismiss" : {

},
"Double-click to select a device" : {
"localizations" : {
Expand All @@ -429,6 +432,9 @@
}
}
}
},
"Error" : {

},
"General" : {
"localizations" : {
Expand All @@ -439,6 +445,9 @@
}
}
}
},
"Hide windows when app launches on login" : {

},
"Home" : {
"localizations" : {
Expand Down Expand Up @@ -499,6 +508,12 @@
}
}
}
},
"Launch app on login" : {

},
"Manage \"Login Items\"..." : {

},
"Manually managing this directory is not recommended." : {
"localizations" : {
Expand Down Expand Up @@ -571,6 +586,12 @@
}
}
}
},
"Open at Login" : {

},
"Previously opened windows will not be restored on launch." : {

},
"Recommended: Manage Toolchains using Xcode's built-in tool (Xcode > Toolchains > Manage Toolchains...)." : {
"localizations" : {
Expand Down
35 changes: 35 additions & 0 deletions Chinotto/LoginItemBehaviour.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// LoginItemBehaviour.swift
// Chinotto
//
// Created by Bosco Ho on 2023-12-04.
//

import Foundation
import AppKit

#if os(macOS)
struct LoginItemBehaviour {
private static var openAtLogin: Bool {
UserDefaults.standard.bool(forKey: "openAtLogin")
}

private static var hideWindowsOnLaunch: Bool {
UserDefaults.standard.bool(forKey: "hideWindowsOnLaunch")
}

static func hideWindowsOnDidFinishLaunching(_ windows: [NSWindow], _ notification: Notification) {
for window in windows {
if openAtLogin == true,
hideWindowsOnLaunch == true,
let isDefaultLaunch = notification.userInfo?[NSApplication.launchIsDefaultUserInfoKey] as? Bool,
isDefaultLaunch == false {
/// Menu bar app window and menu bar item window aren't restorable.
if window.isRestorable {
window.close()
}
}
}
}
}
#endif
2 changes: 1 addition & 1 deletion Chinotto/Preferences/AppPreferencesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct AppPreferencesView: View {
}
.tag(Tabs.general)
}
.frame(width: 480, height: 320)
.frame(minWidth: 480, minHeight: 320)
}
}

Expand Down
135 changes: 93 additions & 42 deletions Chinotto/Preferences/GeneralPreferencesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,114 @@

import SwiftUI
import DestructiveActions
import ServiceManagement

struct GeneralPreferencesView: View {


@AppStorage("openAtLogin") private var openAtLogin = false
@AppStorage("hideWindowsOnLaunch") private var hideWindowsOnLaunch = false
@AppStorage("showMenuBarExtra") private var showMenuBarExtra = true
@AppStorage("preferences.general.deletionBehaviour") var deletionBehaviour: DeletionBehaviour = .moveToTrash


@State private var openAtLoginError: Error?
@State private var isPresentingResetStorageDataAlert = false

var body: some View {
Form {
Section {
LabeledContent("Menu Bar") {
Toggle("Show in Menu Bar (compact view)", isOn: $showMenuBarExtra)
}
}

Spacer(minLength: 24)
.frame(height: 24)

Section {
Picker("Deletion Behavior:", selection: $deletionBehaviour) {
ForEach(DeletionBehaviour.allCases) { value in
Text(value.description).tag(value)
List {
Form {
Section {
LabeledContent("Menu Bar") {
Toggle("Show in Menu Bar (compact view)", isOn: $showMenuBarExtra)
}
}
.pickerStyle(.inline)

GroupBox {
HStack {
Image(systemName: deletionBehaviour.systemImage)
.foregroundStyle(deletionBehaviour.accentColor)
.fontWeight(.bold)
Text(deletionBehaviour.behaviourDescription)
.lineLimit(nil)

LabeledContent("Open at Login") {
Toggle("Launch app on login", isOn: $openAtLogin)
}
.onChange(of: openAtLogin) {
if openAtLogin {
do {
try SMAppService.mainApp.register()
} catch {
openAtLogin = false
openAtLoginError = error
}
} else {
SMAppService.mainApp.unregister { error in
openAtLogin = false
openAtLoginError = error
}
}
}
Toggle("Hide windows when app launches on login", isOn: $hideWindowsOnLaunch)
.disabled(openAtLogin == false)

if hideWindowsOnLaunch, openAtLogin {
GroupBox {
HStack {
Image(systemName: "exclamationmark.triangle")
.foregroundStyle(.red)
.fontWeight(.bold)
Text("Previously opened windows will not be restored on launch.")
.lineLimit(nil)
}
}
.frame(maxWidth: 320)
}

Button("Manage \"Login Items\"...") {
SMAppService.openSystemSettingsLoginItems()
}
}
.frame(maxWidth: 320)
}

Spacer(minLength: 24)
.frame(height: 24)

Section {
Button("Reset Storage Data...") {
isPresentingResetStorageDataAlert = true

Spacer(minLength: 24)
.frame(height: 24)

Section {
Picker("Deletion Behavior:", selection: $deletionBehaviour) {
ForEach(DeletionBehaviour.allCases) { value in
Text(value.description).tag(value)
}
}
.pickerStyle(.inline)

GroupBox {
HStack {
Image(systemName: deletionBehaviour.systemImage)
.foregroundStyle(deletionBehaviour.accentColor)
.fontWeight(.bold)
Text(deletionBehaviour.behaviourDescription)
.lineLimit(nil)
}
}
.frame(maxWidth: 320)
}
GroupBox {
HStack {
Image(systemName: "exclamationmark.triangle")
.foregroundStyle(.red)
.fontWeight(.bold)
Text("This includes disk usage statistics that may take some time to calculate.")

Spacer(minLength: 24)
.frame(height: 24)

Section {
Button("Reset Storage Data...") {
isPresentingResetStorageDataAlert = true
}
GroupBox {
HStack {
Image(systemName: "exclamationmark.triangle")
.foregroundStyle(.red)
.fontWeight(.bold)
Text("This includes disk usage statistics that may take some time to calculate.")
}
}
.frame(maxWidth: 320)
}
.frame(maxWidth: 320)
}
}
.alert("Error", isPresented: .init(get: {
openAtLoginError != nil
}, set: { _ in
// no-op
}), presenting: openAtLoginError, actions: { error in
Button("Dismiss", role: .cancel) { }
})
.alert("Are you sure you want to reset storage data?", isPresented: $isPresentingResetStorageDataAlert) {
Button("Cancel", role: .cancel) { }
Button("Reset", role: .destructive) {
Expand Down

0 comments on commit 1c6a2bf

Please sign in to comment.