feat(11-02): render pre-populated tasks with muted visual distinction in calendar UI
- Add isPrePopulated parameter to CalendarTaskRow (default false, backward compat) - Wrap ListTile in Opacity(0.55) when isPrePopulated to indicate upcoming tasks - Render 'Demnächst' section in CalendarDayList with muted section header - Update _buildAnimatedTaskRow to accept and forward isPrePopulated flag - Update _CompletingTaskRow to accept isPrePopulated (always false during animation) - Update celebration check to include prePopulatedTasks.isEmpty condition - Update _completingTaskIds cleanup to also check prePopulatedTasks
This commit is contained in:
@@ -58,7 +58,8 @@ class _CalendarDayListState extends ConsumerState<CalendarDayList> {
|
|||||||
// Clean up animation IDs for tasks that are no longer in the data.
|
// Clean up animation IDs for tasks that are no longer in the data.
|
||||||
_completingTaskIds.removeWhere((id) =>
|
_completingTaskIds.removeWhere((id) =>
|
||||||
!state.overdueTasks.any((t) => t.task.id == id) &&
|
!state.overdueTasks.any((t) => t.task.id == id) &&
|
||||||
!state.dayTasks.any((t) => t.task.id == id));
|
!state.dayTasks.any((t) => t.task.id == id) &&
|
||||||
|
!state.prePopulatedTasks.any((t) => t.task.id == id));
|
||||||
|
|
||||||
return _buildContent(context, state, l10n, theme);
|
return _buildContent(context, state, l10n, theme);
|
||||||
},
|
},
|
||||||
@@ -82,8 +83,12 @@ class _CalendarDayListState extends ConsumerState<CalendarDayList> {
|
|||||||
|
|
||||||
// State (e): Celebration — today is selected and all tasks are done
|
// State (e): Celebration — today is selected and all tasks are done
|
||||||
// (totalTaskCount > 0 so at least some task exists somewhere, but today
|
// (totalTaskCount > 0 so at least some task exists somewhere, but today
|
||||||
// has none remaining after completion).
|
// has none remaining after completion, including no pre-populated tasks).
|
||||||
if (isToday && state.dayTasks.isEmpty && state.overdueTasks.isEmpty && state.totalTaskCount > 0) {
|
if (isToday &&
|
||||||
|
state.dayTasks.isEmpty &&
|
||||||
|
state.overdueTasks.isEmpty &&
|
||||||
|
state.prePopulatedTasks.isEmpty &&
|
||||||
|
state.totalTaskCount > 0) {
|
||||||
return _buildCelebration(l10n, theme);
|
return _buildCelebration(l10n, theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +274,24 @@ class _CalendarDayListState extends ConsumerState<CalendarDayList> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pre-populated tasks section (upcoming tasks within interval window).
|
||||||
|
if (state.prePopulatedTasks.isNotEmpty) {
|
||||||
|
items.add(_buildSectionHeader(
|
||||||
|
'Demnächst',
|
||||||
|
theme,
|
||||||
|
color: theme.colorScheme.onSurface.withValues(alpha: 0.5),
|
||||||
|
));
|
||||||
|
for (final tw in state.prePopulatedTasks) {
|
||||||
|
items.add(_buildAnimatedTaskRow(
|
||||||
|
tw,
|
||||||
|
isOverdue: false,
|
||||||
|
showRoomTag: showRoomTag,
|
||||||
|
canComplete: true,
|
||||||
|
isPrePopulated: true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ListView(children: items);
|
return ListView(children: items);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +314,7 @@ class _CalendarDayListState extends ConsumerState<CalendarDayList> {
|
|||||||
required bool isOverdue,
|
required bool isOverdue,
|
||||||
required bool showRoomTag,
|
required bool showRoomTag,
|
||||||
required bool canComplete,
|
required bool canComplete,
|
||||||
|
bool isPrePopulated = false,
|
||||||
}) {
|
}) {
|
||||||
final isCompleting = _completingTaskIds.contains(tw.task.id);
|
final isCompleting = _completingTaskIds.contains(tw.task.id);
|
||||||
|
|
||||||
@@ -300,6 +324,7 @@ class _CalendarDayListState extends ConsumerState<CalendarDayList> {
|
|||||||
taskWithRoom: tw,
|
taskWithRoom: tw,
|
||||||
isOverdue: isOverdue,
|
isOverdue: isOverdue,
|
||||||
showRoomTag: showRoomTag,
|
showRoomTag: showRoomTag,
|
||||||
|
isPrePopulated: false, // Completing tasks always show full styling.
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +334,7 @@ class _CalendarDayListState extends ConsumerState<CalendarDayList> {
|
|||||||
isOverdue: isOverdue,
|
isOverdue: isOverdue,
|
||||||
showRoomTag: showRoomTag,
|
showRoomTag: showRoomTag,
|
||||||
canComplete: canComplete,
|
canComplete: canComplete,
|
||||||
|
isPrePopulated: isPrePopulated,
|
||||||
onCompleted: () => _onTaskCompleted(tw.task.id),
|
onCompleted: () => _onTaskCompleted(tw.task.id),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -321,11 +347,13 @@ class _CompletingTaskRow extends StatefulWidget {
|
|||||||
required this.taskWithRoom,
|
required this.taskWithRoom,
|
||||||
required this.isOverdue,
|
required this.isOverdue,
|
||||||
required this.showRoomTag,
|
required this.showRoomTag,
|
||||||
|
this.isPrePopulated = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final TaskWithRoom taskWithRoom;
|
final TaskWithRoom taskWithRoom;
|
||||||
final bool isOverdue;
|
final bool isOverdue;
|
||||||
final bool showRoomTag;
|
final bool showRoomTag;
|
||||||
|
final bool isPrePopulated;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<_CompletingTaskRow> createState() => _CompletingTaskRowState();
|
State<_CompletingTaskRow> createState() => _CompletingTaskRowState();
|
||||||
@@ -372,6 +400,7 @@ class _CompletingTaskRowState extends State<_CompletingTaskRow>
|
|||||||
taskWithRoom: widget.taskWithRoom,
|
taskWithRoom: widget.taskWithRoom,
|
||||||
isOverdue: widget.isOverdue,
|
isOverdue: widget.isOverdue,
|
||||||
showRoomTag: widget.showRoomTag,
|
showRoomTag: widget.showRoomTag,
|
||||||
|
isPrePopulated: widget.isPrePopulated,
|
||||||
onCompleted: () {}, // Already completing — ignore repeat taps.
|
onCompleted: () {}, // Already completing — ignore repeat taps.
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ const _overdueColor = Color(0xFFE07A5F);
|
|||||||
///
|
///
|
||||||
/// When [isOverdue] is true the task name uses coral text to visually
|
/// When [isOverdue] is true the task name uses coral text to visually
|
||||||
/// distinguish overdue carry-over from today's regular tasks.
|
/// distinguish overdue carry-over from today's regular tasks.
|
||||||
|
///
|
||||||
|
/// When [isPrePopulated] is true the entire row is rendered at 0.55 opacity
|
||||||
|
/// to indicate it is not yet due (visible within interval window, but due
|
||||||
|
/// date is in the future).
|
||||||
class CalendarTaskRow extends StatelessWidget {
|
class CalendarTaskRow extends StatelessWidget {
|
||||||
const CalendarTaskRow({
|
const CalendarTaskRow({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -22,6 +26,7 @@ class CalendarTaskRow extends StatelessWidget {
|
|||||||
this.isOverdue = false,
|
this.isOverdue = false,
|
||||||
this.showRoomTag = true,
|
this.showRoomTag = true,
|
||||||
this.canComplete = true,
|
this.canComplete = true,
|
||||||
|
this.isPrePopulated = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final TaskWithRoom taskWithRoom;
|
final TaskWithRoom taskWithRoom;
|
||||||
@@ -38,12 +43,16 @@ class CalendarTaskRow extends StatelessWidget {
|
|||||||
/// When false, the checkbox is disabled (e.g. for future tasks).
|
/// When false, the checkbox is disabled (e.g. for future tasks).
|
||||||
final bool canComplete;
|
final bool canComplete;
|
||||||
|
|
||||||
|
/// When true, the row is rendered at 0.55 opacity to indicate an
|
||||||
|
/// upcoming (not-yet-due) pre-populated task within its interval window.
|
||||||
|
final bool isPrePopulated;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final task = taskWithRoom.task;
|
final task = taskWithRoom.task;
|
||||||
|
|
||||||
return ListTile(
|
final tile = ListTile(
|
||||||
onTap: () => context.go(
|
onTap: () => context.go(
|
||||||
'/rooms/${taskWithRoom.roomId}/tasks/${taskWithRoom.task.id}',
|
'/rooms/${taskWithRoom.roomId}/tasks/${taskWithRoom.task.id}',
|
||||||
),
|
),
|
||||||
@@ -79,5 +88,7 @@ class CalendarTaskRow extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return isPrePopulated ? Opacity(opacity: 0.55, child: tile) : tile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user