Replace the short-lived info toast with the existing titleless confirmation dialog and a single OK button so users can read the routing explanation at their own pace. Keep dialog visibility in saveable screen state and reuse the existing localized help and action strings.
Extract only the help-dialog presentation from local/talkback-all-10; leave app-row semantics, switches, routing descriptions, and notification infrastructure in the accessibility branches.
Reject duplicate names and empty names or URLs before invalidating the existing asset cache. Previously a rejected save left the stored source unchanged but deleted its downloaded file.
Preserve the validation messages and their order, duplicate-name exclusion by asset ID, and successful-save behavior. Renames still invalidate the old filename before updating the asset record.
A saved SUB_IDS array can contain the same GUID more than once. Loading
it verbatim creates repeated subscription rows with identical Compose
and reorderable-list keys, which can crash the subscription screen.
Deduplicate IDs in the shared reader while preserving the first-seen
order and mutable-list contract. This protects every index consumer
without changing subscription records, generating replacement IDs, or
adding writes during reads. Different subscriptions with identical or
blank names remain separate.
Add six regression tests for duplicate rows, stable ordering, read-only
decoding, mutable round trips, repeated names, and existing empty/invalid
input behavior. Three assertions fail on unchanged upstream; all six
pass with the fix. The full 63-test suite and Play Store debug build pass.
On the API 37.1 Pixel 9 Pro emulator, a deliberately duplicated saved
index loaded each subscription once, retained first-occurrence order,
reopened safely, and edited the correct record. The raw index remained
duplicated throughout the check; no app crash was observed.
Logcat used the complete log text as a Compose lazy-list key after 258de2097. Identical timestamped messages and repeated stack frames are valid log output, but collide as keys and crash the main thread while browsing logs.
Give each occurrence its own key in a small ViewModel-owned presentation model. Count oldest-first so prepending newer logs and filtering unrelated lines retain existing occurrence keys. Build the projection off the main thread and keep raw text, duplicates, ordering, copy and share behavior unchanged.
Add six regression tests covering duplicate messages, repeated frames, filtering, refresh, empty input and key-like text. All 63 Play Store unit tests pass; the debug APK was checked on the API 37.1 emulator with duplicate-line scrolling, filtering, refresh, reopening and lossless export. The original failure is documented by the user-provided physical-device crash log.
* docs: refresh agent guidelines
* docs: add agent harness adapters
* Update local-only block markers in AGENTS.md
DO NOT COMMIT phrase was confusing most LLMs and preventing them from committing anything without an additional explicit permission.
Build presentation-ready server row models in the ViewModel and publish each group's raw data and row data as one atomic state.
This removes storage and description work from composition, reduces the server-row API, and keeps reordering consistent across both representations.
Load asset metadata on Dispatchers.IO and publish the asset list and file details as one lifecycle-aware UI state.
Remove refresh-key workarounds, await reloads before downloads, and keep the content composable stateless.
Clear visible delays immediately, but move the per-profile MMKV reset to the existing I/O coroutine. Finish the reset before starting the test service so newly reported results cannot be erased.
* Localize runtime-generated UI text
Keep connection-test and status data locale-neutral until the UI formats it, and localize delay units at their Compose presentation boundary.\n\nShow stable localized failures while retaining diagnostic exceptions in Logcat. Clarify routing rule matching and subscription entry/exit proxy behavior at the relevant UI call sites, and remove the now-unused core error resources.
* Fix Compose resource lookup in routing editor
* Adjust string
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* Refine existing locale translations
Carry over the standalone wording and translation corrections from the combined localization audit across all nine maintained catalogs.
Keep identifiers, order, placeholders, and metadata unchanged. Exclude resource additions, removals, and wording that depends on locale API, connection-result, routing layout, subscription proxy, delay-unit, or core code changes.
* Clarify profile export actions
Distinguish copying a profile share link from copying the fully generated configuration in every maintained locale.
Use AndroidX and framework per-app locale APIs, migrate the existing language preference, and expose the generated locale config to Android 13+ settings.
Resolve resources through the selected app locale in application, ViewModel, tile, and service contexts. Replace the framework OK and Cancel labels directly implicated in the wrong-language report, and refresh retained localized UI state after locale changes.
* fix: localize UI and accessibility text
* fix: translate BQI core errors
* fix: correct Bakhtiari orthography and wording
Replace the remaining Persian confirmation fallbacks, correct stale or mismatched UI meanings, and normalize established Bakhtiari terms without translating xray-core identifiers.
Primary source: Erik Anonby and Ashraf Asadi, Bakhtiari Studies II: Orthography (2018), sections 6.1.1, 6.8.1, 6.8.2, 6.8.7, and 6.8.9. https://www.diva-portal.org/smash/get/diva2%3A1231755/FULLTEXT02.pdf
The standard recommends that "Arabic letters be retained for Bakhtiari words borrowed from Persian" and reports that speakers view soft d as "a defining feature of how the language is pronounced."
Lexicon and phonology source: Erik Anonby and Ashraf Asadi, Bakhtiari Studies: Phonology, Text, Lexicon (2014). https://uu.diva-portal.org/smash/record.jsf?pid=diva2%3A758171
Historical corroboration: D. L. R. Lorimer, The Phonology of the Bakhtiari, Badakhshani, and Madaglashti Dialects of Modern Persian (1922). https://archive.org/details/phonologyofbakht06loriuoft
* fix: keep protocol description technical
* fix: keep Logcat diagnostics unlocalized
* getRemoteIPInfo
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* Optimize app picker filtering and selection
Avoid per-query string copies and repeated state persistence or service restart requests during bulk selection. Preserve the active filter while apps load, calculate automatic and imported selections away from the main thread, and keep upstream's asynchronous Coil icon pipeline unchanged.
* Remove enabled: Boolean = true
---------
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
* Use typed actions for application menus
* Use Material 3 navigation drawer components
Replace the custom drawer rows with NavigationDrawerItem and route system Back through Compose so an open drawer closes before the task is backgrounded.
* Polish typed menus and drawer integration
Camera HALs may expose a Y plane whose row stride is wider than the visible image. Pass that stride to ZXing so padded rows remain aligned, and cover the vendor-layout case with a valid VLESS QR regression test.
Promote each foreground service before onStartCommand can return early. Reuse or create the core notification on repeated starts, and migrate its hidden channel to a silent low-importance channel with a new ID.
Profile editors are bounded forms whose focused child must remain stable while the IME changes the available height. Lazy list item boundaries can be remeasured or detached during these viewport changes, causing visible jitter and leaving lower or multiline fields obscured.
Compose the form eagerly in one vertically scrollable Column. Preserve the existing spacing, scrollbar, IME padding, and bottom padding, and update only protocol-editor call sites to the ColumnScope API.
* Fix reordered list behavior and persistence
Use remove-and-insert semantics for every reorderable collection and persist the resulting order instead of swapping endpoints.
Resolve routing rules and proxy-chain members by stable keys, make proxy rows draggable, and serialize profile-order writes per group so rapid drag updates cannot be persisted out of order.
* Signal touch reorder activation with haptic feedback
Emit one gesture-threshold pulse when a long press makes an item draggable. Reuse the same handle across every reorderable list and rely on the platform touch-feedback setting.