Replaces the plain title/list layout with a header, a coin-balance
summary card, and a product card grid (icon, description, price,
solid Buy button) matching the app's existing card/badge visual
language. Only the two real products render - no fabricated
categories or bundles, since the backend doesn't have that data yet.
Wires the recently-merged question-completion-credits backend
(GET /api/credits) into the client for the first time: a new
CreditsService autoload fetches/caches the balance, and the embedded
credits field on first-answer responses updates it instantly with no
extra round trip. A shared CreditsBadge widget (star icon, balance,
decorative chevron per mockup) surfaces it in both the question
screen toolbar and the main shell header.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Previously the only way out of an active question run was Escape to
open the pause overlay, then click Exit Run. Exposes main.gd's exit
logic publicly (_exit_run -> exit_current_run) so a house-icon button
in the question toolbar can trigger it directly.
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.
Same treatment as Dynamic Questions and CCS Cases: hide the nav
sidebar entry and the dashboard's "flashcards due" review card unless
step3/deployment_environment is "uat".
Both are still in progress and shouldn't be reachable in production
(or local dev) yet - hide every entry point (nav sidebar, the
dashboard's "dynamic concepts due" review card, and the CCS Cases
mode card on the study selector) unless step3/deployment_environment
is "uat", the same setting that already drives the UAT badge. Added
Brand.is_uat_environment() as the shared check.
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.
The study screen was still treated as a fullscreen immersive view (like
the question player), hiding the main nav sidebar entirely. The mockup
and the user's request both call for keeping the app's left menu while
studying, with the deck panel living inside the screen alongside it.
Add real session-history navigation (Previous/Next/Shuffle), compact
side panels, and a segmented progress row to match the mockup layout.
Flashcards now opens straight into Study, with library management
moved into the Options menu ("Manage Flashcards") and Export hidden
from the UI (Import stays). Shuffle is backed by a real, due-before-new
randomized pick on the backend, not a decorative toggle.
Study screen now matches the provided mockup's layout: a "Current
Deck" panel with a circular mastery-progress ring, and a "Spaced
Repetition" panel (New/Due/Learning/Review counts, streak, daily
goal) on either side of the card. Kept the app's real global sidebar
rather than the mockup's own nav, per direction.
Mastery/Streak/Daily Goal weren't tracked anywhere, so this adds real
backend support rather than showing fabricated numbers:
- Mastered = graduated to review state AND FSRS stability >= 21 days
(FlashcardScheduleStore.MasteryStabilityDaysThreshold), stricter
than the plain Review-state count
- CurrentStreakDays = consecutive UTC days with a review, computed
from review-log timestamps in the new pure FlashcardScheduling
.ComputeStreakDays (unit tested, habit-streak semantics: doesn't
reset to 0 the instant a new day starts before today's first review)
- DailyGoal/ReviewsToday reuse the account's existing ReviewsPerDay
setting rather than inventing a new one
Also removes the exit "X" button in favor of the same Escape/pause
menu the question-player flow uses (main.gd's shared app_menu, with
an "Exit Study Session" action), and adds a new circular_progress.gd
reusable ring control plus a real "Options" menu (bury/suspend the
current card) wired to schedule endpoints that had no UI before.
Adds a full flashcards system: FSRS-based scheduling, cloze/basic
card types, CSV import/export, media storage, and study UI, wired
into navigation and the dashboard alongside existing question flows.