Components

Settings

Declare one complete settings catalog with persistent values and global search.

AndroidKitSettingsCatalog is the source of truth for the complete Settings hierarchy. Normal pages and global search render the same keyed declarations, so search results execute the original callback or control instead of navigating to the page that contains it.

val catalog = androidKitSettingsCatalog {
    main(key = "main", title = settingsTitle) {
        section(key = "appearance", label = appearanceTitle) {
            theme(themeSetting)
            transparency(opacitySetting)
            toggle(
                key = "autoplay",
                label = autoplayLabel,
                persistence = settingsStore.setting(booleanPreferencesKey("autoplay"), false),
                onCheckedChange = onAutoplay,
            )
        }
    }
    subpage(key = "downloads", title = downloadsTitle) {
        section(key = "storage") {
            button(key = "clear", label = clearLabel, onClick = onClear)
        }
    }
    about(key = "about", content = aboutContent, onOpen = onAbout)
}

AndroidKitSettings(
    catalog = catalog,
    store = settingsStore,
    onOpenSearch = onOpenSearch,
    onStorageFailure = onSettingsStorageFailure,
) {
    // Host navigation destinations render these inside this single owner.
    AndroidKitSettingsPage(pageKey = catalog.mainPageKey)
    // In the Search destination: AndroidKitSettingsSearchPage(onBack = onBack)
}

Settings is one logical search scope. Main, About and every subpage share the complete catalog, recent queries and history enabled state. AndroidKitSettings binds the store’s existing "settings" history internally. Pages and search have no catalog or history parameters. Missing, nested and simultaneous owners for the same store are rejected. Declare the owner above navigation, never inside an individual destination. Independent content searches retain their own page-scoped history through AndroidKitSearchPage.

The host registers page keys in its navigation stack and routes onOpenSearch/About callbacks. Android Kit does not install a navigation controller. Every catalog page receives the sealed Search title-bar action. About remains optional and, when present, is appended to Main.

Catalog contract

The catalog requires exactly one Main page, at most one About page, unique nonblank page keys, and nonblank titles. Section keys are unique within a page; custom entry keys are unique within a section. Stable keys do not depend on translated labels or list positions.

Hosts own section titles, grouping, custom labels, effect callbacks, destinations, and custom title-bar actions. Kit owns durable Settings state, predefined labels, icons, rendering, picker chrome, About order, the Search action, and search-page chrome. Use searchable = false for transient messages or custom rows that should not appear in search.

Language, Theme, Transparency, and App lock retain their typed declarations. Selection option IDs must be unique and include the selected ID. App lock remains host-confirmed and may expose its timeout picker and Lock now callback while enabled. Custom rows use button, navigation, toggle, slider, or info; all now require a stable key.

Language pickers keep System first and sort the remaining options by their stable IDs, case-insensitively, regardless of the script used in native labels or the host’s insertion order. Use standard BCP 47 language tags as language option IDs (for example, id and zh-Hans). New options are sorted on the next render; filtering preserves this order. Theme and timeout options retain host order.

Selected language and theme options retain their checkmark and use the Material 3 secondaryContainer / onSecondaryContainer color pair with medium-weight text. Selection continues to use Compose radio-group semantics.

AndroidKitSettingsSearchPage searches every catalog page, including pages that have not been opened. It uses the shared search page implementation for the floating field, recent searches, empty states, scrolling and managed clearance. Opening the page focuses its input and requests the software keyboard. The Settings adapter owns catalog indexing and result controls; results remain in the current app language. The Settings owner requires the persistent store and a storage-failure callback. It shares history and enabled state across the complete Settings hierarchy.

Matching is case-, accent-, punctuation-, and whitespace-insensitive. Every query token must match. Exact/current labels rank before prefixes, contained visible text, aliases, and page/section context. No fuzzy matching or network translation is performed.

Results reuse the original controls: links and buttons run, toggles change, pickers open in the search page, sliders remain adjustable, and Version copies. Informational and disabled rows preserve their normal behavior. The automatic Main About destination is excluded because the individual About entries are indexed directly.

Kit-owned settings use an offline lexicon containing labels and semantic aliases for every supported locale. A query in any supported language can therefore find a built-in result while the result remains rendered in the current app language. For host-owned entries, the current rendered text is always searchable. Supply optional AndroidKitSettingsSearchTerms maps on pages, sections, entries, legal entries, or options to add translated labels and aliases from other languages.

Recent queries are Kit-owned durable state. Android Kit trims submitted queries, deduplicates them case/accent-insensitively, moves the newest spelling first, and keeps at most ten. A query is recorded after IME submission or a result action; typing and selecting an existing recent query do not change history. The host persists the list if it must survive app restarts.

About

The fixed About page renders app name/description, optional Website and Source code, required Version, optional Contact, and optional Legal entries in that order. Empty groups are omitted. Built-in links use Kit-owned labels and icons; additional legal entries keep host-localized titles and optional multilingual search terms.

Migration from page-local Settings

Remove AndroidKitSettingsPageConfiguration and construct one catalog containing all former Main, Subpage, and About declarations. Move each page title, actions, and content into main, subpage, or about; render by pageKey; and add the host search route. Add stable keys to custom entries and bind editable values to the Kit store. Host navigation and effect callbacks remain available.

Persistent settings (0.1.52-SNAPSHOT)

Open AndroidKitSettingsStore once in the application’s singleton DI provider, with a stable store name and an explicit Plaintext or Encrypted protection policy. The store uses transactional AndroidX DataStore under app-private noBackupFilesDir; encrypted stores use a non-exportable Android Keystore AES-GCM key. Configure one-time AndroidKitSettingsStoreMigration imports on that first call. Existing values take precedence over imports, and migration cleanup follows a successful write. History and preference imports are separate transactions with separate completion markers.

Every editable Settings declaration requires an AndroidKitPersistentSetting: String for selections, Boolean for toggles/app lock, and Float for sliders/transparency. Create bindings with store.setting(preferencesKey, defaultValue). Screen-local values and arbitrary persistence adapters cannot satisfy this API. The Settings owner binds one canonical "settings" history and its enabled preference for Main, About and every subpage. store.searchHistory(stablePageKey) remains available for independent content searches; Settings pages cannot select a history key.

Kit loads persisted values before showing controls, writes ordinary changes before calling host effect callbacks, and keeps writes independent of composition/navigation. Sliders preview while dragging and persist on completion. App lock remains an authorization request: after successful authentication, the host commits to the same Kit binding or store.preferences; rejection leaves the saved preference unchanged. Hosts still apply theme/locale/security effects and must restore those effects from the saved preferences on startup. Existing host repositories can use store.preferences as their DataStore to retain their keys and all additional preferences.

Storage failures are reported through the required callback. Unreadable or unauthenticated files are never silently replaced with defaults. The storage contract guarantees use of durable storage, not successful writes when the device storage or Keystore is unavailable. Domain records, backups and controls outside the Settings API retain their host-owned storage.

Shared Settings owner migration

Remove AndroidKitSettingsSearchConfiguration and its host-selected history. Build the complete catalog with androidKitSettingsCatalog { ... }, and place one AndroidKitSettings(catalog, store, onOpenSearch, onStorageFailure) above all Settings navigation destinations. Remove catalog arguments from AndroidKitSettingsPage and AndroidKitSettingsSearchPage. Subpage destinations must not build replacement catalogs or declare their own owner.

Existing enabled "settings" queries remain unchanged. Previously hidden histories are migrated to disabled and cleared before loading. Former separate About history is left in storage and is not displayed or merged into Settings; this avoids revealing previously hidden subpage queries. General SearchPage history preferences use the enabled policy described in SearchPage.