← All repositories

listless

A simple list app for Apple platforms

git clone https://code.inqk.net/listless.git


commit 7cba48e134ed7925eff330ca039434dc89e73740
parent f7fd505561ba27161bed9b87b0021ec7ae1199c7
Author: Michael Camilleri <[email protected]>
Date:   Fri, 13 Mar 2026 10:10:56 +0900

Simplify draft row-related variable names

Diffstat

MListless/Extensions/TaskListView+Logic.swift | 28++++++++++++++--------------
MListless/Helpers/TaskListViewProtocol.swift | 4++--
MListlessMac/Helpers/ClickableTextField.swift | 23++++++++---------------
MListlessMac/Views/TaskListView.swift | 30+++++++++++++++---------------
MListlessiOS/Views/TaskListView.swift | 40++++++++++++++++++++--------------------

5 files changed, 59 insertions(+), 66 deletions(-)

diff --git a/Listless/Extensions/TaskListView+Logic.swift b/Listless/Extensions/TaskListView+Logic.swift

@@ -58,7 +58,7 @@ extension TaskListViewProtocol {
         return lastTask.id == taskID
     }
 
-    func draftTaskID(for placement: DraftTaskPlacement) -> UUID {
+    func draftID(for placement: DraftTaskPlacement) -> UUID {
         switch placement {
         case .prepend:
             draftPrependRowID
@@ -67,7 +67,7 @@ extension TaskListViewProtocol {
         }
     }
 
-    func draftTaskPlacement(for taskID: UUID) -> DraftTaskPlacement? {
+    func draftPlacement(for taskID: UUID) -> DraftTaskPlacement? {
         switch taskID {
         case draftPrependRowID:
             .prepend
@@ -90,22 +90,22 @@ extension TaskListViewProtocol {
     }
 
     func revealDraftTask(at placement: DraftTaskPlacement) {
-        if draftTaskPlacement != placement, draftTaskPlacement != nil {
+        if draftPlacement != placement, draftPlacement != nil {
             commitDraftTask()
         }
 
         clearDragState()
-        let taskID = draftTaskID(for: placement)
-        draftTaskTitle = ""
-        draftTaskPlacement = placement
+        let taskID = draftID(for: placement)
+        draftTitle = ""
+        draftPlacement = placement
         fState.pendingFocus = .task(taskID)
         focusedField = .task(taskID)
         fState.selectedTaskID = taskID
     }
 
     func beginDraftTaskEditing(_ placement: DraftTaskPlacement) {
-        guard draftTaskPlacement == placement else { return }
-        let taskID = draftTaskID(for: placement)
+        guard draftPlacement == placement else { return }
+        let taskID = draftID(for: placement)
         fState.selectedTaskID = taskID
         if case .task(let id) = fState.pendingFocus, id == taskID {
             fState.pendingFocus = nil
@@ -113,9 +113,9 @@ extension TaskListViewProtocol {
     }
 
     func commitDraftTask(shouldCreateNewTask: Bool = false) {
-        guard let placement = draftTaskPlacement else { return }
-        let taskID = draftTaskID(for: placement)
-        let title = draftTaskTitle.trimmingCharacters(in: .whitespacesAndNewlines)
+        guard let placement = draftPlacement else { return }
+        let taskID = draftID(for: placement)
+        let title = draftTitle.trimmingCharacters(in: .whitespacesAndNewlines)
 
         // Clear fState.pendingFocus before clearDraftTaskUI so that the iOS
         // onChange(of: focusedFieldBinding) nil-redirect doesn't re-focus
@@ -193,7 +193,7 @@ extension TaskListViewProtocol {
 
         if isTaskFocused || fState.selectedTaskID != nil {
             fState.pendingFocus = nil
-            if draftTaskPlacement != nil {
+            if draftPlacement != nil {
                 commitDraftTask()
             }
             fState.selectedTaskID = nil
@@ -211,7 +211,7 @@ extension TaskListViewProtocol {
             return
         }
 
-        if draftTaskPlacement(for: oldID) != nil {
+        if draftPlacement(for: oldID) != nil {
             return
         }
 
@@ -422,7 +422,7 @@ extension TaskListViewProtocol {
     }
 
     func endEditing(_ taskID: UUID, shouldCreateNewTask: Bool) {
-        if draftTaskPlacement(for: taskID) != nil {
+        if draftPlacement(for: taskID) != nil {
             commitDraftTask(shouldCreateNewTask: shouldCreateNewTask)
             return
         }

diff --git a/Listless/Helpers/TaskListViewProtocol.swift b/Listless/Helpers/TaskListViewProtocol.swift

@@ -10,8 +10,8 @@ protocol TaskListViewProtocol {
     var focusedField: FocusField? { get nonmutating set }
     var fState: FocusStateData { get nonmutating set }
     var dragState: DragState { get nonmutating set }
-    var draftTaskPlacement: DraftTaskPlacement? { get nonmutating set }
-    var draftTaskTitle: String { get nonmutating set }
+    var draftPlacement: DraftTaskPlacement? { get nonmutating set }
+    var draftTitle: String { get nonmutating set }
     func didStartDrag()
     func clearDraftTaskUI(at placement: DraftTaskPlacement, hasTitle: Bool)
 }

diff --git a/ListlessMac/Helpers/ClickableTextField.swift b/ListlessMac/Helpers/ClickableTextField.swift

@@ -115,25 +115,16 @@ struct ClickableTextField: NSViewRepresentable {
 
     // Calculate text height with wrapping
     private func calculateHeight(for text: String, width: CGFloat, font: NSFont) -> CGFloat {
-        let attributedString = NSAttributedString(
-            string: text.isEmpty ? "Enter text" : text,
+        let displayText = text.isEmpty ? "Enter text" : text
+        let rect = (displayText as NSString).boundingRect(
+            with: CGSize(width: width, height: .greatestFiniteMagnitude),
+            options: [.usesLineFragmentOrigin, .usesFontLeading],
             attributes: [.font: font]
         )
-        let textStorage = NSTextStorage(attributedString: attributedString)
-        let layoutManager = NSLayoutManager()
-        let textContainer = NSTextContainer(
-            size: CGSize(width: width, height: .greatestFiniteMagnitude))
-        textContainer.lineFragmentPadding = 0
-
-        layoutManager.addTextContainer(textContainer)
-        textStorage.addLayoutManager(layoutManager)
-
-        layoutManager.ensureLayout(for: textContainer)
-        let rect = layoutManager.usedRect(for: textContainer)
-
         return ceil(rect.height) + 4
     }
 
+    @MainActor
     final class Coordinator: NSObject, NSTextFieldDelegate {
         @Binding var text: String
         let onEditingChanged: (Bool, _ shouldCreateNewTask: Bool) -> Void
@@ -150,7 +141,6 @@ struct ClickableTextField: NSViewRepresentable {
             self.onContentChange = onContentChange
         }
 
-        @MainActor
         func applyStyle(to textField: NSTextField, text: String, isCompleted: Bool) {
             guard !text.isEmpty else {
                 textField.stringValue = ""
@@ -197,6 +187,9 @@ struct ClickableTextField: NSViewRepresentable {
         )
             -> Bool
         {
+            // Note: makeFirstResponder(nil) can trigger a Thread Performance
+            // Checker priority inversion warning. This is internal to AppKit's
+            // first responder machinery, not caused by our callback chain.
             if commandSelector == #selector(NSResponder.insertNewline(_:)) {
                 // Return key pressed
                 editEndReason = .returnKey

diff --git a/ListlessMac/Views/TaskListView.swift b/ListlessMac/Views/TaskListView.swift

@@ -5,8 +5,8 @@ struct TaskListView: View, TaskListViewProtocol {
     struct InteractionStateData {
         var dragState: DragState = .idle
         var liftedTaskID: UUID?
-        var draftTaskPlacement: DraftTaskPlacement?
-        var draftTaskTitle: String = ""
+        var draftPlacement: DraftTaskPlacement?
+        var draftTitle: String = ""
     }
 
     @Environment(\.undoManager) var undoManager
@@ -37,14 +37,14 @@ struct TaskListView: View, TaskListViewProtocol {
         nonmutating set { iState.dragState = newValue }
     }
 
-    var draftTaskPlacement: DraftTaskPlacement? {
-        get { iState.draftTaskPlacement }
-        nonmutating set { iState.draftTaskPlacement = newValue }
+    var draftPlacement: DraftTaskPlacement? {
+        get { iState.draftPlacement }
+        nonmutating set { iState.draftPlacement = newValue }
     }
 
-    var draftTaskTitle: String {
-        get { iState.draftTaskTitle }
-        nonmutating set { iState.draftTaskTitle = newValue }
+    var draftTitle: String {
+        get { iState.draftTitle }
+        nonmutating set { iState.draftTitle = newValue }
     }
 
     var vStackSpacing: CGFloat { 0 }
@@ -150,11 +150,11 @@ struct TaskListView: View, TaskListViewProtocol {
     }
 
     func clearDraftTaskUI(at placement: DraftTaskPlacement, hasTitle _: Bool) {
-        if draftTaskPlacement == placement {
-            draftTaskPlacement = nil
+        if draftPlacement == placement {
+            draftPlacement = nil
         }
-        draftTaskTitle = ""
-        if fState.selectedTaskID == draftTaskID(for: placement) {
+        draftTitle = ""
+        if fState.selectedTaskID == draftID(for: placement) {
             fState.selectedTaskID = nil
         }
         focusedField = nil
@@ -242,7 +242,7 @@ struct TaskListView: View, TaskListViewProtocol {
                     }
                 }
 
-                if draftTaskPlacement == .append {
+                if draftPlacement == .append {
                     let total = max(1, displayActiveTasks.count + 1)
                     let index = displayActiveTasks.count
                     let accentColor = cachedTaskColor(
@@ -260,8 +260,8 @@ struct TaskListView: View, TaskListViewProtocol {
 
                         ClickableTextField(
                             text: Binding(
-                                get: { iState.draftTaskTitle },
-                                set: { iState.draftTaskTitle = $0 }
+                                get: { iState.draftTitle },
+                                set: { iState.draftTitle = $0 }
                             ),
                             isCompleted: false,
                             onEditingChanged: { editing, shouldCreateNewTask in

diff --git a/ListlessiOS/Views/TaskListView.swift b/ListlessiOS/Views/TaskListView.swift

@@ -12,8 +12,8 @@ struct TaskListView: View, TaskListViewProtocol {
         var clearingTaskIDs: Set<UUID> = []
         var rowFrames: [UUID: CGRect] = [:]
         var undoToast: UndoToastData? = nil
-        var draftTaskPlacement: DraftTaskPlacement?
-        var draftTaskTitle: String = ""
+        var draftPlacement: DraftTaskPlacement?
+        var draftTitle: String = ""
     }
 
     @AppStorage("headingText") var headingText = "Items"
@@ -44,28 +44,28 @@ struct TaskListView: View, TaskListViewProtocol {
         nonmutating set { iState.dragState = newValue }
     }
 
-    var draftTaskPlacement: DraftTaskPlacement? {
-        get { iState.draftTaskPlacement }
-        nonmutating set { iState.draftTaskPlacement = newValue }
+    var draftPlacement: DraftTaskPlacement? {
+        get { iState.draftPlacement }
+        nonmutating set { iState.draftPlacement = newValue }
     }
 
-    var draftTaskTitle: String {
-        get { iState.draftTaskTitle }
-        nonmutating set { iState.draftTaskTitle = newValue }
+    var draftTitle: String {
+        get { iState.draftTitle }
+        nonmutating set { iState.draftTitle = newValue }
     }
 
     private var isPrependDraftVisible: Bool {
-        draftTaskPlacement == .prepend
+        draftPlacement == .prepend
     }
 
     private var isAppendDraftVisible: Bool {
-        draftTaskPlacement == .append
+        draftPlacement == .append
     }
 
-    var draftTaskTitleBinding: Binding<String> {
+    var draftTitleBinding: Binding<String> {
         Binding(
-            get: { iState.draftTaskTitle },
-            set: { iState.draftTaskTitle = $0 }
+            get: { iState.draftTitle },
+            set: { iState.draftTitle = $0 }
         )
     }
 
@@ -160,11 +160,11 @@ struct TaskListView: View, TaskListViewProtocol {
 
     func clearDraftTaskUI(at placement: DraftTaskPlacement, hasTitle: Bool) {
         let clear: () -> Void = {
-            if draftTaskPlacement == placement {
-                draftTaskPlacement = nil
+            if draftPlacement == placement {
+                draftPlacement = nil
             }
-            draftTaskTitle = ""
-            if fState.selectedTaskID == draftTaskID(for: placement) {
+            draftTitle = ""
+            if fState.selectedTaskID == draftID(for: placement) {
                 fState.selectedTaskID = nil
             }
 
@@ -283,7 +283,7 @@ struct TaskListView: View, TaskListViewProtocol {
                 .font(.system(size: 17))
 
             TappableTextField(
-                text: draftTaskTitleBinding,
+                text: draftTitleBinding,
                 isCompleted: false,
                 isDragging: false,
                 onEditingChanged: { editing, _ in
@@ -345,7 +345,7 @@ struct TaskListView: View, TaskListViewProtocol {
                     .font(.system(size: 17))
 
                 TappableTextField(
-                    text: draftTaskTitleBinding,
+                    text: draftTitleBinding,
                     isCompleted: false,
                     isDragging: false,
                     onEditingChanged: { editing, shouldCreateNewTask in
@@ -359,7 +359,7 @@ struct TaskListView: View, TaskListViewProtocol {
                             }
                         }
                     },
-                    returnKeyType: draftTaskTitle.trimmingCharacters(
+                    returnKeyType: draftTitle.trimmingCharacters(
                         in: .whitespacesAndNewlines
                     ).isEmpty ? .done : .next
                 )