Skip to content

ADFA-4725: K2Go UX/UI redesign — new content-first UI#219

Merged
luisguzman-adfa merged 57 commits into
mainfrom
redesign/ui
Jul 18, 2026
Merged

ADFA-4725: K2Go UX/UI redesign — new content-first UI#219
luisguzman-adfa merged 57 commits into
mainfrom
redesign/ui

Conversation

@luisguzman-adfa

@luisguzman-adfa luisguzman-adfa commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

K2Go — content-first UI redesign (ADFA-4725)

Reorients the app around reaching the content instead of operating the server. The new Activity is the launcher; the old UI stays dormant.

What's in this PR

  • Shell & navigation: new LibraryActivity launcher, bottom nav (Library · Connect · Clone · Settings), scoped Material 3 theme, entry Lottie boot gate.
  • Onboarding & "Set up your library": wizard (Welcome / Language / Permissions) → Step 1 System (editions with real, non-hardcoded sizes) → Step 2 Content (Option A expandable+bar / Option B 5-step+gauge). New List/Grouped Wikipedia version picker (multi-select, min one, hides variants a language lacks, honest live sizes; "skip" = zero, no tier-coupled auto-pick). Maps shown as Included (ships with the system, not reinstalled).
  • Non-destructive installs: "Get more" never overwrites an installed system; adding content is additive; the entry gate waits and shows live download progress during an install instead of dumping the user on a timeout (and is short when nothing is installed).
  • Library home: content-first cards that open the real Kiwix, per-service status dots, pinned "+ Get more" footer.
  • Settings v3: collapsed list + Advanced/About sub-screens, pinned Turn off K2Go, functional Language (app UI locale + content language), Theme, Send feedback, usage-stats consent; Terminal (Debian) reachable from Advanced (terminal-only, no leak to the old UI).
  • Exit: "Turn off K2Go" closing scene.

Notes

  • Related independent work: ADFA-4756 (build-time rootfs size auto-capture) shipped separately to main.
  • Follow-ups: ADFA-4758 (separate the system installer from the content/module installer); softening the permissions gate.
  • l10n: new-UI strings are English-only (translatable="false") pending a dedicated localization pass.

…up gate + SetupSectionFragment completion (Phase 4a)
… codes (fix auto-detect fallback to en) (Phase 4b)
…wix sizes) + real Download via InstallService (Phase 5.2)
…closing scene & graceful teardown (Phase 6.1)
… up library) in M3; startup no longer shows the legacy wizard (Phase 4 rework)
…sh, translatable=false) for a later l10n pass
…o-return notification to LibraryActivity; drop SYSTEM_ALERT_WINDOW
…/Set-up steps + step-through system back (matches updated wizard diagram)
…< Back' link and bottom-anchored CTA (consistent with wizard)
…ont via FontAssetDelegate (OPEN/CLOSED sign text layer)
…aps + disabled Courses, per-row Skip/Add, live bar+total, skip-all=system only
… keeps numbers, draw (i) info badges on editions + sources + coverage/detail
…ntent, per design); fixes the oversized card gap
…ral height; fixes Wikipedia card taking the whole screen)
…ip link (Back left / Skip right); total reflects skip
…e app empty (no install); set up later via Get more
…g" substitution)

Two catalog-resolution fixes in InstallationPlanner:

- Family-safe variant resolution. When an explicit variant is requested but
  absent for that language, degrade only DOWNWARD within the same coverage
  family (top1m -> top, and across detail), never escalating. A "Popular" pick
  can no longer be silently replaced by the full "Everything" (all_maxi) ZIM
  via the old priority list. If nothing in-family exists, no Wikipedia is
  installed rather than a different corpus. The priority auto-select is kept
  only for legacy callers that pass no explicit variant.

- Newest date by declaration. The listing can expose more than one date for the
  same variant; keep only the newest ("YYYY-MM" compares chronologically),
  instead of whichever row happened to come last in the HTML.

Also adds CANONICAL_VARIANTS + availableVariants() so the UI can render only the
versions a language actually offers.
… one), hide-unavailable

Replaces the fixed 2x2 (Popular/Everything x Pictures/Text) with a shared, honest
picker over what a language actually offers.

- WikiVersionPicker (reusable): two views over the same data — List (sortable by
  name or size) and Grouped-by-coverage (Everything / Top 1M / Popular, only the
  groups a language has). Multi-select checkboxes, min one to continue; only the
  variants present in the catalog are shown, the rest are hidden. Mounted in both
  workflows: integrated among the modules in Option A, full-screen (step 1 of 5)
  in Option B.
- WikiVariants: i18n-ready dictionary (coverage/detail names + descriptions as
  string resources) and helpers, incl. primary() = the single ZIM v1 installs
  from a multi-selection (first in canonical order).
- Selection lives in SetupLibraryActivity (shared Set) so picks and the view mode
  survive the A/B flip.
- v1 downloads one ZIM (the primary); the UI is multi-capable for a later
  iteration. Skip Wikipedia still installs system-only.

Builds on the family-safe resolution from the previous commit: the picker only
ever sends a variant the language actually has, so the install can't fall back to
a different corpus.
The storage bar already used the live rootfs size, but the three edition labels
(~1.2 / 1.4 / 2.7 GB) were hardcoded literals in the fragment. They now resolve
through the same path as the bar: the live .meta4 size when online, and the
last-known RootfsCatalog value (shown instantly, no flicker) when offline —
never a number hardcoded in the UI.

Adds InstallationPlanner.fallbackOsSizeGb(Tier): a no-network accessor to the
RootfsCatalog fallback, used for the instant placeholder before the live value
arrives.
…ew Settings, Connect/Clone preview banner

Makes the new UI safe for a tester to explore without hitting controls that look
functional but do nothing.

- Portal: the bottom bar (with Exit) is now persistent instead of starting hidden
  and auto-hiding after 5s behind a tiny handle. A non-technical user always has an
  obvious way out; manual hide via the down-chevron still works.
- Settings: Language, Theme and About are wired to real actions (system language
  settings, a night-mode chooser, and an About dialog with the real version).
  Every not-yet-implemented row is now a visibly dimmed "Soon" preview rather than
  a normal-looking row that only shows a "Coming soon" toast.
- Connect / Clone: a "Preview — not functional yet" banner frames each shell, so
  the mocked call-to-action bars no longer read as working buttons.

Does not change the permissions-step gate (tracked separately).
Step 1's Back did a bare finish(); since the wizard already finished when it
launched Setup, that dropped the user to the home screen. Route to LibraryActivity
(CLEAR_TOP | SINGLE_TOP so an existing instance is reused) — a consistent escape
whether Setup was opened from the wizard or from inside the running library.
# Conflicts:
#	controller/app/src/main/java/org/iiab/controller/InstallationPlanner.java
…, functional Language

Reorganizes the Settings tab to cut option overload and make Language work.

- Top level: Language · Theme · Help · Send feedback · About · Advanced. "Turn off
  K2Go" is a pinned footer OUTSIDE the scroll, so it is never lost regardless of
  screen size or font scale; the minimize note sits above it and the fuller
  explanation is in the confirm dialog.
- Advanced and About are sub-screens (child of the Settings tab, so the bottom nav
  stays; a ‹ back returns to the top level). Advanced is flat with inline
  SYSTEM / DEVELOPER subheaders.
- Language is functional and sets BOTH the app UI locale (AppLocaleController +
  SupportedAppLanguages, which recreates and persists) AND the default content
  language (selected_lang_minimal, derived from the chosen tag).
- Also wired: Theme (night-mode chooser), Send feedback (reuses FeedbackFragment),
  About → real version + Permissions (system settings) + Share usage statistics
  (AnalyticsConsent toggle).
- Not-yet-implemented rows (Help, Advanced items, licenses, Privacy) render as
  dimmed "Soon" previews rather than rows that look active but do nothing.

Shared SettingsUi builds the rows for the top level and the sub-screens.
…minal

The Debian terminal already exists (TerminalController + TerminalView hosted in
MainActivity). Opening it is a single intent: launch MainActivity with
EXTRA_OPEN_TERMINAL, which runs maybeOpenTerminalFromIntent -> openFullTerminal.
Rest of Advanced stays preview.
…old dashboard

Opening Advanced > Terminal launched MainActivity to host the terminal sheet, but
hiding/closing the sheet revealed the old MainActivity dashboard (ESTADO/USO/…),
dropping the user into the previous UI.

New EXTRA_TERMINAL_ONLY flag: when MainActivity is launched just for the terminal
(from the new UI), a BottomSheet callback finishes the activity as soon as the
terminal sheet is hidden, returning to the new UI instead of exposing the old
dashboard. The redesign row sends the flag alongside EXTRA_OPEN_TERMINAL.
The 'Terminal K2Go activa' notification opened MainActivity in normal mode, showing
the old dashboard behind the sheet. It now carries EXTRA_TERMINAL_ONLY too, so both
entry points (Advanced > Terminal and the notification tap) finish back to the new
UI when the terminal is hidden instead of exposing the old dashboard. onNewIntent
already routes to maybeOpenTerminalFromIntent, so SINGLE_TOP reuse is covered.
…system

Adding content must not wipe the OS or the user's customized content. The system
layer (Basic/Standard/Full precompiled blocks) is destructive to re-extract;
Kiwix/Maps content is additive.

- InstallService guard: if a rootfs is already installed and no explicit reinstall
  was requested, the pipeline skips the OS download/extract entirely and only runs
  the additive companion-data steps (or no-ops). Fresh installs and explicit
  reinstalls are unchanged.
- Get more is state-aware: with a system already installed (detected on disk via
  SystemStateEvaluator.isSystemInstalled), it opens Step 2 (content) directly and
  skips the system step; with no system it runs the full setup from Step 1.
- The installed tier is persisted at install time and read back when entering
  content-only, so Step 2 sizes content against the real tier.
- Step 2 "Back" returns to the library when it is the entry point (content-only),
  instead of a no-op.

The deeper separation of the software vs content installers (and an explicit,
guarded change-system flow) is deferred to a follow-up.
Two Step-2 fixes.

- Skipping Wikipedia no longer pulls in a tier-coupled preset. The UI passed a
  null variant when Wikipedia was skipped, and computeProjection treats null as
  "legacy auto-pick" — it ran the priority list and returned a large ZIM. Option B's
  gauge showed that phantom size (~11 GB), and worse, InstallService would actually
  download that auto-picked ZIM even though the user skipped Wikipedia. Now "skip"
  sends an explicit empty sentinel that computeProjection resolves to zero Kiwix
  (no size, no download); null still means legacy auto-pick for old callers.
- Option B breadcrumb now matches Option A / Step 1 ("1 ✓ System → 2 Content")
  instead of the divergent "System ✓ · Content — step 2 of 2".
…ight)

SwitchCompat enforces a ~48dp touch-target min-height, which made the 'Share usage
statistics' row noticeably taller than the rest. Drop the switch's min-height and
cap it so the toggle row lines up with the value rows.
Inclusion forced the Wikipedia card open on load, so users saw a wall of version
options instead of the row of collapsible sources, missing the tap-to-expand
pattern. Decouple inclusion from expansion: the card starts collapsed (as Books /
Maps / Courses do) and only expands on tap; skipping still collapses it.
… out of view

On small screens the Get more button scrolled off the bottom, so users couldn't
tell there was a way to add more content. Same fix as Turn off in Settings: the
cards scroll in a weighted ScrollView and Get more sits in a pinned footer outside
the scroll, always visible.
…it for)

The entry animation waits for the proot/server to come up. If the user skipped
install there is no rootfs/server, so the server never reports alive and the gate
burned the full 25s safety timeout before revealing the library.

Detect the no-system case (SystemStateEvaluator.isSystemInstalled): skip the
server autostart kick and dismiss the gate after a short beat (~0.9s) instead of
25s, so a skipped/empty install opens promptly. A real install is unchanged.
Pressing "Download" started the 2-3 GB install in the background but immediately
opened the library; the boot gate then dismissed on its timeout, dropping the user
into the app long before the download finished and taking the nice progress bar
with it.

The Setup "Download" now flags the library launch as installing. In that mode the
boot gate:
- keeps looping (no timeout dismissal),
- shows live progress over the animation — "Downloading your library… N% · speed"
  for the download, then an indeterminate bar for extract/provision,
- and only flips open and reveals the app when the install reaches SUCCESS (or
  FAILED, so the user is never trapped).

Driven by InstallProgressRepository/InstallState; an explicit EXTRA_INSTALLING flag
avoids any race on whether the service has started yet.
…al Get-more border)

Turn off reused the teal-outlined get-more background, so its clay text sat in a
blue frame. Add a dedicated clay-stroked background for the destructive action and
leave Get more's teal border untouched.
…nload

The Setup Download showed a LENGTH_LONG toast that overlapped the new persistent
progress overlay for the first few seconds (two bars at once). The overlay now owns
that message, so remove the toast.
…e system)

Maps comes bundled in the software block (the tier's base image), so reinstalling
it from the content step is redundant, and there is no way to customize it yet.
Disable it for now:

- Step 2 (A and B) no longer counts Maps in the projected size, and Option A shows
  the Maps card as "Included" (disabled), not a selectable download.
- The Setup Download passes EXTRA_SKIP_MAPS; InstallService then bypasses the maps
  reinstall (runMapsAnsible) and goes straight to success. Scoped to the content
  flow via the flag, so the old UI's behavior is unchanged.
@luisguzman-adfa
luisguzman-adfa merged commit 3508b90 into main Jul 18, 2026
1 check passed
@luisguzman-adfa
luisguzman-adfa deleted the redesign/ui branch July 18, 2026 01:46
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.

1 participant