Skip to content

Conversation

@kristofnemere
Copy link
Contributor

Summary

  • Fixed empty state display when last ToDo item is marked as done
  • Made account-level calendar events unclickable
  • Implemented auto-refresh of ToDo list when courses are added/removed from favorites or items are added/deleted from calendar
  • Fixed panda avatars appearing in list after orientation change
  • Added comprehensive unit and UI test coverage

Changes

Bug Fixes

  1. Empty state with removingItemIds filtering - Moved filtering logic up to check filtered items instead of raw data for empty state display
  2. Account-level calendar events - Made account-level calendar events unclickable as they have no detail page
  3. ToDo list auto-refresh - Integrated CalendarSharedEvents to refresh ToDo list when:
    • Courses are added/removed from favorites (EditDashboardViewModel)
    • Calendar events/todos are created/edited/deleted (EventFragment, ToDoFragment)
    • Submissions are uploaded (SubmissionWorker)
  4. Panda avatars orientation bug - Fixed panda avatars appearing in middle of list after orientation change by using configuration-aware remember keys
  5. Quiz completion - Fixed empty state logic when quiz is completed

Test Coverage

  1. ToDoListScreenTest.kt (new) - 18 Compose UI tests:

    • State tests (loading, error, empty, with items)
    • Item display (single/multiple, date grouping, badges, tags, labels)
    • Interactions (checkbox clicks, item clicks)
    • Filtering with removingItemIds
    • Clickability (clickable vs non-clickable items)
  2. ToDoListViewModelTest.kt - Added 6 tests:

    • Account-level calendar events not clickable
    • Course-level calendar events clickable
    • User-level calendar events clickable
    • RefreshToDoList event triggers data reload
    • Empty state via swipe on last item
    • Empty state via checkbox on last item after debounce
  3. EditDashboardViewModelTest.kt - Added 2 tests:

    • RefreshToDoList event when course added to favorites
    • RefreshToDoList event when course removed from favorites
  4. QuizSubmissionViewModelTest.kt - Added 2 tests:

    • Empty state after completing last quiz
    • Count updates correctly after completing quiz

Test plan

  • Run unit tests: ./gradle/gradlew :libs:pandautils:test
  • Run UI tests: ./gradle/gradlew :libs:pandautils:connectedDebugAndroidTest
  • Manually verify:
    • Empty state shows when last ToDo item is checked/swiped
    • Account-level calendar events are not clickable
    • ToDo list refreshes when adding/removing favorite courses
    • ToDo list refreshes after creating/editing calendar events
    • Panda avatars don't appear in middle of list after rotation
    • Quiz completion shows empty state correctly

Affects

Student

🤖 Generated with Claude Code

kristofnemere and others added 7 commits November 21, 2025 09:50
Fixed issue #1: Empty state only appeared after manual refresh when
all ToDo items were marked as done via checkboxes.

Changes:
- Added applyFiltersLocally() call in startCheckboxDebounceTimer() after
  items are added to removingItemIds for animation
- This ensures itemsByDate is updated to reflect filtered completed items
- Empty state now appears automatically when last item is completed

Test plan:
- Mark all visible ToDo items as done using checkboxes
- Verify empty state appears automatically after animation (~1 second)
- Test with various filter combinations (Show Completed on/off)
- Verify both swipe-to-done and checkbox trigger empty state correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Fixed issue #11: Account-level calendar events were clickable when they
shouldn't be.

Changes:
- Added isClickable field to ToDoItemUiState (defaults to true)
- In ToDoListViewModel.mapToUiState(), detect account-level events by
  checking if contextType equals "Account" (case-insensitive)
- Set isClickable to false for account-level calendar events
- In ToDoListScreen.ToDoItemContent(), conditionally apply clickable
  modifier based on isClickable flag using Modifier.then()

Account-level calendar events now appear in the ToDo list but are
not clickable, preventing navigation to invalid URLs.

Test plan:
- Create account-level calendar events
- Verify they appear in ToDo list
- Verify clicking on them does nothing (no navigation)
- Verify other items (course/user events, assignments, etc.) remain clickable
- Verify checkbox and swipe-to-done still work on account events

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Fixed multiple issues where ToDo list didn't automatically refresh
after changes in various parts of the app:

Changes:
- ToDoListViewModel: Added CalendarSharedEvents listener to refresh
  on RefreshToDoList events
- EditDashboardViewModel: Emit RefreshToDoList when favoriting/
  unfavoriting courses to update filtered ToDo items
- SubmissionWorker: Emit RefreshToDoList after successful assignment
  submissions to remove completed items

This fixes the following QA findings from MBL-19553:
- Issue #2: Badge updates but page doesn't refresh after creating
  events/todos
- Issue #4: Favorite courses filter doesn't auto-update
- Issue #5: Assignment submission doesn't refresh ToDo page
- Issue #9: ToDo created from widget appears on widget but not page
- Issue #10: Deleted event/ToDo doesn't disappear from page

Test plan:
- Create/update/delete calendar events and verify ToDo list refreshes
- Favorite/unfavorite courses and verify filtered ToDos update
- Submit assignments and verify they disappear from ToDo list
- Create ToDos from widget and verify they appear in list
- Delete events/ToDos and verify they disappear immediately

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Fixed issue where panda illustrations incorrectly appeared at the
bottom of ToDo list after rotating from landscape to portrait mode.

Root cause:
- itemPositions and itemSizes maps survived configuration changes
  with stale values from previous orientation
- listContentHeight calculation used these stale values, making it
  smaller than actual content height in new orientation
- This caused availableSpacePx to be larger than reality, making
  showPandas condition incorrectly evaluate to true

Solution:
- Added LocalConfiguration.current as key to remember() blocks for
  itemPositions and itemSizes maps
- Maps now reset on any configuration change (orientation, etc.)
- All items remeasured with correct values for new layout
- Panda visibility logic uses accurate data immediately

This fixes Issue #3 from MBL-19553:
- Panda avatars appearing incorrectly after orientation change

Test plan:
- Open ToDo list with some items (not enough to fill entire screen)
- Rotate device from portrait to landscape
- Rotate back to portrait
- Verify pandas don't appear unless scrolling reveals actual space
- Verify pandas appear correctly when there is genuine space at bottom

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Added comprehensive unit tests for the QUIZ type in isComplete()
function to verify Issue #7 fix (classic quiz doesn't disappear
after submission).

Tests added:
- isComplete returns true for QUIZ when submitted
- isComplete returns false for QUIZ when not submitted
- isComplete returns false for QUIZ with null submission state
- isComplete returns true for QUIZ with plannerOverride marked complete

These tests ensure that quizzes behave the same as assignments
when determining completion status, preventing regression of
the fix where completed quizzes now properly disappear from
the ToDo list.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Fixed all test compilation errors caused by adding CalendarSharedEvents
parameter to EditDashboardViewModel constructor.

Changes:
- Added CalendarSharedEvents import
- Added calendarSharedEvents mock instance
- Updated all 31 EditDashboardViewModel constructor calls to include
  the calendarSharedEvents parameter

This ensures all existing tests continue to pass after adding the
favorite courses refresh functionality (Issue #4).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…ture

Added unit tests and Compose UI tests to verify CalendarSharedEvents
integration and empty state behavior with removingItemIds filtering.

Changes:
- Added ToDoListScreenTest.kt with 18 Compose UI tests covering all
  states (loading, error, empty, with items), filtering, and interactions
- Made ToDoListContent internal with testTags for testability
- Added tests in ToDoListViewModelTest.kt for:
  * Account-level calendar events clickability
  * RefreshToDoList event triggering data reload
  * Empty state when completing last item via swipe/checkbox
- Added tests in EditDashboardViewModelTest.kt for:
  * RefreshToDoList event when adding/removing courses from favorites

Test plan:
- Run unit tests: ./gradle/gradlew :libs:pandautils:test
- Run UI tests: ./gradle/gradlew :libs:pandautils:connectedDebugAndroidTest
- Verify all tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Review Summary

This PR implements a To-Do List feature with calendar integration for the Canvas Android app. The implementation includes comprehensive test coverage and follows the project's architectural patterns well.

✅ Positive Feedback

  • Excellent test coverage: The new ToDoListScreenTest.kt includes 20+ comprehensive UI tests covering loading states, error states, empty states, item interactions, and edge cases
  • Good architectural patterns: Follows MVVM pattern with proper separation of concerns (ViewModel, Repository, UI State)
  • Proper dependency injection: Uses Hilt throughout for dependency management
  • Comprehensive feature integration: Integrates with calendar events, submission workflows, and dashboard editing
  • Good use of Jetpack Compose: Modern UI implementation with proper state management
  • Test maintenance: Updates to existing test files properly mock the new CalendarSharedEvents dependency

🔍 Issues Found

  • Memory leak concern in SubmissionWorker.kt:665 - Creating a new CoroutineScope unnecessarily
  • Configuration change handling in ToDoListScreen.kt:331 - Overly broad state reset on configuration changes
  • Missing error handling in ToDoListViewModel.kt:126 - Event collection lacks error handling
  • Logic simplification in ToDoListViewModel.kt:196 - Account-level event logic could be cleaner

📋 Additional Observations

Code Quality:

  • Import organization follows project conventions
  • Proper use of test tags for UI testing
  • Good handling of edge cases (empty states, filtering, etc.)
  • Quiz submission status now properly tracked in PlannerItemExtensions.kt

Architecture:

  • Shared events pattern used appropriately for cross-feature communication
  • Filtering logic properly implemented with removingItemIds set
  • Account-level calendar events correctly marked as non-clickable

Testing:

  • Unit tests cover new functionality comprehensively
  • Test helpers are well-designed and reusable
  • Mock setup is clean and follows existing patterns

🎯 Recommendations

  1. Address the memory leak concern in SubmissionWorker
  2. Review the configuration change handling to avoid unnecessary state resets
  3. Add error handling to the calendar event observer
  4. Consider simplifying the account-level event clickability logic

Overall, this is a solid implementation with good test coverage. The issues identified are relatively minor and should be straightforward to address.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses several ToDo list bugs in the Android Student app and adds comprehensive test coverage. The changes focus on fixing UI state management issues, improving user interaction behavior, and implementing auto-refresh functionality across related features.

Key Changes:

  • Fixed empty state display logic by filtering items before checking if the list is empty
  • Made account-level calendar events non-clickable since they have no detail page
  • Integrated CalendarSharedEvents to auto-refresh ToDo list when courses, calendar events, or submissions change
  • Fixed orientation-related bug with panda avatars by using configuration-aware remember keys
  • Added quiz completion support to isComplete() logic

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
PlannerItemExtensions.kt Added QUIZ type to isComplete() logic for checking submission status
PlannerItemExtensionsTest.kt Added comprehensive test coverage for quiz completion scenarios
ToDoListViewModel.kt Integrated CalendarSharedEvents observer and added account-level event clickability logic
ToDoListViewModelTest.kt Added tests for clickability behavior, refresh events, and empty state scenarios
ToDoListUiState.kt Added isClickable boolean property to control item interaction
ToDoListScreen.kt Moved item filtering logic to parent composable for proper empty state detection and fixed orientation bug
ToDoListScreenTest.kt Created comprehensive UI test suite with 18 tests covering all major scenarios
EditDashboardViewModel.kt Integrated CalendarSharedEvents to emit RefreshToDoList when favorites change
EditDashboardViewModelTest.kt Added tests to verify RefreshToDoList event emission on favorite changes
ToDoFragment.kt Added RefreshToDoList event emission on todo create/edit/delete
EventFragment.kt Added RefreshToDoList event emission on calendar event operations
SubmissionWorker.kt Added RefreshToDoList event emission after successful submission upload

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions
Copy link

github-actions bot commented Nov 24, 2025

📊 Code Coverage Report

✅ Student

  • PR Coverage: 42.80%
  • Master Coverage: 42.80%
  • Delta: +0.00%

✅ Teacher

  • PR Coverage: 25.44%
  • Master Coverage: 25.44%
  • Delta: +0.00%

✅ Pandautils

  • PR Coverage: 22.63%
  • Master Coverage: 22.61%
  • Delta: +0.02%

📈 Overall Average

  • PR Coverage: 30.29%
  • Master Coverage: 30.29%
  • Delta: +0.01%

@github-actions
Copy link

github-actions bot commented Nov 24, 2025

Student Install Page

…call

Fixed potential memory leak by using coroutineScope instead of creating
an unmanaged CoroutineScope when sending CalendarSharedEvents.

The coroutineScope function properly inherits the Worker's coroutine
context and ensures the scope is tied to the Worker's lifecycle.

Addresses PR review feedback.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Copy link
Contributor

@adamNagy56 adamNagy56 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Findings in Slack thread.

kristofnemere and others added 5 commits November 25, 2025 11:14
Extended the favorite courses filter logic to properly handle PLANNER_NOTE
items that have courseId stored in plannable.courseId when item.courseId
is null.

Changes:
- Updated filterByToDoFilters to check plannable.courseId as fallback for
  PLANNER_NOTE items when item.courseId is null
- item.courseId always takes precedence when set
- Added 2 unit tests to verify the fallback logic and priority

This ensures PLANNER_NOTE items associated with courses are properly
filtered when "favorite courses only" filter is enabled.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Fixed sticky header not hiding and push-up animation not working after
rotation to landscape mode.

The issue was that rememberStickyHeaderState wasn't tracking changes to
itemPositions in its remember key. After rotation, itemPositions gets
reset but the derivedStateOf wasn't being recreated, causing it to use
stale position data.

Added itemPositions to the remember dependencies so the sticky header
state recalculates properly when positions are remeasured after rotation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Fixed issue where ToDo badge count showed incorrect number when favorite
courses filter was enabled.

Root cause: Badge was passing only favorite courses to filterByToDoFilters,
causing items from non-favorite courses to not be filtered out (course
lookup returned null, so filter couldn't check isFavorite property).

Solution: Fetch ALL courses when favorite filter is enabled, then let
filterByToDoFilters properly check isFavorite property on each course.
This ensures items from non-favorite courses are correctly filtered out.

Changes:
- Use courseApi.getFirstPageCourses() to fetch all courses
- Only fetch courses when favoriteCourses filter is enabled (optimization)
- Filter out access restricted and invited courses (matches ViewModel logic)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Fixed issue where panda illustrations were not showing/hiding correctly
after filter changes.

Root cause: listContentHeight calculation used remember(dateGroups) but
depended on itemPositions which is a mutable state map. When filters
changed, dateGroups changed but itemPositions for new items weren't
measured yet, causing stale values and incorrect showPandas calculation.

Solution: Added itemPositions to remember dependencies, ensuring
listContentHeight recalculates when item positions are updated after
filter changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Extended the calendar ToDo list refresh to trigger after successful media
and file submissions, not just text/URL/annotation submissions.

Previously only text, URL, and student annotation submissions refreshed
the calendar via handleSubmissionResult(). Media and file submissions had
their own success paths that didn't trigger the refresh.

Changes:
- Added coroutineScope calendar refresh call after media submission success
- Added coroutineScope calendar refresh call after file submission success
- Ensures consistent ToDo list refresh across all submission types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Copy link
Contributor

@adamNagy56 adamNagy56 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA +1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants