Add swipe hint for empty first column in task kanban
Shows a subtle "Swipe to see your tasks" hint centered on the first column (Overdue) when it's empty but other columns have tasks. The hint uses the theme primary color and scrolls with the column. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24926,6 +24926,10 @@
|
||||
"comment" : "The title of an alert that appears when a user successfully upgrades to a premium subscription.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Swipe to see your tasks" : {
|
||||
"comment" : "A hint displayed in the \"Tasks\" section of the app, encouraging users to swipe to view their tasks.",
|
||||
"isCommentAutoGenerated" : true
|
||||
},
|
||||
"Take your home management\nto the next level" : {
|
||||
|
||||
},
|
||||
|
||||
@@ -15,6 +15,12 @@ struct TasksSection: View {
|
||||
tasksResponse.columns.allSatisfy { $0.tasks.isEmpty }
|
||||
}
|
||||
|
||||
private var shouldShowSwipeHint: Bool {
|
||||
guard let firstColumn = tasksResponse.columns.first else { return false }
|
||||
let hasTasksInOtherColumns = tasksResponse.columns.dropFirst().contains { !$0.tasks.isEmpty }
|
||||
return firstColumn.tasks.isEmpty && hasTasksInOtherColumns
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text("Tasks")
|
||||
@@ -28,32 +34,38 @@ struct TasksSection: View {
|
||||
GeometryReader { geometry in
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
LazyHStack(spacing: 16) {
|
||||
// Dynamically create columns from response
|
||||
ForEach(Array(tasksResponse.columns.enumerated()), id: \.element.name) { index, column in
|
||||
DynamicTaskColumnView(
|
||||
column: column,
|
||||
onEditTask: { task in
|
||||
onEditTask(task)
|
||||
},
|
||||
onCancelTask: { task in
|
||||
onCancelTask(task)
|
||||
},
|
||||
onUncancelTask: { taskId in
|
||||
onUncancelTask(taskId)
|
||||
},
|
||||
onMarkInProgress: { taskId in
|
||||
onMarkInProgress(taskId)
|
||||
},
|
||||
onCompleteTask: { task in
|
||||
onCompleteTask(task)
|
||||
},
|
||||
onArchiveTask: { task in
|
||||
onArchiveTask(task)
|
||||
},
|
||||
onUnarchiveTask: { taskId in
|
||||
onUnarchiveTask(taskId)
|
||||
ZStack {
|
||||
DynamicTaskColumnView(
|
||||
column: column,
|
||||
onEditTask: { task in
|
||||
onEditTask(task)
|
||||
},
|
||||
onCancelTask: { task in
|
||||
onCancelTask(task)
|
||||
},
|
||||
onUncancelTask: { taskId in
|
||||
onUncancelTask(taskId)
|
||||
},
|
||||
onMarkInProgress: { taskId in
|
||||
onMarkInProgress(taskId)
|
||||
},
|
||||
onCompleteTask: { task in
|
||||
onCompleteTask(task)
|
||||
},
|
||||
onArchiveTask: { task in
|
||||
onArchiveTask(task)
|
||||
},
|
||||
onUnarchiveTask: { taskId in
|
||||
onUnarchiveTask(taskId)
|
||||
}
|
||||
)
|
||||
|
||||
// Show swipe hint on first column when it's empty but others have tasks
|
||||
if index == 0 && shouldShowSwipeHint {
|
||||
SwipeHintView()
|
||||
}
|
||||
)
|
||||
}
|
||||
.frame(width: geometry.size.width - 48)
|
||||
}
|
||||
}
|
||||
@@ -68,6 +80,23 @@ struct TasksSection: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct SwipeHintView: View {
|
||||
var body: some View {
|
||||
HStack(spacing: 8) {
|
||||
Text("Swipe to see your tasks")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(Color.appPrimary)
|
||||
Image(systemName: "arrow.right")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(Color.appPrimary)
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 10)
|
||||
.background(Color.appPrimary.opacity(0.1))
|
||||
.cornerRadius(20)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
TasksSection(
|
||||
tasksResponse: TaskColumnsResponse(
|
||||
|
||||
@@ -31,6 +31,13 @@ struct AllTasksView: View {
|
||||
private var isLoadingTasks: Bool { taskViewModel.isLoadingTasks }
|
||||
private var tasksError: String? { taskViewModel.tasksError }
|
||||
|
||||
private var shouldShowSwipeHint: Bool {
|
||||
guard let response = tasksResponse,
|
||||
let firstColumn = response.columns.first else { return false }
|
||||
let hasTasksInOtherColumns = response.columns.dropFirst().contains { !$0.tasks.isEmpty }
|
||||
return firstColumn.tasks.isEmpty && hasTasksInOtherColumns
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
mainContent
|
||||
.sheet(isPresented: $showAddTask) {
|
||||
@@ -232,45 +239,51 @@ struct AllTasksView: View {
|
||||
LazyHGrid(rows: [
|
||||
GridItem(.flexible(), spacing: 16)
|
||||
], spacing: 16) {
|
||||
// Dynamically create columns from response
|
||||
ForEach(Array(tasksResponse.columns.enumerated()), id: \.element.name) { index, column in
|
||||
DynamicTaskColumnView(
|
||||
column: column,
|
||||
onEditTask: { task in
|
||||
selectedTaskForEdit = task
|
||||
showEditTask = true
|
||||
},
|
||||
onCancelTask: { task in
|
||||
selectedTaskForCancel = task
|
||||
showCancelConfirmation = true
|
||||
},
|
||||
onUncancelTask: { taskId in
|
||||
taskViewModel.uncancelTask(id: taskId) { _ in
|
||||
loadAllTasks()
|
||||
}
|
||||
},
|
||||
onMarkInProgress: { taskId in
|
||||
taskViewModel.markInProgress(id: taskId) { success in
|
||||
if success {
|
||||
ZStack {
|
||||
DynamicTaskColumnView(
|
||||
column: column,
|
||||
onEditTask: { task in
|
||||
selectedTaskForEdit = task
|
||||
showEditTask = true
|
||||
},
|
||||
onCancelTask: { task in
|
||||
selectedTaskForCancel = task
|
||||
showCancelConfirmation = true
|
||||
},
|
||||
onUncancelTask: { taskId in
|
||||
taskViewModel.uncancelTask(id: taskId) { _ in
|
||||
loadAllTasks()
|
||||
}
|
||||
},
|
||||
onMarkInProgress: { taskId in
|
||||
taskViewModel.markInProgress(id: taskId) { success in
|
||||
if success {
|
||||
loadAllTasks()
|
||||
}
|
||||
}
|
||||
},
|
||||
onCompleteTask: { task in
|
||||
selectedTaskForComplete = task
|
||||
},
|
||||
onArchiveTask: { task in
|
||||
selectedTaskForArchive = task
|
||||
showArchiveConfirmation = true
|
||||
},
|
||||
onUnarchiveTask: { taskId in
|
||||
taskViewModel.unarchiveTask(id: taskId) { _ in
|
||||
loadAllTasks()
|
||||
}
|
||||
}
|
||||
},
|
||||
onCompleteTask: { task in
|
||||
selectedTaskForComplete = task
|
||||
},
|
||||
onArchiveTask: { task in
|
||||
selectedTaskForArchive = task
|
||||
showArchiveConfirmation = true
|
||||
},
|
||||
onUnarchiveTask: { taskId in
|
||||
taskViewModel.unarchiveTask(id: taskId) { _ in
|
||||
loadAllTasks()
|
||||
}
|
||||
)
|
||||
|
||||
// Show swipe hint on first column when it's empty but others have tasks
|
||||
if index == 0 && shouldShowSwipeHint {
|
||||
SwipeHintView()
|
||||
}
|
||||
)
|
||||
}
|
||||
.frame(width: 350)
|
||||
.id(index) // Add ID for ScrollViewReader
|
||||
.id(index)
|
||||
.scrollTransition { content, phase in
|
||||
content
|
||||
.opacity(phase.isIdentity ? 1 : 0.8)
|
||||
|
||||
Reference in New Issue
Block a user