Files
honeyDueKMP/TASK_SUMMARY_USAGE.md
Trey t 0130b2cdf1 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>
2025-11-15 11:18:14 -06:00

6.0 KiB

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:

{
  "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:

@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

@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:

@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

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:

// 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:

TaskSummaryCard(
    taskSummary = taskSummary,
    modifier = Modifier
        .padding(horizontal = 16.dp)
        .shadow(4.dp, RoundedCornerShape(12.dp))
)

iOS Implementation

For iOS (SwiftUI), create a similar component:

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:

Text("Overdue: ${taskSummary.overdue}")
Text("Pending: ${taskSummary.pending}")
Text("Completed: ${taskSummary.completed}")

New:

TaskSummaryCard(
    taskSummary = taskSummary,
    visibleCategories = listOf("overdue_tasks", "current_tasks", "done_tasks")
)

Or access categories programmatically:

val overdueCount = taskSummary.categories
    .find { it.name == "overdue_tasks" }?.count ?: 0