Matrix: TickTick-style Priority×deadline view + Progress Dots widget (KC-21)
Matrix (KC-21): the Eisenhower Matrix is now a computed view of tasks. Importance = Priority (High = top row), urgency = deadline proximity, so tasks auto-place into Q1–Q4. Added a persisted `matrixOverride` so a manual drag pins the task and syncs its Priority to that row (top → High, moving down demotes High → Medium) and never gets forced back; editing Priority, due date, or the editor clears the override to re-place live. New tasks get KisaniCal priority defaults (birthday/domain/annual/exam/subscription → High, workout → Medium). AddTaskSheet drops the manual quadrant picker for a Priority menu (pick Priority + Date only). Also includes in-progress Progress Dots widget work (day/week/month/custom event modes, App-Group anchor, recurrence-aware spans). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -13,27 +13,36 @@ struct TaskLiveActivity: Widget {
|
||||
Image(systemName: context.state.isComplete ? "checkmark.circle.fill" : "circle")
|
||||
.font(.system(size: 22))
|
||||
.foregroundColor(context.state.isComplete ? .green : accent)
|
||||
.frame(width: 24)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(context.attributes.title)
|
||||
.font(.system(size: 15, weight: .semibold))
|
||||
.font(.system(.body, design: .monospaced))
|
||||
.foregroundColor(.white)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.8)
|
||||
.strikethrough(context.state.isComplete)
|
||||
if let due = context.state.dueDate {
|
||||
Text(due, style: context.state.isComplete ? .date : .relative)
|
||||
.font(.system(size: 12, design: .monospaced))
|
||||
.font(.system(.caption, design: .monospaced))
|
||||
.foregroundColor(.white.opacity(0.6))
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
.layoutPriority(1)
|
||||
|
||||
if let due = context.state.dueDate, !context.state.isComplete {
|
||||
Text(due, style: .timer)
|
||||
.font(.system(size: 16, weight: .bold, design: .monospaced))
|
||||
.font(.system(.callout, design: .monospaced))
|
||||
.monospacedDigit()
|
||||
.foregroundColor(accent)
|
||||
.frame(maxWidth: 70)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.72)
|
||||
.frame(width: 92, alignment: .trailing)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.leading, 14)
|
||||
.padding(.trailing, 10)
|
||||
.padding(.vertical, 12)
|
||||
.activityBackgroundTint(WidgetTheme.background.opacity(0.9))
|
||||
.activitySystemActionForegroundColor(.white)
|
||||
@@ -47,14 +56,17 @@ struct TaskLiveActivity: Widget {
|
||||
DynamicIslandExpandedRegion(.trailing) {
|
||||
if let due = context.state.dueDate, !context.state.isComplete {
|
||||
Text(due, style: .timer)
|
||||
.font(.system(.body, design: .monospaced))
|
||||
.font(.system(.callout, design: .monospaced))
|
||||
.monospacedDigit()
|
||||
.foregroundColor(accent)
|
||||
.frame(maxWidth: 64)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.75)
|
||||
.frame(width: 86, alignment: .trailing)
|
||||
}
|
||||
}
|
||||
DynamicIslandExpandedRegion(.center) {
|
||||
Text(context.attributes.title)
|
||||
.font(.system(size: 14, weight: .semibold))
|
||||
.font(.system(.callout, design: .monospaced))
|
||||
.lineLimit(1)
|
||||
}
|
||||
} compactLeading: {
|
||||
@@ -63,8 +75,11 @@ struct TaskLiveActivity: Widget {
|
||||
if let due = context.state.dueDate, !context.state.isComplete {
|
||||
Text(due, style: .timer)
|
||||
.font(.system(.caption2, design: .monospaced))
|
||||
.monospacedDigit()
|
||||
.foregroundColor(accent)
|
||||
.frame(maxWidth: 44)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.7)
|
||||
.frame(width: 48, alignment: .trailing)
|
||||
}
|
||||
} minimal: {
|
||||
Image(systemName: "checklist").foregroundColor(accent)
|
||||
|
||||
Reference in New Issue
Block a user