commit 47e27704ad6399b4a21778ae7860d7433cd55ff8
parent d8e196bd917a92ed7a0138dbf02ff92f969cb263
Author: Michael Camilleri <[email protected]>
Date: Wed, 25 Feb 2026 12:54:46 +0900
Fix miscellaneous issues
Co-Authored-By: Codex GPT 5.3 <[email protected]>
Diffstat:
5 files changed, 48 insertions(+), 35 deletions(-)
diff --git a/ListlessMac/Extensions/TaskListView+Toolbar.swift b/ListlessMac/Extensions/TaskListView+Toolbar.swift
@@ -27,7 +27,7 @@ extension TaskListView {
} label: {
Label("Delete", systemImage: "trash")
}
- .disabled(selectedTaskID == nil)
+ .disabled(selectedTaskID == nil || focusedField != .scrollView)
.help("Delete selected task")
Divider()
diff --git a/ListlessMac/Helpers/ClickableTextField.swift b/ListlessMac/Helpers/ClickableTextField.swift
@@ -7,7 +7,7 @@ class ClickableNSTextField: NSTextField {
override func becomeFirstResponder() -> Bool {
let result = super.becomeFirstResponder()
- if result {
+ if result, NSApp.currentEvent?.type == .leftMouseDown {
onBecomeFirstResponder?()
}
return result
diff --git a/ListlessMac/ListlessMacApp.swift b/ListlessMac/ListlessMacApp.swift
@@ -10,9 +10,18 @@ private enum MenuSelectors {
@MainActor
class AppDelegate: NSObject, NSApplicationDelegate, NSMenuItemValidation {
+ private let persistenceController: PersistenceController
+
+ override init() {
+ let isUITesting = ProcessInfo.processInfo.arguments.contains("UI_TESTING")
+ persistenceController = isUITesting ? PersistenceController(inMemory: true) : .shared
+ super.init()
+ }
+
func applicationDidFinishLaunching(_ notification: Notification) {
NSWindow.allowsAutomaticWindowTabbing = false
installMainMenu()
+ openNewWindow()
}
// MARK: - NSMenuItemValidation
@@ -22,7 +31,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuItemValidation {
func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
let coord = MenuCoordinator.shared
switch menuItem.action {
- case #selector(handleNewWindow): return coord.newWindow != nil
+ case #selector(handleNewWindow): return true
case #selector(handleDeleteTask): return coord.canDeleteSelectedTask
case #selector(handleMoveUp): return coord.canMoveSelectedTaskUp
case #selector(handleMoveDown): return coord.canMoveSelectedTaskDown
@@ -45,7 +54,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuItemValidation {
}
@objc private func handleNewWindow() {
- MenuCoordinator.shared.newWindow?()
+ openNewWindow()
}
@objc private func handleMoveUp() {
@@ -64,6 +73,32 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuItemValidation {
MenuCoordinator.shared.clearCompletedTasks?()
}
+ private func openNewWindow() {
+ let defaultContentSize = NSSize(width: 400, height: 350)
+ let rootView = TaskListView(
+ store: TaskStore(persistenceController: persistenceController),
+ syncMonitor: persistenceController.syncMonitor
+ )
+ .environment(\.managedObjectContext, persistenceController.viewContext)
+
+ let window = NSWindow(
+ contentRect: NSRect(origin: .zero, size: defaultContentSize),
+ styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
+ backing: .buffered,
+ defer: false
+ )
+ window.contentViewController = NSHostingController(rootView: rootView)
+ window.setContentSize(defaultContentSize)
+ window.minSize = NSSize(width: 320, height: 240)
+ window.titleVisibility = .hidden
+ window.titlebarAppearsTransparent = true
+ window.isRestorable = false
+ window.center()
+ window.makeKeyAndOrderFront(nil)
+ window.makeFirstResponder(nil)
+ NSApp.activate()
+ }
+
// MARK: - Main Menu
private func installMainMenu() {
@@ -202,24 +237,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuItemValidation {
}
@main
-struct ListlessMacApp: App {
- @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
- private let persistenceController: PersistenceController
-
- init() {
- let isUITesting = ProcessInfo.processInfo.arguments.contains("UI_TESTING")
- persistenceController = isUITesting ? PersistenceController(inMemory: true) : .shared
- }
-
- var body: some Scene {
- WindowGroup(id: "main") {
- TaskListView(
- store: TaskStore(persistenceController: persistenceController),
- syncMonitor: persistenceController.syncMonitor
- )
- .environment(\.managedObjectContext, persistenceController.viewContext)
+enum ListlessMacMain {
+ static func main() {
+ let app = NSApplication.shared
+ let delegate = AppDelegate()
+ app.setActivationPolicy(.regular)
+ app.delegate = delegate
+ withExtendedLifetime(delegate) {
+ app.run()
}
- .windowStyle(.hiddenTitleBar)
- .defaultSize(width: 400, height: 350)
}
}
diff --git a/ListlessMac/Views/TaskListView.swift b/ListlessMac/Views/TaskListView.swift
@@ -19,7 +19,6 @@ struct TaskListView: View {
struct InteractionStateData {
var dragState: DragState = .idle
- var pullOffset: CGFloat = 0
}
struct TaskStateData {
@@ -28,7 +27,6 @@ struct TaskListView: View {
@Environment(\.undoManager) var undoManager
@Environment(\.managedObjectContext) var managedObjectContext
- @Environment(\.openWindow) var openWindow
let store: TaskStore
@ObservedObject var syncMonitor: CloudKitSyncMonitor
@@ -68,11 +66,6 @@ struct TaskListView: View {
nonmutating set { iState.dragState = newValue }
}
- var pullOffset: CGFloat {
- get { iState.pullOffset }
- nonmutating set { iState.pullOffset = newValue }
- }
-
var refreshID: UUID {
get { tState.refreshID }
nonmutating set { tState.refreshID = newValue }
@@ -137,7 +130,6 @@ struct TaskListView: View {
func updateMenuCoordinator() {
let coord = MenuCoordinator.shared
coord.newTask = { createNewTask(); focusedField = nil }
- coord.newWindow = { openWindow(id: "main") }
coord.deleteSelectedTask = { _ = deleteSelectedTask() }
coord.moveSelectedTaskUp = { moveSelectedTaskUp() }
coord.moveSelectedTaskDown = { moveSelectedTaskDown() }
@@ -253,7 +245,6 @@ struct TaskListView: View {
}
}
.frame(maxWidth: .infinity, alignment: .topLeading)
- .offset(y: -pullOffset)
.dropDestination(for: String.self) { items, location in
handleDrop(items: items)
}
diff --git a/ListlessiOS/Views/PullToCreate.swift b/ListlessiOS/Views/PullToCreate.swift
@@ -9,13 +9,10 @@ struct PullToCreateIndicator: View {
private let indicatorHeight: CGFloat = 48
private let textSlideDistance: CGFloat = 22
- // Matches the "top" gradient stop used for the first active task row
- private let accentColor = Color(hue: 0.98, saturation: 0.85, brightness: 1.0)
-
var body: some View {
HStack(spacing: 0) {
Rectangle()
- .fill(accentColor)
+ .fill(taskColor(forIndex: 0, total: 1))
.frame(width: TaskRowMetrics.accentBarWidth)
HStack(alignment: .center, spacing: TaskRowMetrics.contentSpacing) {
Image(systemName: "circle")