Skip to content

[MBL-19529][S] Learner Dashboard - Widget Settings Save#3931

Merged
vargaat merged 38 commits intomasterfrom
feature/MBL-19529-Learner-Dashboard-settings-save
Mar 16, 2026
Merged

[MBL-19529][S] Learner Dashboard - Widget Settings Save#3931
vargaat merged 38 commits intomasterfrom
feature/MBL-19529-Learner-Dashboard-settings-save

Conversation

@vargaat
Copy link
Collaborator

@vargaat vargaat commented Mar 9, 2026

What's new?

Implements persistent saving of widget settings in the Learner Dashboard, so user configurations (visibility, order, colors, course settings) survive app restarts.

Widget Architecture Changes

Split DashboardWidgetIdentifier into Two Enums

  • SystemWidgetIdentifier - fixed, always-visible widgets (offlineSyncProgress, fileUploadProgress, courseInvitations, globalAnnouncements, conferences).
  • EditableWidgetIdentifier - user-configurable widgets (helloWidget, coursesAndGroups). These can be hidden, reordered, and have persisted settings.

Factory Methods Moved Onto Identifier Enums

  • Widget view model creation was extracted from LearnerDashboardWidgetAssembly:
    • SystemWidgetIdentifier.makeViewModel
    • EditableWidgetIdentifier.makeViewModel
    • EditableWidgetIdentifier.makeSubSettingsView - returns an optional settings view per widget (only coursesAndGroups has one)
  • LearnerDashboardWidgetAssembly is now just a thread-safe singleton cache for CoursesInteractor.

Interactor Now Drives Two Separate Widget Pipelines

  • LearnerDashboardInteractorLive accepts two factory closures at init time: systemWidgetFactory and editableWidgetFactory to create view models.
  • loadWidgets() always maps all system widgets first, then loads saved/default configs, merges them (to handle newly added widgets after updates), filters by visibility, sorts by order, and appends editable widgets.

Settings Changes Save Immediately and Trigger Reload

  • When the user changes any setting, it saves immediately to SessionDefaults and fires a callback, which causes LearnerDashboardViewModel to call loadWidgets() again.

Color Management

A new LearnerDashboardColorInteractor owns all dashboard color logic:

  • Holds a CurrentValueSubject<Color, Never> for reactive color updates.
  • Persists the selected color ID (not the raw color value) via SessionDefaults+DashboardColor.
  • LearnerDashboardViewModel subscribes to color changes via .onReceive.
  • Colors are saved by their IDs so we needed some refactoring in Core related to that.

refs: MBL-19529
builds: Student
affects: Student
release note: none

test plan:

  • Test widget settings.

Screenshots

ScreenRecording_03-11-2026.12-45-27_1.mov

Checklist

  • Follow-up e2e test ticket created
  • A11y checked
  • Tested on phone
  • Tested on tablet
  • Tested in dark mode
  • Tested in light mode
  • Approve from product

petkybenedek and others added 17 commits March 3, 2026 13:21
refs: MBL-19529
builds: Student
affects: Student
release note: none
# Conflicts:
#	Student/Student/LearnerDashboard/Widgets/Common/Model/DashboardWidgetConfig.swift
#	Student/Student/LearnerDashboard/Widgets/Common/Model/DashboardWidgetViewModel.swift
#	Student/Student/LearnerDashboard/Widgets/ConferencesWidget/ViewModel/ConferencesWidgetViewModel.swift
#	Student/Student/LearnerDashboard/Widgets/CourseInvitationsWidget/ViewModel/CourseInvitationsWidgetViewModel.swift
#	Student/Student/LearnerDashboard/Widgets/CoursesAndGroupsWidget/ViewModel/CoursesAndGroupsWidgetViewModel.swift
#	Student/Student/LearnerDashboard/Widgets/FileUploadProgressWidget/ViewModel/FileUploadProgressWidgetViewModel.swift
#	Student/Student/LearnerDashboard/Widgets/GlobalAnnouncementsWidget/ViewModel/GlobalAnnouncementsWidgetViewModel.swift
#	Student/Student/LearnerDashboard/Widgets/HelloWidget/ViewModel/HelloWidgetViewModel.swift
#	Student/Student/LearnerDashboard/Widgets/OfflineSyncProgressWidget/ViewModel/OfflineSyncProgressWidgetViewModel.swift
#	Student/StudentUnitTests/LearnerDashboard/Container/Model/LearnerDashboardInteractorTests.swift
#	Student/StudentUnitTests/LearnerDashboard/Container/ViewModel/LearnerDashboardViewModelTests.swift
…//github.com/instructure/canvas-ios into feature/MBL-19529-Dashboard-simple-edit-mode

# Conflicts:
#	Student/StudentUnitTests/LearnerDashboard/Container/ViewModel/LearnerDashboardViewModelTests.swift
refs:
builds:
affects:
release note:

test plan:
…, always visible) and EditableWidgetIdentifier

  (user-configurable)
  - Interactor now loads system widgets always, and editable widgets from merged saved+default configs filtered by visibility/order
  - Settings changes now save immediately to SessionDefaults and trigger a dashboard reload via onConfigsChanged callback
  - Widget assembly split into separate makeSystemWidgetViewModel / makeEditableWidgetViewModel factories
refs: MBL-19529
builds: Student
affects: Student
release note: none

test plan:
- Test widget settings.
@vargaat vargaat self-assigned this Mar 9, 2026
@bitrise
Copy link
Contributor

bitrise bot commented Mar 9, 2026

Builds

Commit: Fix lint violation. (882f35a)
Build Number: 1552
Built At: Mar 13 17:39 CET (03/13 10:39 AM MDT)

Student

vargaat and others added 7 commits March 10, 2026 09:50
…ure/MBL-19529-Learner-Dashboard-settings-save

# Conflicts:
#	Student/Student/LearnerDashboard/Container/ViewModel/LearnerDashboardViewModel.swift
#	Student/Student/LearnerDashboard/Settings/LearnerDashboardSettingsAssembly.swift
#	Student/Student/LearnerDashboard/Settings/View/LearnerDashboardCourseSettingsView.swift
#	Student/Student/LearnerDashboard/Settings/ViewModel/LearnerDashboardCourseSettingsViewModel.swift
#	Student/StudentUnitTests/LearnerDashboard/Container/ViewModel/LearnerDashboardViewModelTests.swift
@instructure instructure deleted a comment from bitrise bot Mar 11, 2026
@instructure instructure deleted a comment from bitrise bot Mar 11, 2026
@instructure instructure deleted a comment from bitrise bot Mar 11, 2026
@bitrise

This comment was marked as outdated.

@vargaat vargaat marked this pull request as ready for review March 11, 2026 13:07
vargaat added 2 commits March 11, 2026 14:44
# Conflicts:
#	Core/Core/Common/CommonUI/InstUI/Styles/Elevation.swift
…ure/MBL-19529-Learner-Dashboard-settings-save

# Conflicts:
#	Student/Student/LearnerDashboard/Widgets/DashboardWidgetIdentifier.swift
#	Student/Student/LearnerDashboard/Widgets/LearnerDashboardWidgetAssembly.swift
#	Student/StudentUnitTests/LearnerDashboard/Container/Model/LearnerDashboardInteractorTests.swift
@bitrise

This comment was marked as outdated.

Base automatically changed from feature/MBL-19529-Dashboard-simple-edit-mode to master March 12, 2026 16:15
@bitrise

This comment was marked as outdated.

@bitrise

This comment was marked as outdated.

@rh12
Copy link
Contributor

rh12 commented Mar 13, 2026

I had some additional findings

  • There should be a "Customize Dashboard" button at the bottom of the Dashboard
    • Both in Empty and Data states
  • We should show an empty state even if there are system widgets (like the Global Announcement on the Figma example). So this state should be determined by the lack of editable widgets.
  • The empty state should be the "All widgets are turned off" one, not the one describing no courses. That's already done for the Courses widget.

I don't mind (actually, would prefer) these to be added in a followup PR though

@bitrise

This comment was marked as outdated.

Copy link
Contributor

@rh12 rh12 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

For the followup ticket:

  • Color selector: white checkmark not visible in Dark Mode "black" circle
  • VoiceOver: Disabled up/down arrow is available (both in end-state and in hidden widget state), and the user never knows that it does nothing. Maybe this could be improved somehow.
  • We could disable the subsetting toggles when the widget itself is hidden. IMHO it would be less confusing to not have active controls in the hidden section.

@bitrise
Copy link
Contributor

bitrise bot commented Mar 13, 2026

Warnings
⚠️ This pull request will not generate a release note.
⚠️ One or more files are below the minimum test coverage 50%

Affected Apps: Student

Builds: Student

MBL-19529

Coverage New % Master % Delta
Canvas iOS 91.7% 81.06% 10.64%
Core/Core/Common/CommonUI/Layout/FlexibleGrid.swift 0% -- --

Generated by 🚫 dangerJS against 882f35a

@vargaat vargaat merged commit b9b9baa into master Mar 16, 2026
5 checks passed
@vargaat vargaat deleted the feature/MBL-19529-Learner-Dashboard-settings-save branch March 16, 2026 09:19
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