commit 7d831d8ddffddb726ec25e3065572a83884564f4
parent 22d14a88e25a2f69ffc59fda81c7c5b4d8532fa7
Author: Michael Camilleri <[email protected]>
Date: Tue, 17 Feb 2026 16:10:47 +0900
Fix various bugs
Co-Authored-By: Codex GPT 5.3 <[email protected]>
Diffstat:
7 files changed, 44 insertions(+), 80 deletions(-)
diff --git a/Listless.xcodeproj/project.pbxproj b/Listless.xcodeproj/project.pbxproj
@@ -11,12 +11,14 @@
0ACA67F6578EFF181EE5C9A7 /* TaskItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB8A3BEB346267B30B4675F /* TaskItem.swift */; };
15B71073767FB4766A6BA2BE /* HoverCursorModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41D6E0CED14D79F31C45062 /* HoverCursorModifier.swift */; };
1AA328A921EF8A7FDD03119A /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75B048B19C5219862BBED2E7 /* TestHelpers.swift */; };
+ 1E3857004DDD888BB4A6ED50 /* AccentColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0630FFEEFF7662A414E9A8 /* AccentColor.swift */; };
269B93D5543770B464DFB37A /* TaskStoreOrderingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D3A2DDCE24E54ABCCFBBD4C /* TaskStoreOrderingTests.swift */; };
3ABE52A15C2059D8D5570528 /* TaskStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3DEE364304587D280C5672 /* TaskStore.swift */; };
3D1F551A03B97ECF4E3DC8B0 /* TaskRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E06485DBE35B60868E14202A /* TaskRowView.swift */; };
3FCEFB586D9A9085A201AE7D /* TaskListView+PullToCreate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BF73E1B8FE337B76D3E757 /* TaskListView+PullToCreate.swift */; };
42E4CDE1D17463554CC4F41F /* TaskListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537A913AC421BAEF60D26D9C /* TaskListView.swift */; };
5B60B409CE4BA668DB30A65D /* Listless.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C093494053E6C348F245D4EC /* Listless.xcdatamodeld */; };
+ 5CFFBC8A17E065640857540A /* AccentColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0630FFEEFF7662A414E9A8 /* AccentColor.swift */; };
614FCCA450EC0BFFD8B40640 /* ListlessMacApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA467DF2E59BDBE6EEF6A7D /* ListlessMacApp.swift */; };
6C252050E62AED3A0A684EBF /* KeyboardNavigationModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7B37EF6A2389656D105FF8 /* KeyboardNavigationModifier.swift */; };
731477635D3F4DFF1F78D673 /* AppColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1FE1858BC9E8915A091D33 /* AppColors.swift */; };
@@ -80,6 +82,7 @@
74255E6B6C40899E9B17D927 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = "<group>"; };
75B048B19C5219862BBED2E7 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = "<group>"; };
7C73E9D4C42CCABBF0F33543 /* Listless.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Listless.entitlements; sourceTree = "<group>"; };
+ 7F0630FFEEFF7662A414E9A8 /* AccentColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccentColor.swift; sourceTree = "<group>"; };
81880970CCFC2CB00B65047E /* PlatformTextFieldWidthModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformTextFieldWidthModifier.swift; sourceTree = "<group>"; };
82A3509AD32A54434BCC8017 /* HoverCursorModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoverCursorModifier.swift; sourceTree = "<group>"; };
9262207DAC21619BD9EDEE15 /* Listless.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Listless.entitlements; sourceTree = "<group>"; };
@@ -114,6 +117,7 @@
isa = PBXGroup;
children = (
D123BB181208FC825777B0A7 /* .gitkeep */,
+ 7F0630FFEEFF7662A414E9A8 /* AccentColor.swift */,
0E7B37EF6A2389656D105FF8 /* KeyboardNavigationModifier.swift */,
537A913AC421BAEF60D26D9C /* TaskListView.swift */,
);
@@ -365,6 +369,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 5CFFBC8A17E065640857540A /* AccentColor.swift in Sources */,
83378A0575640417ED41FC25 /* ClickableTextField.swift in Sources */,
15B71073767FB4766A6BA2BE /* HoverCursorModifier.swift in Sources */,
D8EFF49E9156083D675D47F0 /* KeyboardNavigationModifier.swift in Sources */,
@@ -388,6 +393,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 1E3857004DDD888BB4A6ED50 /* AccentColor.swift in Sources */,
731477635D3F4DFF1F78D673 /* AppColors.swift in Sources */,
FEC96DAA2BF8BB5D6D8504EB /* HoverCursorModifier.swift in Sources */,
6C252050E62AED3A0A684EBF /* KeyboardNavigationModifier.swift in Sources */,
diff --git a/Listless/Models/TaskStore.swift b/Listless/Models/TaskStore.swift
@@ -25,9 +25,9 @@ final class TaskStore {
let activeTasks = allTasks.filter { !$0.isCompleted }
.sorted { $0.sortOrder < $1.sortOrder }
- // Completed tasks sorted by updatedAt (most recently completed last)
+ // Completed tasks sorted by updatedAt (most recently completed first)
let completedTasks = allTasks.filter { $0.isCompleted }
- .sorted { $0.updatedAt < $1.updatedAt }
+ .sorted { $0.updatedAt > $1.updatedAt }
return activeTasks + completedTasks
} catch {
diff --git a/Listless/Sync/PersistenceController.swift b/Listless/Sync/PersistenceController.swift
@@ -51,8 +51,7 @@ final class PersistenceController {
do {
try context.save()
} catch {
- let nsError = error as NSError
- fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
+ print("Failed to save context: \(error.localizedDescription)")
}
}
}
diff --git a/Listless/Views/AccentColor.swift b/Listless/Views/AccentColor.swift
@@ -0,0 +1,29 @@
+import SwiftUI
+
+func taskColor(forIndex index: Int, total: Int) -> Color {
+ guard total > 1 else { return Color(hue: 0.98, saturation: 0.85, brightness: 1.0) }
+
+ // Gradient matches gradient.png: coral/red → pink/magenta → purple/blue
+ let progress = Double(index) / Double(total - 1)
+ let top = (h: 0.98, s: 0.85, b: 1.00)
+ let mid = (h: 0.88, s: 0.75, b: 0.95)
+ let bottom = (h: 0.72, s: 0.65, b: 0.85)
+
+ if progress < 0.5 {
+ return interpolateHSB(from: top, to: mid, progress: progress * 2.0)
+ } else {
+ return interpolateHSB(from: mid, to: bottom, progress: (progress - 0.5) * 2.0)
+ }
+}
+
+private func interpolateHSB(
+ from: (h: Double, s: Double, b: Double),
+ to: (h: Double, s: Double, b: Double),
+ progress: Double
+) -> Color {
+ Color(
+ hue: from.h + (to.h - from.h) * progress,
+ saturation: from.s + (to.s - from.s) * progress,
+ brightness: from.b + (to.b - from.b) * progress
+ )
+}
diff --git a/Listless/Views/TaskListView.swift b/Listless/Views/TaskListView.swift
@@ -202,7 +202,7 @@ struct TaskListView: View {
HStack(spacing: 0) {
Rectangle()
.fill(
- accentColor(
+ taskColor(
forIndex: visualOrder?.firstIndex(of: state.taskID) ?? 0,
total: displayActiveTasks.count
)
@@ -506,7 +506,7 @@ struct TaskListView: View {
}
guard let currentID = selectedTaskID else {
- selectedTaskID = completedTasks.first?.id ?? activeTasks.first?.id
+ selectedTaskID = activeTasks.first?.id ?? completedTasks.first?.id
return .handled
}
@@ -771,27 +771,5 @@ struct TaskListView: View {
visualOrder = nil
}
- private func accentColor(forIndex index: Int, total: Int) -> Color {
- guard total > 1 else { return Color(hue: 0.98, saturation: 0.85, brightness: 1.0) }
- let progress = Double(index) / Double(total - 1)
- let top = (h: 0.98, s: 0.85, b: 1.00)
- let mid = (h: 0.88, s: 0.75, b: 0.95)
- let bottom = (h: 0.72, s: 0.65, b: 0.85)
- if progress < 0.5 {
- let t = progress * 2.0
- return Color(
- hue: top.h + (mid.h - top.h) * t,
- saturation: top.s + (mid.s - top.s) * t,
- brightness: top.b + (mid.b - top.b) * t
- )
- } else {
- let t = (progress - 0.5) * 2.0
- return Color(
- hue: mid.h + (bottom.h - mid.h) * t,
- saturation: mid.s + (bottom.s - mid.s) * t,
- brightness: mid.b + (bottom.b - mid.b) * t
- )
- }
- }
#endif
}
diff --git a/ListlessMac/Views/TaskRowView.swift b/ListlessMac/Views/TaskRowView.swift
@@ -29,31 +29,7 @@ struct TaskRowView: View {
private func computeAccentColor() -> Color {
guard !task.isCompleted else { return .clear }
- guard totalTasks > 1 else { return Color(hue: 0.98, saturation: 0.85, brightness: 1.0) }
-
- // Gradient matches gradient.png: coral/red → pink/magenta → purple/blue
- let progress = Double(index) / Double(totalTasks - 1)
- let top = (h: 0.98, s: 0.85, b: 1.00)
- let mid = (h: 0.88, s: 0.75, b: 0.95)
- let bottom = (h: 0.72, s: 0.65, b: 0.85)
-
- if progress < 0.5 {
- return interpolateHSB(from: top, to: mid, progress: progress * 2.0)
- } else {
- return interpolateHSB(from: mid, to: bottom, progress: (progress - 0.5) * 2.0)
- }
- }
-
- private func interpolateHSB(
- from: (h: Double, s: Double, b: Double),
- to: (h: Double, s: Double, b: Double),
- progress: Double
- ) -> Color {
- Color(
- hue: from.h + (to.h - from.h) * progress,
- saturation: from.s + (to.s - from.s) * progress,
- brightness: from.b + (to.b - from.b) * progress
- )
+ return taskColor(forIndex: index, total: totalTasks)
}
init(
@@ -213,7 +189,7 @@ struct TaskRowView: View {
}
private func copyToPasteboard() {
- let text = isEditing ? editingTitle : task.title
+ let text = isCurrentlyEditing ? editingTitle : task.title
guard !text.isEmpty else { return }
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
@@ -222,7 +198,7 @@ struct TaskRowView: View {
private func pasteFromPasteboard() {
guard let string = NSPasteboard.general.string(forType: .string) else { return }
- if isEditing {
+ if isCurrentlyEditing {
editingTitle = string
}
onTitleChange(task, string)
diff --git a/ListlessiOS/Views/TaskRowView.swift b/ListlessiOS/Views/TaskRowView.swift
@@ -164,31 +164,7 @@ struct TaskRowView: View {
private func computeAccentColor() -> Color {
guard !task.isCompleted else { return .clear }
- guard totalTasks > 1 else { return Color(hue: 0.98, saturation: 0.85, brightness: 1.0) }
-
- // Gradient: coral/red → pink/magenta → purple/blue (matches macOS)
- let progress = Double(index) / Double(totalTasks - 1)
- let top = (h: 0.98, s: 0.85, b: 1.00)
- let mid = (h: 0.88, s: 0.75, b: 0.95)
- let bottom = (h: 0.72, s: 0.65, b: 0.85)
-
- if progress < 0.5 {
- return interpolateHSB(from: top, to: mid, progress: progress * 2.0)
- } else {
- return interpolateHSB(from: mid, to: bottom, progress: (progress - 0.5) * 2.0)
- }
- }
-
- private func interpolateHSB(
- from: (h: Double, s: Double, b: Double),
- to: (h: Double, s: Double, b: Double),
- progress: Double
- ) -> Color {
- Color(
- hue: from.h + (to.h - from.h) * progress,
- saturation: from.s + (to.s - from.s) * progress,
- brightness: from.b + (to.b - from.b) * progress
- )
+ return taskColor(forIndex: index, total: totalTasks)
}
@ViewBuilder