commit 88cad792b010172e156c691364d738bd8f11d47b
parent d2a80337b3b9cdb11e8a8968a5ca74d05b643938
Author: Michael Camilleri <[email protected]>
Date: Sat, 14 Feb 2026 13:28:51 +0900
Experiment with gradient colours
Co-Authored-By: Claude 4.5 Sonnet <[email protected]>
Diffstat:
6 files changed, 49 insertions(+), 52 deletions(-)
diff --git a/Listless.xcodeproj/project.pbxproj b/Listless.xcodeproj/project.pbxproj
@@ -36,7 +36,6 @@
D878CD3A552C6A9685A30AA8 /* PlatformTextFieldWidthModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF6B0195EA0176B72DE9B092 /* PlatformTextFieldWidthModifier.swift */; };
D8EFF49E9156083D675D47F0 /* KeyboardNavigationModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7B37EF6A2389656D105FF8 /* KeyboardNavigationModifier.swift */; };
D9DA553485AD0CA28D5BE0C8 /* TaskListView+Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93FF5B9F5B979D54D5DEE192 /* TaskListView+Toolbar.swift */; };
- DAB0D2F8881B234DDE2B0BF6 /* TaskRowTapGesture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8829E89B1F50224FCAE10F84 /* TaskRowTapGesture.swift */; };
DC71C45D92524C3893BF9FDB /* PlatformTextFieldWidthModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81880970CCFC2CB00B65047E /* PlatformTextFieldWidthModifier.swift */; };
DC73A39A269AB495BCE1AC48 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14858BDFD1FD5119F1F24A6 /* PersistenceController.swift */; };
ECD5E7EA05AE1C00B38C939E /* TaskStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 967F7ECEB3915CEDCE584872 /* TaskStoreTests.swift */; };
@@ -78,7 +77,6 @@
7C73E9D4C42CCABBF0F33543 /* Listless.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Listless.entitlements; 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>"; };
- 8829E89B1F50224FCAE10F84 /* TaskRowTapGesture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskRowTapGesture.swift; sourceTree = "<group>"; };
917597025B3D5D18E33982D3 /* ColorExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtensions.swift; sourceTree = "<group>"; };
9262207DAC21619BD9EDEE15 /* Listless.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Listless.entitlements; sourceTree = "<group>"; };
93FF5B9F5B979D54D5DEE192 /* TaskListView+Toolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TaskListView+Toolbar.swift"; sourceTree = "<group>"; };
@@ -142,7 +140,6 @@
93FF5B9F5B979D54D5DEE192 /* TaskListView+Toolbar.swift */,
1B3D0B4710C7A0EE4F227851 /* TaskRowDragGesture.swift */,
44C16D36971A140364159FB9 /* TaskRowSwipeGesture.swift */,
- 8829E89B1F50224FCAE10F84 /* TaskRowTapGesture.swift */,
199CC2F58DD7CBA3F2229366 /* TaskRowView.swift */,
);
path = Views;
@@ -388,7 +385,6 @@
42E4CDE1D17463554CC4F41F /* TaskListView.swift in Sources */,
D6B3DBDD6A3F0A6E166CFFD5 /* TaskRowDragGesture.swift in Sources */,
7B2CD636BA3B63A586F93E31 /* TaskRowSwipeGesture.swift in Sources */,
- DAB0D2F8881B234DDE2B0BF6 /* TaskRowTapGesture.swift in Sources */,
7E366008FF9335A77FE1636D /* TaskRowView.swift in Sources */,
91EDF52C7C5C0B35E9D8B51E /* TaskStore.swift in Sources */,
);
diff --git a/Listless/Views/TaskListView.swift b/Listless/Views/TaskListView.swift
@@ -129,6 +129,18 @@ struct TaskListView: View {
handleDrop(items: items)
}
}
+ // .background(
+ // LinearGradient(
+ // colors: [
+ // Color(hue: 0.98, saturation: 0.85, brightness: 1.0),
+ // Color(hue: 0.88, saturation: 0.75, brightness: 0.95),
+ // Color(hue: 0.72, saturation: 0.65, brightness: 0.85),
+ // ],
+ // startPoint: .top,
+ // endPoint: .bottom
+ // )
+ // .ignoresSafeArea()
+ // )
.contentShape(Rectangle())
.onTapGesture {
handleBackgroundTap()
diff --git a/ListlessMac/Views/TaskRowView.swift b/ListlessMac/Views/TaskRowView.swift
@@ -135,6 +135,16 @@ struct TaskRowView: View {
onSelect(taskID)
}
.background(selectionBackground)
+ .overlay(alignment: .bottom) {
+ if !task.isCompleted {
+ LinearGradient(
+ colors: [.clear, .black.opacity(0.15)],
+ startPoint: .top,
+ endPoint: .bottom
+ )
+ .frame(height: 6)
+ }
+ }
.overlay(alignment: .leading) {
// Colored accent bar on the left edge
Rectangle()
@@ -193,7 +203,9 @@ struct TaskRowView: View {
@ViewBuilder
private var selectionBackground: some View {
- if isSelected {
+ if task.isCompleted {
+ Color(nsColor: .windowBackgroundColor)
+ } else if isSelected {
RoundedRectangle(cornerRadius: 6, style: .continuous)
.fill(Color.accentColor.opacity(0.2))
}
diff --git a/ListlessiOS/Views/TaskRowSwipeGesture.swift b/ListlessiOS/Views/TaskRowSwipeGesture.swift
@@ -95,7 +95,7 @@ struct TaskRowSwipeGesture: ViewModifier {
Spacer()
Image(systemName: "trash.fill")
.font(.system(size: 24))
- .foregroundStyle(.white)
+ .foregroundStyle(isTriggered ? .black : .white)
.padding(.trailing, 20)
}
}
diff --git a/ListlessiOS/Views/TaskRowTapGesture.swift b/ListlessiOS/Views/TaskRowTapGesture.swift
@@ -1,39 +0,0 @@
-import SwiftUI
-
-extension View {
- func taskTapGesture(
- onCheckboxTap: @escaping () -> Void,
- onTextTap: @escaping () -> Void
- ) -> some View {
- self.modifier(
- TaskRowTapGesture(
- onCheckboxTap: onCheckboxTap,
- onTextTap: onTextTap
- ))
- }
-}
-
-struct TaskRowTapGesture: ViewModifier {
- let onCheckboxTap: () -> Void
- let onTextTap: () -> Void
-
- private let checkboxZoneWidth: CGFloat = 48 // Checkbox + padding area
-
- func body(content: Content) -> some View {
- content
- .contentShape(Rectangle())
- .onTapGesture(coordinateSpace: .local) { location in
- handleTap(at: location)
- }
- }
-
- private func handleTap(at location: CGPoint) {
- if location.x <= checkboxZoneWidth {
- // Tap in checkbox zone
- onCheckboxTap()
- } else {
- // Tap in text zone - TextField will handle focus natively
- onTextTap()
- }
- }
-}
diff --git a/ListlessiOS/Views/TaskRowView.swift b/ListlessiOS/Views/TaskRowView.swift
@@ -63,6 +63,7 @@ struct TaskRowView: View {
TextField("Task", text: $editingTitle)
.focused($focusedField, equals: .task(taskID))
+ .font(.system(size: 18))
.foregroundStyle(task.isCompleted ? Color.secondary : Color.primary)
.strikethrough(task.isCompleted, color: .secondary)
.disabled(task.isCompleted)
@@ -72,7 +73,7 @@ struct TaskRowView: View {
onEndEdit(taskID, true)
}
}
- .padding(.vertical, 8)
+ .padding(.vertical, 14)
.padding(.horizontal, 16)
.frame(maxWidth: .infinity, alignment: .leading)
.contentShape(Rectangle())
@@ -94,6 +95,21 @@ struct TaskRowView: View {
}
}
.background(selectionBackground)
+ .overlay(alignment: .top) {
+ if !task.isCompleted {
+ VStack(spacing: 0) {
+ LinearGradient(
+ colors: [.black.opacity(0.10), .clear],
+ startPoint: .bottom,
+ endPoint: .top
+ )
+ .frame(height: 6)
+ Rectangle()
+ .fill(.black.opacity(0.4))
+ .frame(height: 0.5)
+ }
+ }
+ }
.onAppear {
editingTitle = task.title
}
@@ -128,12 +144,12 @@ struct TaskRowView: View {
)
}
+ @ViewBuilder
private var selectionBackground: some View {
- Color(uiColor: .systemBackground)
- .overlay {
- if isSelected {
- Color.accentColor.opacity(0.2)
- }
- }
+ if task.isCompleted {
+ Color(uiColor: .systemBackground)
+ } else if isSelected {
+ Color.accentColor.opacity(0.2)
+ }
}
}