- Remove AppColors struct, migrate to iOS system colors throughout - Redesign ContractorFormSheet to use native SwiftUI Form components - Add color-coded icons to contractor form sections - Improve dark mode contrast for task cards - Add background colors to document detail fields - Fix text alignment issues in ContractorDetailView - Make task completion lists expandable/collapsible by default - Clear app badge on launch and when app becomes active - Update button styling with proper gradients and shadows - Improve form field focus states and accessibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
121 lines
4.2 KiB
Swift
121 lines
4.2 KiB
Swift
import SwiftUI
|
|
import ComposeApp
|
|
|
|
struct CompletionCardView: View {
|
|
let completion: TaskCompletion
|
|
@State private var showPhotoSheet = false
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
HStack {
|
|
Text(formatDate(completion.completionDate))
|
|
.font(.caption)
|
|
.fontWeight(.semibold)
|
|
.foregroundColor(.blue)
|
|
|
|
Spacer()
|
|
|
|
if let rating = completion.rating {
|
|
HStack(spacing: 2) {
|
|
Image(systemName: "star.fill")
|
|
.font(.caption2)
|
|
Text("\(rating)")
|
|
.font(.caption)
|
|
.fontWeight(.bold)
|
|
}
|
|
.foregroundColor(.orange)
|
|
.padding(.horizontal, 8)
|
|
.padding(.vertical, 4)
|
|
.background(Color.orange.opacity(0.1))
|
|
.cornerRadius(6)
|
|
}
|
|
}
|
|
|
|
// Display contractor or manual entry
|
|
if let contractorDetails = completion.contractorDetails {
|
|
HStack(alignment: .top, spacing: 6) {
|
|
Image(systemName: "wrench.and.screwdriver")
|
|
.font(.caption2)
|
|
.foregroundColor(.blue)
|
|
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text("By: \(contractorDetails.name)")
|
|
.font(.caption2)
|
|
.fontWeight(.medium)
|
|
.foregroundColor(.primary)
|
|
|
|
if let company = contractorDetails.company {
|
|
Text(company)
|
|
.font(.caption2)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
}
|
|
}
|
|
} else if let completedBy = completion.completedByName {
|
|
Text("By: \(completedBy)")
|
|
.font(.caption2)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
|
|
if let cost = completion.actualCost {
|
|
Text("Cost: $\(cost)")
|
|
.font(.caption2)
|
|
.foregroundColor(.green)
|
|
.fontWeight(.medium)
|
|
}
|
|
|
|
if let notes = completion.notes {
|
|
Text(notes)
|
|
.font(.caption2)
|
|
.foregroundColor(.secondary)
|
|
.lineLimit(2)
|
|
}
|
|
|
|
// Show button to view photos if images exist
|
|
if let images = completion.images, !images.isEmpty {
|
|
Button(action: {
|
|
showPhotoSheet = true
|
|
}) {
|
|
HStack {
|
|
Image(systemName: "photo.on.rectangle")
|
|
.font(.caption)
|
|
Text("View Photos (\(images.count))")
|
|
.font(.caption)
|
|
.fontWeight(.semibold)
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
.padding(.vertical, 8)
|
|
.background(Color.blue.opacity(0.1))
|
|
.foregroundColor(.blue)
|
|
.cornerRadius(8)
|
|
}
|
|
}
|
|
}
|
|
.padding(12)
|
|
.background(Color(.systemGray6))
|
|
.cornerRadius(8)
|
|
.sheet(isPresented: $showPhotoSheet) {
|
|
if let images = completion.images {
|
|
PhotoViewerSheet(images: images)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func formatDate(_ dateString: String) -> String {
|
|
let formatter = DateFormatter()
|
|
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
|
|
if let date = formatter.date(from: dateString) {
|
|
formatter.dateStyle = .medium
|
|
formatter.timeStyle = .none
|
|
return formatter.string(from: date)
|
|
}
|
|
// Try without time
|
|
formatter.dateFormat = "yyyy-MM-dd"
|
|
if let date = formatter.date(from: dateString) {
|
|
formatter.dateStyle = .medium
|
|
return formatter.string(from: date)
|
|
}
|
|
return dateString
|
|
}
|
|
}
|