Add documentation and remove hardcoded task threshold from API calls
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>
This commit is contained in:
259
TASK_SUMMARY_USAGE.md
Normal file
259
TASK_SUMMARY_USAGE.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# Task Summary Component Usage
|
||||
|
||||
## Overview
|
||||
|
||||
The `TaskSummaryCard` component displays task statistics dynamically based on backend data. The backend provides all metadata (icons, colors, display names), making the UI fully data-driven.
|
||||
|
||||
## Backend Structure
|
||||
|
||||
The backend returns task summaries in this format:
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 25,
|
||||
"categories": [
|
||||
{
|
||||
"name": "overdue_tasks",
|
||||
"display_name": "Overdue",
|
||||
"icons": {
|
||||
"ios": "exclamationmark.triangle",
|
||||
"android": "Warning",
|
||||
"web": "exclamation-triangle"
|
||||
},
|
||||
"color": "#FF3B30",
|
||||
"count": 3
|
||||
},
|
||||
{
|
||||
"name": "current_tasks",
|
||||
"display_name": "Current",
|
||||
"icons": {
|
||||
"ios": "calendar",
|
||||
"android": "CalendarToday",
|
||||
"web": "calendar"
|
||||
},
|
||||
"color": "#007AFF",
|
||||
"count": 8
|
||||
},
|
||||
// ... more categories
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Model Classes
|
||||
|
||||
The app models are defined in `Residence.kt`:
|
||||
|
||||
```kotlin
|
||||
@Serializable
|
||||
data class TaskCategoryIcon(
|
||||
val ios: String,
|
||||
val android: String,
|
||||
val web: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TaskCategory(
|
||||
val name: String,
|
||||
@SerialName("display_name") val displayName: String,
|
||||
val icons: TaskCategoryIcon,
|
||||
val color: String,
|
||||
val count: Int
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TaskSummary(
|
||||
val total: Int,
|
||||
val categories: List<TaskCategory>
|
||||
)
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: Show All Categories
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun ResidenceDetailScreen(residence: ResidenceWithTasks) {
|
||||
Column {
|
||||
// Other residence details...
|
||||
|
||||
TaskSummaryCard(
|
||||
taskSummary = residence.taskSummary
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Show Only Specific Categories
|
||||
|
||||
For the main residence view, you might want to show only certain categories:
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun ResidenceCard(residence: ResidenceSummary) {
|
||||
Card {
|
||||
Column {
|
||||
Text(text = residence.name)
|
||||
|
||||
// Only show overdue, current, and in_progress
|
||||
TaskSummaryCard(
|
||||
taskSummary = residence.taskSummary,
|
||||
visibleCategories = listOf(
|
||||
"overdue_tasks",
|
||||
"current_tasks",
|
||||
"in_progress_tasks"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Custom Styling
|
||||
|
||||
```kotlin
|
||||
TaskSummaryCard(
|
||||
taskSummary = residence.taskSummary,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
visibleCategories = listOf("overdue_tasks", "current_tasks")
|
||||
)
|
||||
```
|
||||
|
||||
## Available Categories
|
||||
|
||||
The backend defines these categories (in `task/constants.py`):
|
||||
|
||||
1. **overdue_tasks** - Red (#FF3B30) - Tasks past their due date
|
||||
2. **current_tasks** - Blue (#007AFF) - Tasks due within threshold (29 days)
|
||||
3. **in_progress_tasks** - Orange (#FF9500) - Tasks being worked on
|
||||
4. **backlog_tasks** - Purple (#5856D6) - Tasks beyond current threshold
|
||||
5. **done_tasks** - Green (#34C759) - Completed tasks
|
||||
6. **archived_tasks** - Gray (#8E8E93) - Archived tasks
|
||||
|
||||
## Customization
|
||||
|
||||
### Filtering Categories
|
||||
|
||||
Use the `visibleCategories` parameter to control which categories appear:
|
||||
|
||||
```kotlin
|
||||
// Show only active task categories
|
||||
TaskSummaryCard(
|
||||
taskSummary = taskSummary,
|
||||
visibleCategories = listOf(
|
||||
"overdue_tasks",
|
||||
"current_tasks",
|
||||
"in_progress_tasks",
|
||||
"backlog_tasks"
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
### Styling
|
||||
|
||||
The component uses Material Design 3 theming. Customize via modifier:
|
||||
|
||||
```kotlin
|
||||
TaskSummaryCard(
|
||||
taskSummary = taskSummary,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.shadow(4.dp, RoundedCornerShape(12.dp))
|
||||
)
|
||||
```
|
||||
|
||||
## iOS Implementation
|
||||
|
||||
For iOS (SwiftUI), create a similar component:
|
||||
|
||||
```swift
|
||||
struct TaskSummaryCard: View {
|
||||
let taskSummary: TaskSummary
|
||||
let visibleCategories: [String]?
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text("Tasks")
|
||||
.font(.headline)
|
||||
|
||||
ForEach(filteredCategories, id: \.name) { category in
|
||||
TaskCategoryRow(category: category)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color(.systemBackground))
|
||||
.cornerRadius(12)
|
||||
.shadow(radius: 2)
|
||||
}
|
||||
|
||||
var filteredCategories: [TaskCategory] {
|
||||
if let visible = visibleCategories {
|
||||
return taskSummary.categories.filter { visible.contains($0.name) }
|
||||
}
|
||||
return taskSummary.categories
|
||||
}
|
||||
}
|
||||
|
||||
struct TaskCategoryRow: View {
|
||||
let category: TaskCategory
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
// Use SF Symbol from category.icons.ios
|
||||
Image(systemName: category.icons.ios)
|
||||
.foregroundColor(Color(hex: category.color))
|
||||
|
||||
Text(category.displayName)
|
||||
.font(.body)
|
||||
|
||||
Spacer()
|
||||
|
||||
Text("\(category.count)")
|
||||
.font(.headline)
|
||||
.foregroundColor(.white)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 4)
|
||||
.background(Color(hex: category.color))
|
||||
.cornerRadius(12)
|
||||
}
|
||||
.padding(12)
|
||||
.background(Color(hex: category.color).opacity(0.1))
|
||||
.cornerRadius(8)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **Data-Driven**: All icons, colors, and names come from backend
|
||||
✅ **Single Source of Truth**: Change values in `task/constants.py` to update everywhere
|
||||
✅ **Flexible**: Easy to show different categories in different screens
|
||||
✅ **Consistent**: Same categorization logic across all platforms
|
||||
✅ **Maintainable**: No hardcoded UI values in app code
|
||||
|
||||
## Migration from Old TaskSummary
|
||||
|
||||
If you have existing code using the old TaskSummary structure:
|
||||
|
||||
**Old:**
|
||||
```kotlin
|
||||
Text("Overdue: ${taskSummary.overdue}")
|
||||
Text("Pending: ${taskSummary.pending}")
|
||||
Text("Completed: ${taskSummary.completed}")
|
||||
```
|
||||
|
||||
**New:**
|
||||
```kotlin
|
||||
TaskSummaryCard(
|
||||
taskSummary = taskSummary,
|
||||
visibleCategories = listOf("overdue_tasks", "current_tasks", "done_tasks")
|
||||
)
|
||||
```
|
||||
|
||||
Or access categories programmatically:
|
||||
```kotlin
|
||||
val overdueCount = taskSummary.categories
|
||||
.find { it.name == "overdue_tasks" }?.count ?: 0
|
||||
```
|
||||
Reference in New Issue
Block a user