diff --git a/js/content.js b/js/content.js
index 765eb2e..78c20e4 100644
--- a/js/content.js
+++ b/js/content.js
@@ -928,6 +928,7 @@ function applyOptionsChanges(changes) {
case "todo_timeframe":
// case "todo_overdues":
case "todo_hide_feedback":
+ case "todo_hide_read":
case "todo_full_height":
case "todo_ignore_card_colors":
case "todo_remove_icons":
@@ -3285,7 +3286,18 @@ async function createTodoSections(location) {
return cid === String(betterTodoProgressFilter);
});
- announcements = displayData.filter(item => item.plannable_type == "announcement");
+ // Announcements: dismissed (marked-complete) ones are always
+ // hidden, and already-read ones are hidden unless the user turned
+ // "Hide read announcements" off. This mirrors how native Canvas
+ // clears announcements from the to-do once seen; without it the list
+ // accumulated every announcement in the lookback window (reporters
+ // saw 200+ "Seen" entries from a single year).
+ announcements = displayData.filter(item => {
+ if (item.plannable_type != "announcement") return false;
+ if (item.planner_override?.marked_complete === true) return false;
+ if (options.todo_hide_read !== false && item.plannable.read_state == "read") return false;
+ return true;
+ });
// Pinned items (locally forced incomplete, e.g. a submitted assignment
// the user sent back to Tasks) always count as due; everything else is
// due only when neither submitted nor marked complete.
@@ -3824,15 +3836,30 @@ function populateAnnouncements() {
`}