Info badge: the icon was a PanelContainer using StyleBoxFlat corner
radius to fake a circle, with the radius exceeding half the box size,
causing visible artifacts. Replaced with a custom-drawn Control
(draw_arc) for a clean ring at any size, and added a hover tooltip
explaining what each stat card measures.
Profile: Dictionary.get(key, default) only falls back when the key is
missing, not when it's present with a null value, so a null
displayName rendered as the literal string "<null>" (str(null) in
GDScript) - including pre-filling the edit-profile dialog with it.
Added a shared string_field() helper that treats null the same as
missing, applied everywhere an account/preference string field is
displayed or edited.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
The pause menu (Escape during a question/CCS/flashcards run) only had
Resume/UI Sounds/Exit Run/Log Out. Settings already has an equivalent
"Interface sounds" toggle, so drop the duplicate from the pause menu.
More importantly, "player" and "ccs_player" hide the entire app shell
(header + sidebar), so there was no way to reach Settings or Profile
at all mid-session - add Profile/Settings buttons to the pause menu to
close that gap.
Navigating there follows the existing return_screen payload
convention (already used by simulation_history/results/review) rather
than inventing new navigation infrastructure: _navigate_from_pause()
remembers current_screen_name and passes it through show_screen's
payload. Both screens show a "Back to session" button when that's
set, and hide it otherwise (including on ordinary non-paused visits).
show_screen() unconditionally resumes the question timer via
_close_app_menu() as a side effect of any navigation, so
_navigate_from_pause() re-pauses it immediately when leaving "player" -
the timer then resumes for real, for free, when the user actually
returns via show_screen(return_screen).
progress_profile.gd rebuilds its whole child tree on every theme
toggle (_rebuild -> _build), which would otherwise wipe the button's
visibility - added _refresh_back_to_session_visibility(), called both
after _build() and from on_show(), so it survives a theme change while
paused.
Flipped tests/web_responsive_test.gd's assertion, which previously
required the pause menu NOT to have a Profile button.
Verified end-to-end headlessly: opening the pause menu from a live
"player" session, navigating to Settings and Profile, confirming
current_question_pause_started_at is correctly paused while away and
resumed on return, confirming the back-to-session button appears only
when reached via pause (not on ordinary nav), and confirming it
survives a dark/light theme toggle on the Profile screen.
It checked for a "DynamicQuestionsIcon" mode card that no longer
exists in study_selector.gd (that mode moved to its own nav item and
screen a while back), so it always failed. CCS Cases is now also
UAT-gated and won't be present in the default test environment either,
so point the check at Question Bank, the one mode card that's always
rendered.
- A toolbar icon that hides itself at runtime (labs, notes,
flashcard, bookmark) left its text label behind, showing as an
orphaned label floating in a gap. The label's wrapper now tracks
the button's own visibility.
- The theme toggle used a distinct circular pill shape; changed it
to match the same rounded-square box every other toolbar icon uses.
Adapts the quiz screen's header, toolbar, choice cards, and bottom bar
to the designer's new layout:
- Header: adds the RanaZe logo/wordmark and a question-progress bar +
percentage alongside the existing "Question N of M" text.
- Toolbar: consolidates 12 icon-only/chip buttons into 6 labeled items
(Text size, Calculator, Clear highlight, Notes, Bookmark, More), with
a new "More" popup holding the rest (labs, flag, report, flashcard,
theme toggle, feedback). The underlying buttons are reparented, not
duplicated, so every existing theming/visibility/state call site
keeps working unmodified.
- Category tag: shows the question's discipline (falling back to
system) above the stem.
- Choice cards: every choice now renders as a subtly-bordered rounded
card even before answering, not just a flat divider row; the
currently-selected pre-submit choice shows a checkmark.
- Bottom bar: merges the Skip/Submit row and the timer row into one -
Skip as a plain link, a centered "X of Y" progress bar, and a
time slot that shows the existing countdown when a limit applies or
a new count-up stopwatch ("Time elapsed") otherwise, plus a
Ctrl+Enter/Cmd+Enter submit shortcut with a visible hint.
Two real gaps meant the account-synced zoom (from the previous
"sync through the account" change) never reached the screen:
_load_cache() updated AccountProfileService.preferences but never
emitted profile_changed, so question_player.gd/ccs_service.gd (already
built and listening before login even happens) never found out a
cached value had loaded. And nothing forced a server refresh
right after login - it only fired if the user happened to open the
profile/progress screen, so a fresh device/session had no path to
the true synced value at all.
main.gd now calls AccountProfileService.refresh() once per login
(not on every silent token refresh) so the real preferences GET
always runs right after signing in, on any device.
Also added Question bank/CCS case text size steppers to the Settings
screen next to dark mode, per user request, reusing the same
AccountProfileService/CCSService plumbing as the in-screen A-/A+
buttons.
Drop the redundant header row (duplicate percentage badge + collapse
chevron), the "Why this is appropriate/less appropriate:"/"Why this
is incorrect:" heading labels, and the nested sub-box - now that
these cards live inside their own choice's colored border, all of
that was repeating what the color and position already say. Both the
selected-wrong-choice resolved follow-up and the never-selected
distractor cards now just show the plain explanation sentence, with
the leading "Correct."/"Incorrect." verdict word stripped too.
Removing the toggle chevron removes the only way to reach the
collapse/expand behavior, so that machinery (_collapse_resolved_followups,
_toggle_followup_state, the "collapsed" state field) comes out too
rather than linger unreachable.
Local user://settings.cfg meant zoom level didn't follow a student
across devices/browsers. Question bank and CCS text scale now live on
the user's study profile in Mongo (QuestionTextScale/CcsTextScale),
synced through a new PUT /api/profile/me/text-scale endpoint and the
existing preferences GET/cache already used for study preferences.
Both question_player.gd and ccs_service.gd read the synced value at
startup and react to AccountProfileService.profile_changed so a value
pulled down after login (or changed from another session) applies
without a restart. Backend validates the 0.85-1.35 range and updates
only the field(s) provided via a targeted $set, so it can't clobber
the other scale or the unrelated study-profile preferences.
The choice button above the panel already shows the letter badge,
choice text, and percentage, so repeating them in the panel header
was redundant now that the panel is docked inside the choice's card.
Keeps the collapse toggle, now named FollowupToggle since the old
FollowupSummary button it lived on is gone.
A choice that was crossed out (right-click) and also happened to be
locked as the submitted-wrong choice, or revealed as the correct
answer, silently lost its strikethrough because the percentage-badge
branches took precedence over the elimination check in the same
if/elif chain. Decoupled the two so a choice can show both the
strikethrough and its reveal percentage at once.
The warning was purely a token-expiry countdown with no concept of
user activity, so it interrupted people who had been clicking through
questions the whole time. AuthState now tracks real input activity
globally and silently refreshes the session in the background when
the user has interacted recently, only surfacing the "Stay logged in?"
dialog for sessions that are genuinely idle. A failed background
refresh still surfaces the dialog rather than silently logging the
user out.
Flagged questions disappear from every student-facing surface (search,
exam simulation sampling, the missed-question review queue, bookmarks,
direct fetch) while staying published - flagging and unpublishing are
now separate, reversible actions with their own audit trail (who
flagged it, when, why). Backend-only for now: SUPER-only flag/unflag/
list endpoints, no client UI. Includes a one-time CLI sweep
(flag-media-questions) to flag every existing question with an image
so they can be reviewed.
Matches the mockup: the "Show Answer" button is replaced by an in-card
"Tap card to reveal answer" hint, and clicking anywhere on the card
reveals it (guarded the same way Space already was - only while at the
live card and not yet revealed).