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_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
CURRENT_PROJECT_VERSION = 8;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 9Y64TRM77N;
|
||||
|
|
@ -475,7 +475,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll.dev;
|
||||
PRODUCT_NAME = Atoll;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
@ -505,7 +505,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 7;
|
||||
CURRENT_PROJECT_VERSION = 8;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 9Y64TRM77N;
|
||||
|
|
@ -547,7 +547,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 14.6;
|
||||
MARKETING_VERSION = 2.0.0;
|
||||
MARKETING_VERSION = 2.0.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.Ebullioscopic.Atoll;
|
||||
PRODUCT_NAME = Atoll;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ struct ContentView: View {
|
|||
@State private var lastHapticTime: Date = Date()
|
||||
@State private var hoverClickMonitor: Any?
|
||||
@State private var hoverClickLocalMonitor: Any?
|
||||
@State private var stickyTerminalClickMonitor: Any?
|
||||
|
||||
@State private var gestureProgress: CGFloat = .zero
|
||||
@State private var skipGestureActiveDirection: MusicManager.SkipDirection?
|
||||
|
|
@ -424,6 +425,9 @@ struct ContentView: View {
|
|||
isHovering = false
|
||||
}
|
||||
}
|
||||
if newState == .closed {
|
||||
removeStickyTerminalClickMonitor()
|
||||
}
|
||||
}
|
||||
.onChange(of: vm.isBatteryPopoverActive) { _, newPopoverState in
|
||||
runAfter(0.1) {
|
||||
|
|
@ -606,6 +610,7 @@ struct ContentView: View {
|
|||
.onDisappear {
|
||||
hoverTask?.cancel()
|
||||
stopHoverClickMonitor()
|
||||
removeStickyTerminalClickMonitor()
|
||||
cancelMusicControlWindowSync()
|
||||
hideMusicControlWindow()
|
||||
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
|
||||
|
||||
/// Handle hover state changes with debouncing
|
||||
|
|
@ -1594,6 +1616,7 @@ struct ContentView: View {
|
|||
|
||||
if hovering {
|
||||
startHoverClickMonitor()
|
||||
removeStickyTerminalClickMonitor()
|
||||
} else {
|
||||
stopHoverClickMonitor()
|
||||
}
|
||||
|
|
@ -1642,6 +1665,12 @@ struct ContentView: View {
|
|||
|
||||
if self.vm.notchState == .open && !self.shouldPreventAutoClose() {
|
||||
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 {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -894,6 +894,22 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||
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
|
||||
guard let self 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(.colorPickerPanel, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableColorPickerFeature])
|
||||
updateShortcut(.screenAssistantPanel, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableScreenAssistant])
|
||||
updateShortcut(.toggleTerminalTab, isEnabled: Defaults[.enableShortcuts] && Defaults[.enableTerminalFeature])
|
||||
}
|
||||
|
||||
@MainActor
|
||||
|
|
|
|||
|
|
@ -13239,6 +13239,9 @@
|
|||
"Just now" : {
|
||||
"comment" : "A string indicating that an action was performed just recently.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Keep terminal open until clicked outside" : {
|
||||
|
||||
},
|
||||
"Keyboard Backlight HUD" : {
|
||||
"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" : {
|
||||
|
||||
|
|
@ -18648,6 +18654,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Prevents the terminal from closing when the cursor accidentally leaves the notch area." : {
|
||||
|
||||
},
|
||||
"Preview" : {
|
||||
"localizations" : {
|
||||
|
|
@ -23266,6 +23275,9 @@
|
|||
"Terminal" : {
|
||||
"comment" : "The title of the settings view related to the terminal.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Terminal feature is disabled" : {
|
||||
|
||||
},
|
||||
"Terminal 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." : {
|
||||
"comment" : "A description of the \"Toggle Navigation\" keyboard shortcut.",
|
||||
"isCommentAutoGenerated" : true,
|
||||
|
|
|
|||
|
|
@ -31,5 +31,6 @@ extension KeyboardShortcuts.Name {
|
|||
static let increaseBacklight = Self("increaseBacklight", default: .init(.f2, modifiers: [.command]))
|
||||
static let toggleSneakPeek = Self("toggleSneakPeek", default: .init(.h, 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]))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5473,6 +5473,29 @@ struct Shortcuts: View {
|
|||
.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 {
|
||||
HStack {
|
||||
VStack(alignment: .leading) {
|
||||
|
|
@ -7218,6 +7241,18 @@ struct TerminalSettings: View {
|
|||
Section {
|
||||
Defaults.Toggle("Enable terminal", key: .enableTerminalFeature)
|
||||
.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: {
|
||||
Text("General")
|
||||
} footer: {
|
||||
|
|
|
|||
|
|
@ -926,6 +926,7 @@ extension Defaults.Keys {
|
|||
static let terminalBackgroundColor = Key<Color>("terminalBackgroundColor", default: .black)
|
||||
static let terminalForegroundColor = Key<Color>("terminalForegroundColor", default: .white)
|
||||
static let terminalCursorColor = Key<Color>("terminalCursorColor", default: Color(.selectedControlColor))
|
||||
static let terminalStickyMode = Key<Bool>("terminalStickyMode", default: false)
|
||||
|
||||
// MARK: Timer Feature
|
||||
static let enableTimerFeature = Key<Bool>("enableTimerFeature", default: true)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue