mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Feature: Terminal stay open and shortcuts
This commit is contained in:
parent
39d1135006
commit
2085815ab5
7 changed files with 104 additions and 5 deletions
|
|
@ -433,7 +433,7 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 7;
|
CURRENT_PROJECT_VERSION = 8;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 9Y64TRM77N;
|
"DEVELOPMENT_TEAM[sdk=macosx*]" = 9Y64TRM77N;
|
||||||
|
|
@ -475,7 +475,7 @@
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
||||||
MARKETING_VERSION = 2.0.0;
|
MARKETING_VERSION = 2.0.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll.dev;
|
PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll.dev;
|
||||||
PRODUCT_NAME = Atoll;
|
PRODUCT_NAME = Atoll;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
|
@ -505,7 +505,7 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 7;
|
CURRENT_PROJECT_VERSION = 8;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = "";
|
||||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 9Y64TRM77N;
|
"DEVELOPMENT_TEAM[sdk=macosx*]" = 9Y64TRM77N;
|
||||||
|
|
@ -547,7 +547,7 @@
|
||||||
"@executable_path/../Frameworks",
|
"@executable_path/../Frameworks",
|
||||||
);
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
||||||
MARKETING_VERSION = 2.0.0;
|
MARKETING_VERSION = 2.0.1;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll;
|
PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll;
|
||||||
PRODUCT_NAME = Atoll;
|
PRODUCT_NAME = Atoll;
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ struct ContentView: View {
|
||||||
@State private var lastHapticTime: Date = Date()
|
@State private var lastHapticTime: Date = Date()
|
||||||
@State private var hoverClickMonitor: Any?
|
@State private var hoverClickMonitor: Any?
|
||||||
@State private var hoverClickLocalMonitor: Any?
|
@State private var hoverClickLocalMonitor: Any?
|
||||||
|
@State private var stickyTerminalClickMonitor: Any?
|
||||||
|
|
||||||
@State private var gestureProgress: CGFloat = .zero
|
@State private var gestureProgress: CGFloat = .zero
|
||||||
@State private var skipGestureActiveDirection: MusicManager.SkipDirection?
|
@State private var skipGestureActiveDirection: MusicManager.SkipDirection?
|
||||||
|
|
@ -424,6 +425,9 @@ struct ContentView: View {
|
||||||
isHovering = false
|
isHovering = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if newState == .closed {
|
||||||
|
removeStickyTerminalClickMonitor()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: vm.isBatteryPopoverActive) { _, newPopoverState in
|
.onChange(of: vm.isBatteryPopoverActive) { _, newPopoverState in
|
||||||
runAfter(0.1) {
|
runAfter(0.1) {
|
||||||
|
|
@ -606,6 +610,7 @@ struct ContentView: View {
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
hoverTask?.cancel()
|
hoverTask?.cancel()
|
||||||
stopHoverClickMonitor()
|
stopHoverClickMonitor()
|
||||||
|
removeStickyTerminalClickMonitor()
|
||||||
cancelMusicControlWindowSync()
|
cancelMusicControlWindowSync()
|
||||||
hideMusicControlWindow()
|
hideMusicControlWindow()
|
||||||
cancelMusicControlVisibilityTimer()
|
cancelMusicControlVisibilityTimer()
|
||||||
|
|
@ -1586,6 +1591,23 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func installStickyTerminalClickMonitor() {
|
||||||
|
guard stickyTerminalClickMonitor == nil else { return }
|
||||||
|
stickyTerminalClickMonitor = NSEvent.addGlobalMonitorForEvents(matching: [.leftMouseDown]) { [weak vm] _ in
|
||||||
|
Task { @MainActor in
|
||||||
|
guard let vm, vm.notchState == .open else { return }
|
||||||
|
vm.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func removeStickyTerminalClickMonitor() {
|
||||||
|
if let stickyTerminalClickMonitor {
|
||||||
|
NSEvent.removeMonitor(stickyTerminalClickMonitor)
|
||||||
|
self.stickyTerminalClickMonitor = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Hover Management
|
// MARK: - Hover Management
|
||||||
|
|
||||||
/// Handle hover state changes with debouncing
|
/// Handle hover state changes with debouncing
|
||||||
|
|
@ -1594,6 +1616,7 @@ struct ContentView: View {
|
||||||
|
|
||||||
if hovering {
|
if hovering {
|
||||||
startHoverClickMonitor()
|
startHoverClickMonitor()
|
||||||
|
removeStickyTerminalClickMonitor()
|
||||||
} else {
|
} else {
|
||||||
stopHoverClickMonitor()
|
stopHoverClickMonitor()
|
||||||
}
|
}
|
||||||
|
|
@ -1642,6 +1665,12 @@ struct ContentView: View {
|
||||||
|
|
||||||
if self.vm.notchState == .open && !self.shouldPreventAutoClose() {
|
if self.vm.notchState == .open && !self.shouldPreventAutoClose() {
|
||||||
self.vm.close()
|
self.vm.close()
|
||||||
|
} else if self.vm.notchState == .open
|
||||||
|
&& Defaults[.terminalStickyMode]
|
||||||
|
&& self.coordinator.currentView == .terminal {
|
||||||
|
// Terminal sticky mode kept the notch open — install a
|
||||||
|
// global click monitor so a click outside closes it.
|
||||||
|
self.installStickyTerminalClickMonitor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1660,7 +1689,7 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func shouldPreventAutoClose() -> Bool {
|
private func shouldPreventAutoClose() -> Bool {
|
||||||
coordinator.firstLaunch || hasAnyActivePopovers() || vm.isAutoCloseSuppressed || SharingStateManager.shared.preventNotchClose
|
coordinator.firstLaunch || hasAnyActivePopovers() || vm.isAutoCloseSuppressed || SharingStateManager.shared.preventNotchClose || (Defaults[.terminalStickyMode] && coordinator.currentView == .terminal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to prevent rapid haptic feedback
|
// Helper to prevent rapid haptic feedback
|
||||||
|
|
|
||||||
|
|
@ -894,6 +894,22 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
ColorPickerPanelManager.shared.toggleColorPickerPanel()
|
ColorPickerPanelManager.shared.toggleColorPickerPanel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyboardShortcuts.onKeyDown(for: .toggleTerminalTab) { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
|
guard Defaults[.enableShortcuts], Defaults[.enableTerminalFeature] else { return }
|
||||||
|
|
||||||
|
if vm.notchState == .closed {
|
||||||
|
vm.open()
|
||||||
|
coordinator.currentView = .terminal
|
||||||
|
} else {
|
||||||
|
if coordinator.currentView == .terminal {
|
||||||
|
vm.close()
|
||||||
|
} else {
|
||||||
|
coordinator.currentView = .terminal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KeyboardShortcuts.onKeyDown(for: .screenAssistantPanel) { [weak self] in
|
KeyboardShortcuts.onKeyDown(for: .screenAssistantPanel) { [weak self] in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
guard Defaults[.enableShortcuts], Defaults[.enableScreenAssistant] else { return }
|
guard Defaults[.enableShortcuts], Defaults[.enableScreenAssistant] else { return }
|
||||||
|
|
@ -920,6 +936,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
updateShortcut(.clipboardHistoryPanel, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableClipboardManager])
|
updateShortcut(.clipboardHistoryPanel, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableClipboardManager])
|
||||||
updateShortcut(.colorPickerPanel, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableColorPickerFeature])
|
updateShortcut(.colorPickerPanel, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableColorPickerFeature])
|
||||||
updateShortcut(.screenAssistantPanel, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableScreenAssistant])
|
updateShortcut(.screenAssistantPanel, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableScreenAssistant])
|
||||||
|
updateShortcut(.toggleTerminalTab, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableTerminalFeature])
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
|
|
|
||||||
|
|
@ -13239,6 +13239,9 @@
|
||||||
"Just now" : {
|
"Just now" : {
|
||||||
"comment" : "A string indicating that an action was performed just recently.",
|
"comment" : "A string indicating that an action was performed just recently.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
|
},
|
||||||
|
"Keep terminal open until clicked outside" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Keyboard Backlight HUD" : {
|
"Keyboard Backlight HUD" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|
@ -18201,6 +18204,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Opens the terminal tab in the notch. Default is Ctrl+`. Only works when terminal feature is enabled." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Option as Meta key" : {
|
"Option as Meta key" : {
|
||||||
|
|
||||||
|
|
@ -18648,6 +18654,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Prevents the terminal from closing when the cursor accidentally leaves the notch area." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Preview" : {
|
"Preview" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|
@ -23266,6 +23275,9 @@
|
||||||
"Terminal" : {
|
"Terminal" : {
|
||||||
"comment" : "The title of the settings view related to the terminal.",
|
"comment" : "The title of the settings view related to the terminal.",
|
||||||
"isCommentAutoGenerated" : true
|
"isCommentAutoGenerated" : true
|
||||||
|
},
|
||||||
|
"Terminal feature is disabled" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Terminal is disabled" : {
|
"Terminal is disabled" : {
|
||||||
"comment" : "A message displayed when the terminal feature is disabled.",
|
"comment" : "A message displayed when the terminal feature is disabled.",
|
||||||
|
|
@ -23849,6 +23861,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Toggle Terminal Tab:" : {
|
||||||
|
"comment" : "Name for a keyboard shortcut that toggles the terminal tab in the notch.",
|
||||||
|
"isCommentAutoGenerated" : true
|
||||||
|
},
|
||||||
"Toggle the Dynamic Island open or closed from anywhere." : {
|
"Toggle the Dynamic Island open or closed from anywhere." : {
|
||||||
"comment" : "A description of the \"Toggle Navigation\" keyboard shortcut.",
|
"comment" : "A description of the \"Toggle Navigation\" keyboard shortcut.",
|
||||||
"isCommentAutoGenerated" : true,
|
"isCommentAutoGenerated" : true,
|
||||||
|
|
|
||||||
|
|
@ -31,5 +31,6 @@ extension KeyboardShortcuts.Name {
|
||||||
static let increaseBacklight = Self("increaseBacklight", default: .init(.f2, modifiers: [.command]))
|
static let increaseBacklight = Self("increaseBacklight", default: .init(.f2, modifiers: [.command]))
|
||||||
static let toggleSneakPeek = Self("toggleSneakPeek", default: .init(.h, modifiers: [.command, .shift]))
|
static let toggleSneakPeek = Self("toggleSneakPeek", default: .init(.h, modifiers: [.command, .shift]))
|
||||||
static let toggleNotchOpen = Self("toggleNotchOpen", default: .init(.i, modifiers: [.command, .shift]))
|
static let toggleNotchOpen = Self("toggleNotchOpen", default: .init(.i, modifiers: [.command, .shift]))
|
||||||
|
static let toggleTerminalTab = Self("toggleTerminalTab", default: .init(.backtick, modifiers: [.control]))
|
||||||
static let startDemoTimer = Self("startDemoTimer", default: .init(.t, modifiers: [.command, .shift]))
|
static let startDemoTimer = Self("startDemoTimer", default: .init(.t, modifiers: [.command, .shift]))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5473,6 +5473,29 @@ struct Shortcuts: View {
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Section {
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
KeyboardShortcuts.Recorder("Toggle Terminal Tab:", name: .toggleTerminalTab)
|
||||||
|
.disabled(!enableShortcuts || !Defaults[.enableTerminalFeature])
|
||||||
|
if !Defaults[.enableTerminalFeature] {
|
||||||
|
Text("Terminal feature is disabled")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.padding(.top, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
} header: {
|
||||||
|
Text("Terminal")
|
||||||
|
} footer: {
|
||||||
|
Text("Opens the terminal tab in the notch. Default is Ctrl+`. Only works when terminal feature is enabled.")
|
||||||
|
.multilineTextAlignment(.trailing)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.font(.caption)
|
||||||
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
HStack {
|
HStack {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
|
|
@ -7218,6 +7241,18 @@ struct TerminalSettings: View {
|
||||||
Section {
|
Section {
|
||||||
Defaults.Toggle("Enable terminal", key: .enableTerminalFeature)
|
Defaults.Toggle("Enable terminal", key: .enableTerminalFeature)
|
||||||
.settingsHighlight(id: highlightID("Enable terminal"))
|
.settingsHighlight(id: highlightID("Enable terminal"))
|
||||||
|
|
||||||
|
if enableTerminalFeature {
|
||||||
|
Defaults.Toggle(key: .terminalStickyMode) {
|
||||||
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
Text("Keep terminal open until clicked outside")
|
||||||
|
Text("Prevents the terminal from closing when the cursor accidentally leaves the notch area.")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.settingsHighlight(id: highlightID("Keep terminal open"))
|
||||||
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text("General")
|
Text("General")
|
||||||
} footer: {
|
} footer: {
|
||||||
|
|
|
||||||
|
|
@ -926,6 +926,7 @@ extension Defaults.Keys {
|
||||||
static let terminalBackgroundColor = Key<Color>("terminalBackgroundColor", default: .black)
|
static let terminalBackgroundColor = Key<Color>("terminalBackgroundColor", default: .black)
|
||||||
static let terminalForegroundColor = Key<Color>("terminalForegroundColor", default: .white)
|
static let terminalForegroundColor = Key<Color>("terminalForegroundColor", default: .white)
|
||||||
static let terminalCursorColor = Key<Color>("terminalCursorColor", default: Color(.selectedControlColor))
|
static let terminalCursorColor = Key<Color>("terminalCursorColor", default: Color(.selectedControlColor))
|
||||||
|
static let terminalStickyMode = Key<Bool>("terminalStickyMode", default: false)
|
||||||
|
|
||||||
// MARK: Timer Feature
|
// MARK: Timer Feature
|
||||||
static let enableTimerFeature = Key<Bool>("enableTimerFeature", default: true)
|
static let enableTimerFeature = Key<Bool>("enableTimerFeature", default: true)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue