summaryrefslogtreecommitdiff
path: root/Hutch/Views/Home/HomeView.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-03-22 20:42:53 -0500
committerChristian Cleberg <[email protected]>2026-03-22 20:42:53 -0500
commit82e54ad018ae5fa5cdf90c0d763e09e99bc0e933 (patch)
treecafdbc8f4116af5cc6e0ca706e05ced599e26570 /Hutch/Views/Home/HomeView.swift
parent1f8b7a23529462c3c332753d33810b5c9f692bbc (diff)
downloadhutch-82e54ad018ae5fa5cdf90c0d763e09e99bc0e933.tar.gz
hutch-82e54ad018ae5fa5cdf90c0d763e09e99bc0e933.tar.bz2
hutch-82e54ad018ae5fa5cdf90c0d763e09e99bc0e933.zip
feat: swipe actions on tickets, pastes, builds, and home dashboard
Diffstat (limited to 'Hutch/Views/Home/HomeView.swift')
-rw-r--r--Hutch/Views/Home/HomeView.swift87
1 files changed, 87 insertions, 0 deletions
diff --git a/Hutch/Views/Home/HomeView.swift b/Hutch/Views/Home/HomeView.swift
index 55ec41e..d3d370a 100644
--- a/Hutch/Views/Home/HomeView.swift
+++ b/Hutch/Views/Home/HomeView.swift
@@ -1,6 +1,7 @@
import SwiftUI
struct HomeView: View {
+ @AppStorage(AppStorageKeys.swipeActionsEnabled) private var swipeActionsEnabled = true
@Environment(AppState.self) private var appState
@State private var viewModel: HomeViewModel?
private let previewLimit = 4
@@ -109,6 +110,23 @@ struct HomeView: View {
} label: {
HomeAssignedTicketRow(ticket: ticket)
}
+ .swipeActions(edge: .leading, allowsFullSwipe: true) {
+ if swipeActionsEnabled {
+ ticketLeadingSwipeAction(ticket, viewModel: viewModel)
+ }
+ }
+ .swipeActions(edge: .trailing, allowsFullSwipe: false) {
+ if swipeActionsEnabled {
+ Button {
+ Task {
+ await viewModel.unassignFromMe(ticket)
+ }
+ } label: {
+ Label("Unassign Me", systemImage: "person.badge.minus")
+ }
+ .tint(.orange)
+ }
+ }
}
}
} header: {
@@ -142,6 +160,19 @@ struct HomeView: View {
} label: {
HomeBuildRow(build: build)
}
+ .swipeActions(edge: .leading, allowsFullSwipe: true) {
+ if swipeActionsEnabled, build.job.status.isCancellable {
+ Button {
+ Task {
+ await viewModel.cancelBuild(build)
+ }
+ }
+ label: {
+ Label("Cancel", systemImage: "xmark.circle")
+ }
+ .tint(.red)
+ }
+ }
}
}
} header: {
@@ -151,6 +182,32 @@ struct HomeView: View {
}
}
+ @ViewBuilder
+ private func ticketLeadingSwipeAction(
+ _ ticket: HomeAssignedTicket,
+ viewModel: HomeViewModel
+ ) -> some View {
+ if ticket.ticket.status.isOpen {
+ Button {
+ Task {
+ await viewModel.resolveTicket(ticket)
+ }
+ } label: {
+ Label("Resolve", systemImage: "checkmark.circle")
+ }
+ .tint(.green)
+ } else {
+ Button {
+ Task {
+ await viewModel.reopenTicket(ticket)
+ }
+ } label: {
+ Label("Reopen", systemImage: "arrow.uturn.backward")
+ }
+ .tint(.blue)
+ }
+ }
+
}
private struct HomeInboxToolbarIcon: View {
@@ -367,6 +424,7 @@ private struct HomeSectionActionHeader: View {
private struct HomeAssignedTicketsListView: View {
let viewModel: HomeViewModel
+ @AppStorage(AppStorageKeys.swipeActionsEnabled) private var swipeActionsEnabled = true
var body: some View {
List {
@@ -382,6 +440,35 @@ private struct HomeAssignedTicketsListView: View {
} label: {
HomeAssignedTicketRow(ticket: ticket)
}
+ .swipeActions(edge: .leading, allowsFullSwipe: true) {
+ if swipeActionsEnabled {
+ if ticket.ticket.status.isOpen {
+ Button {
+ Task { await viewModel.resolveTicket(ticket) }
+ } label: {
+ Label("Resolve", systemImage: "checkmark.circle")
+ }
+ .tint(.green)
+ } else {
+ Button {
+ Task { await viewModel.reopenTicket(ticket) }
+ } label: {
+ Label("Reopen", systemImage: "arrow.uturn.backward")
+ }
+ .tint(.blue)
+ }
+ }
+ }
+ .swipeActions(edge: .trailing, allowsFullSwipe: false) {
+ if swipeActionsEnabled {
+ Button {
+ Task { await viewModel.unassignFromMe(ticket) }
+ } label: {
+ Label("Unassign Me", systemImage: "person.badge.minus")
+ }
+ .tint(.orange)
+ }
+ }
}
if !viewModel.isLoadingAssignedTickets && viewModel.assignedTickets.isEmpty {