Settings detail shell and profile settings
All mobile Settings children use the same shell background and one shell top navbar with the destination title and actions. In-app Back appears only in the floating bottom navbar, never in the top navbar. Android system Back remains available. Offline is/settings/offline; its
Finance, Inventory, Tasks and Calendar details are /settings/offline/<module>.
They do not add body title/back bars, nested AppBars or another top safe area.
Their scroll content reserves the shell-provided bottom padding, so the floating
dock clears the last actionable row. Pushed destinations return to the screen
that opened them; direct links fall back to their Settings parent.
Settings → You now opens identity, avatar and account-status settings at
/settings/profile, with account management at /settings/accounts. Legacy
/profile/edit and /profile/accounts links redirect to those destinations.
/profile retains the Overview/Timeline activity surface. Its edit entry is a
compact icon with an accessible Identity label and tooltip. Account-switching
shortcuts remain available there. These defaults apply in both mobile languages;
workspace permissions and queued profile writes retain their existing rules.
Profile identity fields use the shared Settings tiles and panel material, with
read-only values until a field is opened for editing. Manage accounts uses the
same grouped Add account row and account panels; its shell title is not repeated
in a hero card. The Profile account-management entry has one label, and What’s
new keeps its description and installed version without repeating the shell
heading. Account removal confirmations and queued profile writes are unchanged.
These defaults apply to both languages, light/dark themes and enlarged text.
Licenses, onboarding replay and explicit admin edit forms intentionally open
above the shell on the root navigator with their own full-screen chrome. Sheet
editors retain their existing modal presentation. They never stack a second
navbar within a shell body.
Home Agenda, Profile Overview/Timeline and Calendar Agenda reclaim the dock’s
bottom scroll clearance while it is hidden, retaining the physical safe area.
The viewport remains full height; reverse scrolling or idle restores the dock
and its clearance. Other screens keep stable clearance by default. Text Assistant
publishes a lifecycle-scoped composer/action slot into the same shell-owned
floating dock used by every root and detail destination. The material stays
mounted as navigation and prompt content change; width and root bodies animate
independently, with only the current dock controls interactive. No page mounts a
second dock. Reduced motion disables transitions, and a focused composer remains
visible above the keyboard. Draft controllers stay with the cached Assistant
page, while disposed publishers cannot overwrite a newer registration. Text
immersive mode retains the same composer and navigation toggle,
including when entered through an Assistant tool. Live keeps normal navigation while idle or connecting; only connected call
controls replace it, retaining the navbar width and the same shell material. While no workspace is resolved, shell
navigation remains available.
Shell profile reads and cache mutations are fenced by current actor and request
generation. Account changes, logout and newer edits reject late results; cache
writes and clearing remain ordered. Feature-level identity guards also remain.
Regression coverage: settings_detail_shell_checks.dart exercises actual
Offline registrations, inherited background/header and dock clearance, enlarged
text, system/dock back without a top Back button, and unknown module links;
profile_overview_shell_test.dart covers the icon edit entry and return path.
floating_shell_dock_test.dart verifies hidden clearance and stable viewport;
shell_assistant_composer_test.dart verifies one dock, draft/focus and Live
transitions, and shell_profile_races_test.dart covers delayed account/cache
completion. These widget checks do not establish installed-device or production evidence.
Centered navigation and action group
Root and mini-app destinations center the combined visible navigation island and its actions whenever they fit. Empty action columns do not consume space after exit. Dynamic actions reserve width first, moving navigation left, then fade and scale into the free space. On exit, controls disappear before their width is released and navigation recenters. The combined navigation/action group stays centered at every intermediate frame; actions do not animate through a size clip. An interrupted transition reverses from its current geometry, and a replaced outgoing action cannot accept input or accessibility focus. Reduced motion settles both phases immediately. Actions keep 52px slots and share the bottom baseline, including when large text makes the composer taller; narrow layouts keep secondary actions in the top navbar. When the viewport becomes too narrow, the second dock column is removed immediately rather than retaining it while shrinking navigation touch targets. The navigation and Assistant dock share horizontal and safe-area bottom insets, and switching root destinations retains one dock while bodies ease between tabs. Only the active body receives pointer input or semantics. Visited tabs remain mounted, preserving drafts and scroll positions; reduced-motion changes retain the same page elements. Navigation and prompt slots never paint two docks. Coverage:dock_action_choreography_test.dart, persistent_shell_dock_test.dart,
lazy_indexed_stack_test.dart, floating_dock_rail_test.dart,
apps_search_submit_test.dart, and shell_assistant_composer_test.dart.
Leaving Apps or launching a module clears Apps search so returning starts in
navigation mode. Workspace picker search replaces the shell title, and its
visible footer actions are centered. Hiding and restoring workspace shortcuts
belongs to Settings; the normal picker never exposes hide buttons. Coverage:
workspace_picker_sheet_test.dart. Native dark launch backgrounds match the
actual app theme, checked by native_splash_theme_test.dart; the locked screen
shows only the lock status and unlock action. Device visual, transition, and
keyboard checks on the exact CI-built artifact remain required.
Notification navigation and refresh
Mobile Notifications keeps its scoped snapshot visible while revalidating on entry. Concurrent unread badge refreshes share one awaitable request; the visible feed owns its push listener, and count-only changes do not rebuild page rows. Unchanged counts do not serialize the retained feed again. Workspace switches clear the visible feed and reload the selected tab; responses from an older workspace or actor cannot replace current reads. Pagination and offline pending read overlays retain their existing behavior. These defaults apply to the native Inbox and Archive; the sheet also updates its unread header. Empty and error messages use a minimum height rather than a fixed height, so narrow screens and enlarged text can wrap without clipping. The real 320px root transition matrix inshell_assistant_composer_test.dart covers this responsive empty-state path.
notifications_cubit_test.dart covers coalescing, retry, delayed scope responses
and close safety. Focused tests establish request behavior, not a measured device
frame-time improvement.
The persistent notifications action button coalesces unread refreshes only for
the same signed-in actor and workspace. An account transition clears the badge,
retained feeds and pending state before starting a new request, including a
switch away and back in the same workspace. Delayed old requests cannot replace
the new count or end its loading state. This applies to the native shell action
button and shared notifications cubit; delayed-actor and same-workspace ABA
regressions are in notifications_cubit_test.dart.
Product settings entry points
The central Settings overview lists native products with maintained settings entries inproduct_settings_registry.dart. Calendar and Finance open the
existing shared Preferences controls; Mail resolves the selected workspace’s
mailboxes and opens its existing quick-settings editor. Entries are shown only
when the product’s corresponding state/access is available; this registry does
not grant permissions or fabricate settings for unimplemented products. App
quick settings and central entries share implementations and persisted state.
Mail’s nested editor uses the shell title, bottom navigation/actions and inherited
background. A scoped route is cancelled on any account/workspace transition;
request completion cannot replace an editor opened for another scope.
Native text editing and keyboard dismissal
Across mobile routes and modal forms, editable fields keep their native copy, cut, paste and select-all actions while the keyboard is visible. Tapping a selection toolbar, selection handle or aTextFieldTapRegion accessory keeps
editing focus. A genuine outside tap dismisses the visible keyboard through
Flutter’s EditableTextTapOutsideIntent. Dialogs that consume the inherited
keyboard inset still recognize the visible keyboard from the view. A field’s
explicit onTapOutside
callback retains control of its behavior. The task interaction dismissal guard
still suspends outside dismissal. Without a visible keyboard, the existing
focus policy is delegated to Flutter, including mouse and stylus outside
dismissal.
Shadcn text fields and areas explicitly pair the platform menu builder with
native handle-only selection controls. Android and iOS retain draggable
selection handles; desktop keeps its platform handle policy. The device-name
and QR-link inputs use the same native editing controls. Workspace search
already uses a native Material field.
This applies to Material fields and shadcn fields and text areas, including the
Assistant composer and settings forms. Disabled fields remain disabled,
read-only fields allow selection and copying without mutation, and obscured
fields retain Flutter’s restrictions on copying and cutting. Input formatters
and IME composition remain owned by the field.
Regression coverage lives in test/app/view/text_editing_*_test.dart and
dismiss_keyboard_on_pointer_down_test.dart. It exercises real clipboard menu
press/release gestures with a frame between pointer down and up, Android/iOS,
English/Vietnamese, single and multiline inputs, modal and enlarged text,
selection replacement, keyboard shortcuts, field policies and composition.
Widget evidence does not replace native-device clipboard and IME verification.
Private error diagnostics
Mobile Mira reply failures and timezone read/write failures offer Copy debug information only to an authenticated account with a confirmed@tuturuuu.com
email. External addresses, unconfirmed addresses and MFA-required sessions do not
see this control. Email/confirmation changes update auth-state equality; logout
and account changes revoke the control and its stale callback.
Copying writes a local, fixed-field envelope to the clipboard: operation stage,
error category, HTTP status, retry delay and allowlisted rate-limit policy fields.
It never includes messages, prompts, response bodies, URLs, email addresses or
credentials, and never uploads diagnostics. Retry and cooldown rules are unchanged.
Recovery clears old diagnostics; timezone actor/workspace changes discard them.
Streamed HTTP errors retain at most 64 KiB before parsing. Error-body reads have
a total deadline matching the request timeout (30 seconds by default), even if
small chunks keep arriving. Deadline, source failure or overflow requests source
cancellation and discards partial payloads while preserving HTTP status and
headers for typed errors; transport cleanup cannot delay that result. Logout or
actor departure during this read cancels it and rejects publication, including
a return to the same actor. Successful streams keep their existing lifetime. Oversized bodies are
canceled and become generic status failures; status/retry headers survive.
Successful streams remain unread until consumed by the assistant transport.
Coverage: safe_error_diagnostics_test.dart, api_client_stream_error_test.dart,
bounded_stream_error_test.dart, stream_error_deadline_test.dart,
internal_diagnostics_copy_test.dart and
timezone_safe_diagnostics_test.dart. These tests establish local capture,
clipboard privacy and cooldown behavior; they do not establish the cause of a
production 429 or stopped reply.
Component localization fallback
The mobile app supports English and Vietnamese. App and Material strings keep the selected language, including native text actions. The installed Shad component library supplies English resources only, so its built-in control strings use an explicit English fallback in Vietnamese sessions. This does not expand the app’s supported locales or claim those component strings are translated. The shared widget-test app uses the same production delegate. Coverage:shadcn_localizations_fallback_test.dart renders the actual Shad date
picker and Material/app strings in both locales without missing delegates.
Compact settings sections
General and product settings share page-background row groups with quiet separators and unboxed icons, rather than a separate outlined card for every action. Existing profile panels and explicit destructive confirmations retain their grouping. Preference categories use one consistent gap between groups and no trailing group gap; the parent owns spacing to the next section. Row touch targets remain at least 48 logical pixels, while translated labels and enlarged text may increase height. These defaults apply to mobile English/Vietnamese and light/dark themes; settings permissions, destinations and persistence are unchanged. Assistant settings leaves use the same shell and row vocabulary.settings_design_checks.dart exercises the actual Settings host spacing and
320px enlarged-text navigation in both languages/themes. Its harness uses the
production localization fallback and explicit theme/locale. Widget renders are
bounded evidence; exact-build device safe-area, keyboard and visual checks remain
required.
Handled timezone operational failures
Mobile timezone diagnostics distinguish preference load (timezoneRead), API
write (timezoneWrite) and unresolved native timezone after a successful write
(timezoneResolve). A genuine handled HTTP 429 records its status and bounded
Retry-After bucket once, while preserving the existing cooldown, failed edit and
explicit retry. A cooldown-blocked tap, logout, closed cubit or superseded ABA
request does not create an incident. Native lookup that is unnecessary for a
named preference also creates no incident.
The production Crashlytics boundary follows the fixed-field privacy and bounded
dedup defaults documented in mobile chat.
It excludes timezone values and actor/workspace identifiers. Tests can inject a
sink without Firebase. Sink rejection leaves existing UI failure and retry
behavior intact. timezone_operational_reporting_test.dart exercises genuine
HTTP 429 responses through the authenticated API client and repository with
synthetic credentials, separate read/write phases, cooldown/recovery, stale
requests and sink failure. Native authenticated provider/device evidence remains
pending; this does not identify the cause of any customer’s 429.