wip
This commit is contained in:
267
iosApp/iosApp/Task/AllTasksView.swift
Normal file
267
iosApp/iosApp/Task/AllTasksView.swift
Normal file
@@ -0,0 +1,267 @@
|
||||
import SwiftUI
|
||||
import ComposeApp
|
||||
|
||||
struct AllTasksView: View {
|
||||
@StateObject private var taskViewModel = TaskViewModel()
|
||||
@State private var tasksResponse: AllTasksResponse?
|
||||
@State private var isLoadingTasks = false
|
||||
@State private var tasksError: String?
|
||||
@State private var showAddTask = false
|
||||
@State private var showEditTask = false
|
||||
@State private var selectedTaskForEdit: TaskDetail?
|
||||
@State private var showInProgressTasks = false
|
||||
@State private var showDoneTasks = false
|
||||
@State private var showCompleteTask = false
|
||||
@State private var selectedTaskForComplete: TaskDetail?
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(.systemGroupedBackground)
|
||||
.ignoresSafeArea()
|
||||
|
||||
if isLoadingTasks {
|
||||
ProgressView()
|
||||
} else if let error = tasksError {
|
||||
ErrorView(message: error) {
|
||||
loadAllTasks()
|
||||
}
|
||||
} else if let tasksResponse = tasksResponse {
|
||||
ScrollView {
|
||||
VStack(spacing: 16) {
|
||||
// Header Card
|
||||
VStack(spacing: 12) {
|
||||
Image(systemName: "checklist")
|
||||
.font(.system(size: 48))
|
||||
.foregroundStyle(.blue.gradient)
|
||||
|
||||
Text("All Tasks")
|
||||
.font(.title)
|
||||
.fontWeight(.bold)
|
||||
|
||||
Text("Tasks across all your properties")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.background(Color(.systemBackground))
|
||||
.cornerRadius(12)
|
||||
.shadow(color: Color.black.opacity(0.05), radius: 5, x: 0, y: 2)
|
||||
.padding(.horizontal)
|
||||
.padding(.top)
|
||||
|
||||
// Tasks Section
|
||||
AllTasksSectionView(
|
||||
tasksResponse: tasksResponse,
|
||||
showInProgressTasks: $showInProgressTasks,
|
||||
showDoneTasks: $showDoneTasks,
|
||||
onEditTask: { task in
|
||||
selectedTaskForEdit = task
|
||||
showEditTask = true
|
||||
},
|
||||
onCancelTask: { task in
|
||||
taskViewModel.cancelTask(id: task.id) { _ in
|
||||
loadAllTasks()
|
||||
}
|
||||
},
|
||||
onUncancelTask: { task in
|
||||
taskViewModel.uncancelTask(id: task.id) { _ in
|
||||
loadAllTasks()
|
||||
}
|
||||
},
|
||||
onMarkInProgress: { task in
|
||||
taskViewModel.markInProgress(id: task.id) { success in
|
||||
if success {
|
||||
loadAllTasks()
|
||||
}
|
||||
}
|
||||
},
|
||||
onCompleteTask: { task in
|
||||
selectedTaskForComplete = task
|
||||
showCompleteTask = true
|
||||
}
|
||||
)
|
||||
.padding(.horizontal)
|
||||
}
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("All Tasks")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.sheet(isPresented: $showEditTask) {
|
||||
if let task = selectedTaskForEdit {
|
||||
EditTaskView(task: task, isPresented: $showEditTask)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showCompleteTask) {
|
||||
if let task = selectedTaskForComplete {
|
||||
CompleteTaskView(task: task, isPresented: $showCompleteTask) {
|
||||
loadAllTasks()
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: showEditTask) { isShowing in
|
||||
if !isShowing {
|
||||
loadAllTasks()
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
loadAllTasks()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadAllTasks() {
|
||||
guard let token = TokenStorage.shared.getToken() else { return }
|
||||
|
||||
isLoadingTasks = true
|
||||
tasksError = nil
|
||||
|
||||
let taskApi = TaskApi(client: ApiClient_iosKt.createHttpClient())
|
||||
taskApi.getTasks(token: token, days: 30) { result, error in
|
||||
if let successResult = result as? ApiResultSuccess<AllTasksResponse> {
|
||||
self.tasksResponse = successResult.data
|
||||
self.isLoadingTasks = false
|
||||
} else if let errorResult = result as? ApiResultError {
|
||||
self.tasksError = errorResult.message
|
||||
self.isLoadingTasks = false
|
||||
} else if let error = error {
|
||||
self.tasksError = error.localizedDescription
|
||||
self.isLoadingTasks = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AllTasksSectionView: View {
|
||||
let tasksResponse: AllTasksResponse
|
||||
@Binding var showInProgressTasks: Bool
|
||||
@Binding var showDoneTasks: Bool
|
||||
let onEditTask: (TaskDetail) -> Void
|
||||
let onCancelTask: (TaskDetail) -> Void
|
||||
let onUncancelTask: (TaskDetail) -> Void
|
||||
let onMarkInProgress: (TaskDetail) -> Void
|
||||
let onCompleteTask: (TaskDetail) -> Void
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
// Task summary pills
|
||||
HStack(spacing: 8) {
|
||||
TaskPill(
|
||||
count: Int32(tasksResponse.summary.upcoming),
|
||||
label: "Upcoming",
|
||||
color: .blue
|
||||
)
|
||||
|
||||
TaskPill(
|
||||
count: Int32(tasksResponse.summary.inProgress),
|
||||
label: "In Progress",
|
||||
color: .orange
|
||||
)
|
||||
|
||||
TaskPill(
|
||||
count: Int32(tasksResponse.summary.done),
|
||||
label: "Done",
|
||||
color: .green
|
||||
)
|
||||
}
|
||||
.padding(.bottom, 4)
|
||||
|
||||
// Upcoming tasks
|
||||
if !tasksResponse.upcomingTasks.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Label("Upcoming (\(tasksResponse.upcomingTasks.count))", systemImage: "calendar")
|
||||
.font(.headline)
|
||||
.foregroundColor(.blue)
|
||||
|
||||
ForEach(tasksResponse.upcomingTasks, id: \.id) { task in
|
||||
TaskCard(
|
||||
task: task,
|
||||
onEdit: { onEditTask(task) },
|
||||
onCancel: { onCancelTask(task) },
|
||||
onUncancel: { onUncancelTask(task) },
|
||||
onMarkInProgress: { onMarkInProgress(task) },
|
||||
onComplete: { onCompleteTask(task) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In Progress section (collapsible)
|
||||
if !tasksResponse.inProgressTasks.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack {
|
||||
Label("In Progress (\(tasksResponse.inProgressTasks.count))", systemImage: "play.circle")
|
||||
.font(.headline)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: showInProgressTasks ? "chevron.up" : "chevron.down")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
showInProgressTasks.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
if showInProgressTasks {
|
||||
ForEach(tasksResponse.inProgressTasks, id: \.id) { task in
|
||||
TaskCard(
|
||||
task: task,
|
||||
onEdit: { onEditTask(task) },
|
||||
onCancel: { onCancelTask(task) },
|
||||
onUncancel: { onUncancelTask(task) },
|
||||
onMarkInProgress: nil,
|
||||
onComplete: { onCompleteTask(task) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Done section (collapsible)
|
||||
if !tasksResponse.doneTasks.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack {
|
||||
Label("Done (\(tasksResponse.doneTasks.count))", systemImage: "checkmark.circle")
|
||||
.font(.headline)
|
||||
.foregroundColor(.green)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: showDoneTasks ? "chevron.up" : "chevron.down")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
showDoneTasks.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
if showDoneTasks {
|
||||
ForEach(tasksResponse.doneTasks, id: \.id) { task in
|
||||
TaskCard(
|
||||
task: task,
|
||||
onEdit: { onEditTask(task) },
|
||||
onCancel: nil,
|
||||
onUncancel: nil,
|
||||
onMarkInProgress: nil,
|
||||
onComplete: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationView {
|
||||
AllTasksView()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user