-
Notifications
You must be signed in to change notification settings - Fork 108
[MBL-19461][Student] Add My Courses dashboard widget #3429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Implement the data and domain layers for the new My Courses widget: - Add domain models for course and group cards with grade display states - Extend CourseRepository with favorite courses and dashboard cards - Create GroupRepository for fetching user groups - Add use cases for loading courses and groups - Implement CoursesWidgetViewModel with state management - Add DataStore for persisting section expanded state - Create app-specific behaviors for grade visibility (Student only) - Set up dependency injection modules for all apps 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Implements the Compose UI components for the My Courses dashboard widget: - Generic shimmer loading component in pandautils for reusable loading states - CourseCard with horizontal 72x72 layout, kebab menu with dropdown, grade badge - GroupCard with member count badge and parent course name display - CollapsibleSection for expandable courses/groups sections with animations - CoursesWidget main composable with loading, courses, and groups sections - Integrated widget into dashboard with WidgetMetadata and default widgets - Updated behavior interface with menu action methods (manage offline content, customize course) All components follow Material3 design system and match Figma specifications. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Implements color overlay preference for course cards, matching existing dashboard behavior: - Created ObserveColorOverlayUseCase following same pattern as grade visibility - Added observeColorOverlay() to CoursesWidgetBehavior interface - Updated CourseCard to conditionally show overlay (0.4 alpha) or full image (1.0 alpha) - Course color background always visible when no image present - ViewModel observes preference changes and updates UI state reactively - Integrated with existing StudentPrefs.hideCourseColorOverlay setting The overlay switch in the navigation drawer now controls both legacy cards and the new widget. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Remove course code display, show only course name for cleaner layout - Update NotAvailable grade badge to use noGradeText string resource - Match grade badge font styling (14sp SemiBold) across all grade types including N/A 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Add CoursesWidgetRouter interface and app-specific implementations - Update use cases to return raw Course/Group objects - Move card item mapping to ViewModel for navigation access - Add NonLazyGrid composable for grid layout in non-lazy context - Pass Course/Group objects to router for proper navigation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Fix CourseCard ripple effect to respect rounded corners - Add preview composables for DashboardScreen states (loading, error, empty) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Add LoadFavoriteCoursesUseCaseTest - Add LoadGroupsUseCaseTest - Add CoursesWidgetViewModelTest - Extend CourseRepositoryTest with getFavoriteCourses and getDashboardCards tests - Add GroupRepositoryTest - Add StudentCoursesWidgetBehaviorTest - Add TeacherCoursesWidgetBehaviorTest - Add ObserveGradeVisibilityUseCaseTest - Add ObserveColorOverlayUseCaseTest - Fix TeacherCoursesWidgetModule DI scope (FragmentComponent -> ViewModelComponent) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Add comprehensive UI tests for CoursesWidgetContent composable covering: - Loading shimmer state - Empty state (no courses or groups) - Single and multiple courses display - Groups display - Courses and groups together - Grade display (percentage, letter, hidden) - Collapsible section toggle callbacks - Section collapse/expand interactions - Synced indicator and announcement count - Multiple columns on tablet Also add getFragmentActivityOrNull extension for test-safe activity access and test tags to CourseCard and GroupCard composables. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Summary
This PR adds a new Courses Widget to the dashboard, implementing the feature for both Student and Teacher apps with appropriate app-specific behavior. The implementation follows the project's established patterns well, including proper use of the Router pattern, dependency injection with Hilt, and comprehensive test coverage.
✅ Positive Aspects
- Excellent test coverage: Comprehensive unit tests for use cases, behaviors, and UI components
- Good architectural separation: Proper use of the Router pattern with app-specific implementations
- Clean Compose UI: Well-structured composables with proper state management and animations
- Consistent with project patterns: Follows MVVM architecture, uses Hilt DI, and matches existing code style
- Responsive design: Properly handles both phone and tablet layouts with configurable columns
- Accessibility: Good use of content descriptions and semantic elements
🔍 Issues Found
Below are specific issues that should be addressed:
- Hardcoded SharedPreferences constants (ObserveColorOverlayUseCase.kt:51, ObserveGradeVisibilityUseCase.kt:51): Extract PREFS_NAME and preference keys to avoid duplication and potential sync issues
- Inconsistent error handling (StudentCoursesWidgetRouter.kt:38 vs TeacherCoursesWidgetBehavior.kt:48): Student router uses TODO comments while Teacher throws NotImplementedError - should be consistent
- Potential UI flash (DashboardFragment.kt:54): Status bar styling moved to onViewCreated may cause brief visual flash
- Unused parameter (CourseCard.kt:177): onMenuClick callback is defined but never used in the implementation
- Background color changes (DashboardScreen.kt:114, 129): Changed from backgroundLightest to backgroundLight - verify this is intentional and doesn't affect other UI elements
🎯 Additional Recommendations
- TODO Comments: Consider creating follow-up GitHub issues for unimplemented routing features (Manage Offline Content, Customize Course) to ensure they're tracked
- Constants Management: Consider creating a shared constants object for preference keys used across multiple files
- Error Handling: The use cases using SharedPreferences don't handle potential exceptions - consider adding error handling
- Memory Leaks: The SharedPreferences listeners in use cases are properly cleaned up with awaitClose - good job!
🔒 Security & Performance
- ✅ No security vulnerabilities identified
- ✅ No SQL injection or XSS risks
- ✅ Proper use of Flow for reactive data
- ✅ Efficient SharedPreferences listener management
📝 Code Quality
Overall code quality is very good. The implementation is clean, well-tested, and follows Kotlin best practices. Minor improvements suggested in inline comments would enhance maintainability.
Recommendation: Address the inline comments, particularly around constants duplication and error handling consistency, then this should be good to merge.
...java/com/instructure/student/features/dashboard/widget/courses/ObserveColorOverlayUseCase.kt
Show resolved
Hide resolved
...a/com/instructure/student/features/dashboard/widget/courses/ObserveGradeVisibilityUseCase.kt
Show resolved
Hide resolved
...java/com/instructure/student/features/dashboard/widget/courses/StudentCoursesWidgetRouter.kt
Show resolved
Hide resolved
...va/com/instructure/teacher/features/dashboard/widget/courses/TeacherCoursesWidgetBehavior.kt
Show resolved
Hide resolved
...tudent/src/main/java/com/instructure/student/features/dashboard/compose/DashboardFragment.kt
Show resolved
Hide resolved
🧪 Unit Test Results✅ 📱 Parent App
✅ 📱 Student App
✅ 🌅 Horizon
✅ 📦 Submodules
📊 Summary
Last updated: Thu, 11 Dec 2025 13:51:12 GMT |
Add courses widget verification to all test cases, fixing test failures after the My Courses widget was added to the default widgets list. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
📊 Code Coverage Report✅ Student
✅ Teacher
|
Add a stub provider for CoursesWidgetBehavior in HorizonTestModule to fix the Hilt dependency graph for Horizon test builds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Remove assertion for "Favorite Courses and Groups" title that was removed from UI - Remove assertion for "All Courses" button in loading state (button only appears after loading) - All 18 tests now pass on Pixel 2 API 29 emulator 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
… widget - Switch to getCourses() API endpoint instead of getFavoriteCourses() to ensure enrollment data with grades is properly loaded - Use Course.getCourseGrade() method to properly calculate grades with grading period support - Filter courses by dashboard card presence to exclude concluded/hidden courses - Add getCourses() method to CourseRepository with depagination support - Update LoadFavoriteCoursesUseCase to filter by both isFavorite and dashboard card presence - Update all unit tests to use getCourses() and Student enrollment types The getFavoriteCourses() endpoint was not reliably including enrollment data, causing grades to appear as locked. The getCourses() endpoint (same as legacy dashboard) includes full enrollment data needed for grade calculations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Add parentCourseColor property to GroupCardItem - Group card background and placeholder use group's own color - Parent course name text displays in parent course's color - Use CanvasContext.color extension for theme-aware colors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Dashboard not updating when favorites change.
- We only use light course/group colors regardless of the theme.
- Course and group item background color is different in dark mode.
- The colors are incorrect on the course color/image. Text colors in dark mode should always be dark on colored backgrounds. Also the background of the icons and numbers of colored text should be dark. See the design.
- All courses button should be at the top right according to the design. We would also need a "Favorite Courses and Groups" title next to it.
- We should reconsider how we scale the UI when the font size is changed. Especially the All Courses button. (see screenshot)
...tils/src/main/java/com/instructure/pandautils/data/repository/course/CourseRepositoryImpl.kt
Outdated
Show resolved
Hide resolved
...rc/main/java/com/instructure/pandautils/domain/usecase/courses/LoadFavoriteCoursesUseCase.kt
Outdated
Show resolved
Hide resolved
...main/java/com/instructure/pandautils/features/dashboard/widget/courses/CollapsibleSection.kt
Outdated
Show resolved
Hide resolved
...ils/src/main/java/com/instructure/pandautils/features/dashboard/widget/courses/CourseCard.kt
Show resolved
Hide resolved
...ils/src/main/java/com/instructure/pandautils/features/dashboard/widget/courses/CourseCard.kt
Outdated
Show resolved
Hide resolved
.../src/main/java/com/instructure/pandautils/features/dashboard/widget/courses/CoursesWidget.kt
Outdated
Show resolved
Hide resolved
.../java/com/instructure/pandautils/features/dashboard/widget/courses/CoursesWidgetViewModel.kt
Outdated
Show resolved
Hide resolved
.../java/com/instructure/pandautils/features/dashboard/widget/courses/CoursesWidgetViewModel.kt
Outdated
Show resolved
Hide resolved
.../java/com/instructure/pandautils/features/dashboard/widget/courses/CoursesWidgetViewModel.kt
Outdated
Show resolved
Hide resolved
.../java/com/instructure/pandautils/features/dashboard/widget/courses/CoursesWidgetViewModel.kt
Show resolved
Hide resolved
tamaskozmer
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QA + 1
Summary
Test plan
refs: MBL-19461
affects: Student
release note: Added "My Courses" widget to the dashboard showing your favorite courses and groups with quick access to grades and announcements
🤖 Generated with Claude Code