Skip to main content

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 in shell_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 in product_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 a TextFieldTapRegion 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.