Added comprehensive usage documentation for dynamic task summary components and updated TaskApi to rely on backend's default threshold value. **Changes:** **New: TASK_SUMMARY_USAGE.md** - Complete Android usage guide for TaskSummaryCard component - Examples of basic usage, filtering categories, and customization - Documents all available categories and their metadata - Shows how to use dynamic task summary in different screens **New: iosApp/TASK_SUMMARY_USAGE_IOS.md** - Complete iOS usage guide for TaskSummaryCard SwiftUI component - Examples for ResidenceDetailView, ResidenceCard, and HomeScreen - Documents SF Symbol icon usage and color parsing - Integration examples and troubleshooting tips **New: TaskConstants.kt** - Created client-side constants file (currently unused) - Contains TASK_CURRENT_THRESHOLD_DAYS = 29 - Available for future use if client needs local threshold **Updated: TaskApi.kt** - Changed days parameter from `days: Int = 30` to `days: Int? = null` - Now only sends days parameter to backend if explicitly provided - Allows backend's default threshold (29 days) to be used - Applied to both getTasks() and getTasksByResidence() **Updated: ApiConfig.kt** - Minor configuration update **Benefits:** ✅ Comprehensive documentation for both platforms ✅ Apps now use backend's default threshold value ✅ Cleaner API calls without unnecessary parameters ✅ Client can still override threshold if needed ✅ Documentation includes troubleshooting and best practices 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
255 lines
7.1 KiB
Markdown
255 lines
7.1 KiB
Markdown
# Task Summary Card - iOS Usage Guide
|
|
|
|
## Overview
|
|
|
|
The `TaskSummaryCard` SwiftUI component displays task statistics dynamically based on backend data. All metadata (icons, colors, display names) comes from the API.
|
|
|
|
## Files Created
|
|
|
|
1. **`Components/TaskSummaryCard.swift`** - Main component
|
|
|
|
**Note:** The component uses the existing `Color(hex:)` initializer from `Design/DesignSystem.swift`, so no additional files are needed.
|
|
|
|
## Basic Usage
|
|
|
|
### Example 1: Show All Categories
|
|
|
|
In `ResidenceDetailView.swift` or `ResidencesListView.swift`:
|
|
|
|
```swift
|
|
import SwiftUI
|
|
import Shared
|
|
|
|
struct ResidenceDetailView: View {
|
|
let residence: ResidenceSummary
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(spacing: 16) {
|
|
// Residence info...
|
|
|
|
// Task summary with all categories
|
|
TaskSummaryCard(taskSummary: residence.taskSummary)
|
|
.padding(.horizontal)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Example 2: Show Only Specific Categories
|
|
|
|
For the main residence list, show only key categories:
|
|
|
|
```swift
|
|
struct ResidenceCard: View {
|
|
let residence: ResidenceSummary
|
|
|
|
var body: some View {
|
|
VStack(alignment: .leading, spacing: 12) {
|
|
Text(residence.name)
|
|
.font(.title2)
|
|
.fontWeight(.bold)
|
|
|
|
Text(residence.streetAddress)
|
|
.font(.subheadline)
|
|
.foregroundColor(.secondary)
|
|
|
|
// Only show overdue, current, and in progress
|
|
TaskSummaryCard(
|
|
taskSummary: residence.taskSummary,
|
|
visibleCategories: [
|
|
"overdue_tasks",
|
|
"current_tasks",
|
|
"in_progress_tasks"
|
|
]
|
|
)
|
|
}
|
|
.padding()
|
|
.background(Color(.systemBackground))
|
|
.cornerRadius(12)
|
|
.shadow(radius: 2)
|
|
}
|
|
}
|
|
```
|
|
|
|
### Example 3: In Home Screen
|
|
|
|
```swift
|
|
struct HomeScreenView: View {
|
|
@StateObject private var viewModel = ResidenceViewModel()
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(spacing: 20) {
|
|
ForEach(viewModel.residences, id: \.id) { residence in
|
|
VStack(alignment: .leading, spacing: 12) {
|
|
NavigationLink(destination: ResidenceDetailView(residence: residence)) {
|
|
VStack(alignment: .leading) {
|
|
Text(residence.name)
|
|
.font(.headline)
|
|
|
|
// Show task summary for quick overview
|
|
TaskSummaryCard(
|
|
taskSummary: residence.taskSummary,
|
|
visibleCategories: ["overdue_tasks", "current_tasks"]
|
|
)
|
|
}
|
|
}
|
|
}
|
|
.padding()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Available Categories
|
|
|
|
The backend provides these categories (can filter with `visibleCategories`):
|
|
|
|
1. **overdue_tasks** - Red (#FF3B30) - `exclamationmark.triangle`
|
|
2. **current_tasks** - Blue (#007AFF) - `calendar`
|
|
3. **in_progress_tasks** - Orange (#FF9500) - `play.circle`
|
|
4. **backlog_tasks** - Purple (#5856D6) - `tray`
|
|
5. **done_tasks** - Green (#34C759) - `checkmark.circle`
|
|
6. **archived_tasks** - Gray (#8E8E93) - `archivebox`
|
|
|
|
## Customization
|
|
|
|
### Custom Styling
|
|
|
|
```swift
|
|
TaskSummaryCard(taskSummary: taskSummary)
|
|
.padding()
|
|
.background(Color(.secondarySystemBackground))
|
|
.cornerRadius(16)
|
|
.shadow(color: Color.black.opacity(0.2), radius: 8, x: 0, y: 4)
|
|
```
|
|
|
|
### Filter Specific Categories
|
|
|
|
```swift
|
|
// Show only active tasks
|
|
TaskSummaryCard(
|
|
taskSummary: taskSummary,
|
|
visibleCategories: [
|
|
"overdue_tasks",
|
|
"current_tasks",
|
|
"in_progress_tasks",
|
|
"backlog_tasks"
|
|
]
|
|
)
|
|
```
|
|
|
|
### Access Individual Category Counts
|
|
|
|
If you need to access counts programmatically:
|
|
|
|
```swift
|
|
extension TaskSummary {
|
|
func categoryCount(for name: String) -> Int {
|
|
categories.first { $0.name == name }?.count ?? 0
|
|
}
|
|
}
|
|
|
|
// Usage:
|
|
let overdueCount = taskSummary.categoryCount(for: "overdue_tasks")
|
|
```
|
|
|
|
## Component Features
|
|
|
|
✅ **Dynamic Icons** - Uses SF Symbols from backend (e.g., `calendar`, `exclamationmark.triangle`)
|
|
✅ **Dynamic Colors** - Parses hex colors from backend
|
|
✅ **Flexible Filtering** - Show only categories you need
|
|
✅ **Live Preview** - Includes SwiftUI preview with mock data
|
|
✅ **Responsive** - Adapts to different screen sizes
|
|
✅ **Native Look** - Uses iOS design patterns and typography
|
|
|
|
## Preview
|
|
|
|
The component includes a preview for development. In Xcode:
|
|
|
|
1. Open `Components/TaskSummaryCard.swift`
|
|
2. Click "Resume" in the preview canvas
|
|
3. See both "all categories" and "filtered" versions
|
|
|
|
## Integration Example
|
|
|
|
Here's a complete example for ResidenceDetailView:
|
|
|
|
```swift
|
|
import SwiftUI
|
|
import Shared
|
|
|
|
struct ResidenceDetailView: View {
|
|
let residence: ResidenceSummary
|
|
@State private var showingManageUsers = false
|
|
@State private var showingTasks = false
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(alignment: .leading, spacing: 20) {
|
|
// Header
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
Text(residence.name)
|
|
.font(.title)
|
|
.fontWeight(.bold)
|
|
|
|
Text(residence.streetAddress)
|
|
.font(.subheadline)
|
|
.foregroundColor(.secondary)
|
|
}
|
|
.padding(.horizontal)
|
|
|
|
// Task Summary Card
|
|
TaskSummaryCard(
|
|
taskSummary: residence.taskSummary,
|
|
visibleCategories: [
|
|
"overdue_tasks",
|
|
"current_tasks",
|
|
"in_progress_tasks"
|
|
]
|
|
)
|
|
.padding(.horizontal)
|
|
.onTapGesture {
|
|
showingTasks = true
|
|
}
|
|
|
|
// Other residence details...
|
|
}
|
|
.padding(.vertical)
|
|
}
|
|
.navigationTitle("Residence Details")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.sheet(isPresented: $showingTasks) {
|
|
TasksView(residenceId: residence.id)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Benefits
|
|
|
|
✅ **Backend-Driven** - All icons, colors, names from API
|
|
✅ **Single Source of Truth** - Change in `task/constants.py` updates everywhere
|
|
✅ **Type-Safe** - Full Swift type safety with Shared models
|
|
✅ **Reusable** - Use in any view that has TaskSummary
|
|
✅ **Consistent** - Matches Android implementation
|
|
✅ **Maintainable** - No hardcoded values
|
|
|
|
## Troubleshooting
|
|
|
|
### Colors not showing correctly
|
|
Make sure `Extensions/Color+Hex.swift` is included in your target.
|
|
|
|
### Icons not appearing
|
|
The component uses SF Symbols. Ensure the icon names from backend are valid SF Symbol names.
|
|
|
|
### Type errors
|
|
Make sure you're importing `Shared` module which contains the TaskSummary models.
|
|
|
|
### Preview not working
|
|
The preview uses mock data. If you get compiler errors, make sure all model types are properly imported.
|