From 2517435551ea1f74fb6a91645230918688556b78 Mon Sep 17 00:00:00 2001 From: Trey t Date: Mon, 15 Dec 2025 22:04:31 -0600 Subject: [PATCH] Add swipe hint for empty first column in task kanban MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- iosApp/iosApp/Localizable.xcstrings | 4 + .../iosApp/Subviews/Task/TasksSection.swift | 77 ++++++++++++------ iosApp/iosApp/Task/AllTasksView.swift | 79 +++++++++++-------- 3 files changed, 103 insertions(+), 57 deletions(-) diff --git a/iosApp/iosApp/Localizable.xcstrings b/iosApp/iosApp/Localizable.xcstrings index 55e7483..8759ab0 100644 --- a/iosApp/iosApp/Localizable.xcstrings +++ b/iosApp/iosApp/Localizable.xcstrings @@ -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" : { }, diff --git a/iosApp/iosApp/Subviews/Task/TasksSection.swift b/iosApp/iosApp/Subviews/Task/TasksSection.swift index f4aafe6..0e5cca2 100644 --- a/iosApp/iosApp/Subviews/Task/TasksSection.swift +++ b/iosApp/iosApp/Subviews/Task/TasksSection.swift @@ -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( diff --git a/iosApp/iosApp/Task/AllTasksView.swift b/iosApp/iosApp/Task/AllTasksView.swift index 89036f6..9792c09 100644 --- a/iosApp/iosApp/Task/AllTasksView.swift +++ b/iosApp/iosApp/Task/AllTasksView.swift @@ -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)