feat: disable IME extract UI and centralize singleLine keyboard behavior - #1014
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
✅ Files skipped from review due to trivial changes (4)
📝 WalkthroughWalkthroughAdds Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant IME
participant Interceptor as InterceptPlatformTextInput
participant TextField as NoExtractOutlinedTextField
participant Focus as FocusManager
User->>IME: enter text / trigger IME action
IME->>Interceptor: PlatformTextInputMethodRequest (EditorInfo)
Interceptor-->>IME: forward modified EditorInfo (imeOptions OR-ed with IME_FLAG_NO_EXTRACT_UI)
Interceptor->>TextField: deliver input events / composition
TextField->>User: render updated text
alt singleLine && IME action == Done
TextField->>Focus: clearFocus()
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
app/src/main/java/app/gamenative/ui/component/settings/SettingsTextField.kt (1)
42-49: Consider parameterizingsingleLinefor flexibility.The hardcoded
singleLine = trueworks for most use cases (button labels, typical settings). However, this component is also used for environment variable values (perSettingsEnvVars.kt), which could theoretically contain longer or multi-part values.Given the 76.dp width constraint already implies compact single-line usage, this is acceptable. If multi-line env var support is needed later, consider exposing
singleLineas a parameter.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/app/gamenative/ui/component/settings/SettingsTextField.kt` around lines 42 - 49, The NoExtractOutlinedTextField usage hardcodes singleLine = true; make this configurable by adding a singleLine: Boolean parameter to the SettingsTextField composable (default true) and forward it into NoExtractOutlinedTextField, then update call sites (e.g., SettingsEnvVars usage) to pass singleLine = false where multi-line values may be needed; ensure default preserves current behavior.app/src/main/java/app/gamenative/ui/component/dialog/GeneralTab.kt (1)
69-91: Consider addingImeAction.Nextto navigate between width and height fields.Both fields use
singleLine = truewithout explicitimeAction, so pressing "Done" on the width field will clear focus instead of moving to the height field. Users can still tap the height field manually, but addingImeAction.Nextwith focus navigation would improve the input flow.♻️ Optional: Add focus navigation between width and height
+val heightFocusRequester = remember { FocusRequester() } + NoExtractOutlinedTextField( - modifier = Modifier.width(128.dp), + modifier = Modifier.width(128.dp).focusRequester(widthFocusRequester), value = state.customScreenWidth.value, onValueChange = { state.customScreenWidth.value = it }, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Number, + imeAction = ImeAction.Next, + ), + keyboardActions = KeyboardActions( + onNext = { heightFocusRequester.requestFocus() }, + ), label = { Text(text = stringResource(R.string.width)) }, singleLine = true, ) // ... separator ... NoExtractOutlinedTextField( - modifier = Modifier.width(128.dp), + modifier = Modifier.width(128.dp).focusRequester(heightFocusRequester), value = state.customScreenHeight.value, // ... rest remains the same with singleLine = true for Done behavior )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/main/java/app/gamenative/ui/component/dialog/GeneralTab.kt` around lines 69 - 91, The width and height NoExtractOutlinedTextField inputs (NoExtractOutlinedTextField using state.customScreenWidth.value and state.customScreenHeight.value) lack an explicit IME action, so pressing "Done" on the width field clears focus instead of moving to the height field; update the first field's KeyboardOptions to include imeAction = ImeAction.Next and add KeyboardActions (or a FocusRequester/LocalFocusManager) to move focus to the height field on Next, and set the height field's imeAction appropriately (e.g., ImeAction.Done) so keyboard navigation flows from the width field to the height field.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@app/src/main/java/app/gamenative/ui/component/dialog/GeneralTab.kt`:
- Around line 69-91: The width and height NoExtractOutlinedTextField inputs
(NoExtractOutlinedTextField using state.customScreenWidth.value and
state.customScreenHeight.value) lack an explicit IME action, so pressing "Done"
on the width field clears focus instead of moving to the height field; update
the first field's KeyboardOptions to include imeAction = ImeAction.Next and add
KeyboardActions (or a FocusRequester/LocalFocusManager) to move focus to the
height field on Next, and set the height field's imeAction appropriately (e.g.,
ImeAction.Done) so keyboard navigation flows from the width field to the height
field.
In `@app/src/main/java/app/gamenative/ui/component/settings/SettingsTextField.kt`:
- Around line 42-49: The NoExtractOutlinedTextField usage hardcodes singleLine =
true; make this configurable by adding a singleLine: Boolean parameter to the
SettingsTextField composable (default true) and forward it into
NoExtractOutlinedTextField, then update call sites (e.g., SettingsEnvVars usage)
to pass singleLine = false where multi-line values may be needed; ensure default
preserves current behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f9daec99-4575-41e4-ab4f-3fa8b6c81e0a
📒 Files selected for processing (11)
app/src/main/java/app/gamenative/ui/component/NoExtractOutlinedTextField.ktapp/src/main/java/app/gamenative/ui/component/dialog/Box64PresetsDialog.ktapp/src/main/java/app/gamenative/ui/component/dialog/ControllerBindingDialog.ktapp/src/main/java/app/gamenative/ui/component/dialog/EnvironmentTab.ktapp/src/main/java/app/gamenative/ui/component/dialog/FEXCorePresetsDialog.ktapp/src/main/java/app/gamenative/ui/component/dialog/GameFeedbackDialog.ktapp/src/main/java/app/gamenative/ui/component/dialog/GeneralTab.ktapp/src/main/java/app/gamenative/ui/component/dialog/TouchGestureSettingsDialog.ktapp/src/main/java/app/gamenative/ui/component/settings/SettingsTextField.ktapp/src/main/java/app/gamenative/ui/screen/login/TwoFactorAuthScreen.ktapp/src/main/java/app/gamenative/ui/screen/login/UserLoginScreen.kt
a9471d6 to
b4d9061
Compare
|
|
Tip For best results, initiate chat on the files or code changes.
✏️ Learnings added
🧠 Learnings used |
There was a problem hiding this comment.
Is this the only way we can do this? Is there no way to use OutlinedTextField with a param or something?
b4d9061 to
adef332
Compare
…ior (utkarshdalal#1014) * feat: disable IME extract UI and centralize singleLine keyboard behavior * fix: convert remaining OutlinedTextField to NoExtractOutlinedTextField
* feat: use game hero image as booting splash background * fix: add drop shadow to booting splash status and tip text * feat: resolve hero image for all game sources on booting splash * Update app/src/main/java/app/gamenative/ui/model/MainViewModel.kt Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Added verify files to GOG, clear prerequisite markers on verify, allow submitting feedback for non-steam, non-custom games * fix: do not crash on game start on Meta Quest (#1105) * Don't show logged out steam splash when offline and steam games are installed (#1138) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Hide local saves only setting (#1139) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Added back best config for non steam games, except remove executable path if it's a different store (#1141) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * bumped version code for 0.9 full release * fix: prevent carousel touch loss during pagination (#1127) * fix: prevent carousel touch loss during pagination by removing touch-conflicting draggable modifier * fix: address bot review feedback on carousel mouse input handler * fix: add drag slop to carousel mouse drag to prevent accidental scrolls on click * fix: Download support files for gen 2 (#1130) * Download support files for gen 2 * Added tests to verify downloading support and game files for gen 1 and 2 * fix: include shared redistributables when resolving steam depots (#1166) * fix: include shared redistributables when resolving steam depots Merges depot IDs from the shared license (ID 0) with app-specific depots to ensure common redistributables and dependencies are correctly identified and downloaded along with game-specific files. * Update app/src/main/java/app/gamenative/service/SteamService.kt Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix: use horizontal tab row for downloads screen in portrait mode (#1153) * Added wine env var fix type + fix for stardew (#1156) * fix: improve download memory handling on CaseInsensitiveFileSystem (#1142) * do less caching for god of war download * bump js version 1.8.0.1-18-SNAPSHOT, update CaseInsensitiveFileSystem to implement BaseCaseInsensitiveFileSystem * only remove the file from cache inside removeFileCache * fix: nested segment cache + pre-populated listings in CaseInsensitiveFileSystem * update resolveAndCache only cache directory and skip file * add log option to CaseInsensitiveFileSystem, handle deleteRecursively properly * coderabbitai comments --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> Co-authored-by: Jeremy Bernstein <jeremy.d.bernstein@googlemail.com> * chore: re-order downloads & storage tabs (#1079) * Reorder sidebar: Storage Manager first, Downloads second; fix header title on Downloads tab * Default selected tab to Storage Manager * Add downloads_section_title translations for all 13 locales * fix: swap Settings before Downloads in System sidebar * chore: add fexcore 2604 (#1170) Co-authored-by: Phobos665 <5970062+phobos665@users.noreply.github.com> * feat: empty Wine/XDG trash on container shutdown (#1151) * Feat: Update wine-mono version to 11.0.0 in installer scripts (#1133) * feat: update wine-mono version to 11.0.0 in installer scripts * fix: bump_version in ImageFsInstaller.java, will trigger extraction for all existing containers that are on Mono 9.0.0 and install 11.0.0. * Added additional directory for xna msi (#1125) * feat: warn-before-exit preference with double-back confirmation (#993) * Update README.md * fix: match UFS save file globs case-insensitively (#1183) * feat: ludashi style vivid screen effect (#1106) * feat: add fake HDR screen effect * fix: remove quick menu darkening scrim * chore: shorten HDR effect description * refactor: rename HDR effect to vivid mode * i18n: add vivid mode translations * Add GOG force cloud save and related string updates. (#812) * fix: library view not updating after game uninstall (#956) DownloadService caches directory listings for 5s. After deleteApp, the cache still holds the deleted directory, so the subsequent LibraryInstallStatusChanged refresh sees stale data. Invalidate the cache after deletion so the next scan picks up the change. * fix: correct steam game dlc licensing logic and enhance dlc display (#1191) * fix: correct steam game dlc licensing logic and enhance dlc display in content Cross-references resolved depots with owned DLC package information to ensure depots are attributed to the correct DLC app ID. This ensures accurate DLC identification for titles like Don't Starve, Halo MCC, and Cyberpunk 2077. * refactor getMainAppDepots to calculate the logic to be used in getDownloadableDepots * fix: suppress connection banner during initial Steam connect (#918) Also use state.isSteamConnected (Compose-observable StateFlow) instead of SteamService.isConnected (static boolean invisible to recomposition) for banner visibility. * Devil blade reboot utkarsh (#1198) * fix: case-insensitive .exe filter in getWindowsLaunchInfos * removed bug around appLaunchInfo null opening wfm.exe * fixed build * addressed coderabbit * more coderabbit --------- Co-authored-by: Dan Brooke <mail@danbrooke.net> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * fix: Migrate GSE Saves to steam userdata, always upload userdata files to steamcloud (#1100) * migrate GSE Saves to steam userdata, always upload userdata files to steam cloud fix tests * move migrateGSESavesToSteamUserdata just before beginLaunchApp * also migrateGSESavesToSteamUserdata just before forceSyncUserFiles * also migrateGSESavesToSteamUserdata in SteamUtils ensureSteamSettings * use Files.move for migrating files * check dir empty to exit earlier, update logging * preserve file attributes like timestamp and permission during migration * Add reusable INI game fix for Imperivm (#1009) * Add reusable ini game fix for Imperivm * Avoid rereading ini fixes after migration * Remove ini migration marker tracking * feat: disable IME extract UI and centralize singleLine keyboard behavior (#1014) * feat: disable IME extract UI and centralize singleLine keyboard behavior * fix: convert remaining OutlinedTextField to NoExtractOutlinedTextField * fix: preserve file timestamps during Steam Cloud download (#1199) Maintains the original modification time from Steam Cloud for downloaded files. This ensures that games which rely on file timestamps for save loading and ordering, such as Skyrim, function correctly. * feat: added multi-controller support (#1047) * feat: added multi-controller support - physical controller handler services now acommodate multi controller state management via deviceId - new autoassign func - windhandler accomodated MAX_PLAYERS = 4 suppot, multi-controller state management - new MultiControllerTest.kt test suite fix: address multi-controller rumble and device identifier bugs - prevent missed rumble on secondary slots when controller is adopted after a rumble command arrives by deferring the "delivered" marker - remove unreachable vendor/product fallback in device identifier lookup since getDescriptor() is available on all supported API levels revert to original controller manager handling legacy cases and added test case * handled respect disabled slots when reusing an existing assignment * reset rumble state when a slot adopts a new controller * magic number removed using dedicated WinHandler.MAX_PLAYERS const * removed more magic numbers - using dedicated MAX_PLAYERS const and remove null controller phone vibrate case with some docs on why --------- Co-authored-by: = <=> * fix: use container language for install size estimate (#1054) size estimate used PrefManager.containerLanguage (global default) but download uses container.language (per-container). mismatch causes wrong depot count and size when container language differs from default. * feat: FSR 1.0 & Scaling Modes (#1112) * feat: add quick menu fsr and sharpness controls * refactor: port fsr passes from official gpuopen source * feat: add true fsr render-scale upscaling * chore: remove fsr toggle description * refactor: derive fsr input from container resolution * feat: add live scaling modes * chore: move scaling controls to top of screen effects * fix: match default fsr rcas denoise behavior * fix: save quick menu scrim removal before master sync * fix(renderer): only override render target size for scaled scenes * fix: clear stale container state on task swipe and app restart (#1136) * fix: clear stale container state on task swipe and app restart when the user swipes the app from the task switcher while a container is running, keepAlive stays true but xEnvironment is gone. on next launch the app is stuck thinking a container is running. extract shutdownEnvironment() from XServerScreen.exit() so the same full teardown runs in both the normal exit path and the crash recovery path. each step is wrapped in runCatching so one failure doesn't prevent the rest. - onCreate: if keepAlive is set but xEnvironment is null, run shutdownEnvironment() to clear stale state - onDestroy: emit ActivityDestroyed before super (so exit() listeners still fire), then force shutdownEnvironment() if keepAlive persists - exit(): delegates teardown to shutdownEnvironment(), keeps only winHandler.stop() and trash cleanup (container-specific) * fix: stop all foreground services on task swipe when idle Steam/GOG/Epic services had no onTaskRemoved — foreground notification persisted after swipe because nothing told the service to stop itself. * fix: recognize unhandled UFS path types and fix save pattern parsing edge cases (#1157) * fix: recognize WindowsHome UFS root as PathType.Root for cloud save sync Steam PICS can specify `root: WindowsHome` in save file patterns (e.g. Stellar Blade, app 3489700). PathType.from() did not handle this token, causing it to fall through to PathType.None. None.isWindows is false, so the pattern was silently dropped in getLocalUserFilesAsPrefixMap and the saves were never scanned or synced. WindowsHome is the Windows user home directory (C:\users\xuser\ in Wine), which is exactly what PathType.Root maps to. Fix by recognising "windowshome", "%windowshome%", and "root" in PathType.from() as Root, and adding Root to the isWindows set so it passes the save pattern filter. * fix: recognize SteamCloudDocuments UFS root as WinMyDocuments for cloud save sync Steam PICS can specify `root: SteamCloudDocuments` in save file patterns (e.g. Sonic Mania, app 584400). PathType.from() did not handle this token, causing it to fall through to PathType.None and be silently dropped during save pattern filtering. SteamCloudDocuments is Steam's name for the user's Documents folder, which maps to WinMyDocuments (C:\users\xuser\Documents\) in Wine. Fix by recognising "steamclouddocuments" and "%steamclouddocuments%" in PathType.from() as WinMyDocuments. * fix: normalize '.' save path to empty string to prevent broken cloud keys Steam PICS manifests sometimes use `path: .` to mean "root of this path type, no subdirectory" (common in Unity games). When a Windows rootoverride also has a non-empty addpath, the dot was appended literally — producing paths like "Thunder Lotus Games/Spiritfarer/." and uploadPath = "." — which caused cloudPrefixToLocalPath to build a key like "%GameInstall%." that never matches the bare "%GameInstall%" prefix the cloud API returns, so downloaded files landed in the wrong directory. Fix by normalising "." to "" at parse time in KeyValueUtils, consistent with how UserFileInfo.prefix already treats cloudPath == ".". Affected games: Spiritfarer and CrossCode. * fix: recognize WinProgramData and SteamUserBaseStorage UFS path types, handle oslist in rootoverrides - Add WinProgramData PathType mapping to drive_c/ProgramData/ - Alias SteamUserBaseStorage to SteamUserData in PathType.from() - Check oslist field alongside os when filtering Windows rootoverrides * fix: bump CURRENT_UFS_PARSE_VERSION to 2 to force re-parse of cached UFS data Ensures existing cached SteamApp rows are re-parsed to pick up the path normalization and oslist rootoverride fixes from this branch. * fix: lowercase Root/ROOT_MOD aliases and add wrapped %root% form in PathType.from() * fix: add %steamuserbasestorage% as suggested by coderabbit * fix: perf hud fps fix for other wrappers (#1164) * fix(hud): measure fps from render frames * fix(hud): track fps against topmost app window * Fix silent cloud save overwrite when sync cache is missing (#1169) * fix: show conflict dialog when cloud sync cache is missing, regardless of change number the old gate (localAppChangeNumber >= 0) skipped the conflict dialog for first-time offline players whose change number is -1. this meant local saves were silently overwritten by cloud on reconnect. remove the gate: if cache is absent and local files exist, always treat as conflict. * test: cloud sync decision matrix covering all cache/CN/cloud states 12 scenarios covering: cache present/absent, local changes/none, cloud ahead/same, preferred save location, first-time offline play. also fixes existing download test (cloud filenames, mock params, deprecated API). * fix: split cache-absent conflict into upgrade vs first-offline cases * test: revert modifications to existing tests, keep only new additions * fixed steam intent launches, no need to check for offline mode * Added option to toggle button hints bar (#811) * fix crashes on migrateGSESavesToSteamUserdata (#1207) * GOG chunk URL broken when CDN token is in query string (#1215) * Update CONTRIBUTING.md to reduce ambiguity * Update pull_request_template.md to reduce ambiguity * Jb/streaming assembly utkarsh (#1219) * feat: streaming download+assembly for Epic/GOG to reduce disk usage replace two-phase (download all chunks → assemble all files) with a unified loop that assembles files front-to-back as their chunks land and deletes consumed chunks immediately. peak disk usage drops from ~2x install size to ~1x. - StreamingAssembly: shared pure logic for chunk ordering, last-file tracking, readiness checks, and safe deletion decisions - EpicDownloadManager: downloadAndAssembleEpicChunks replaces separate download+assembly phases for both base game and DLC - GOGDownloadManager: downloadAndAssembleChunks with secure link refresh, used by both main game and dependency downloads. removed dead downloadChunksSimple and assembleFiles. - 14 unit tests covering ordering, deduplication, shared chunks, cleanup safety, and full batch-loop simulations * fix: run final assembly pass for zero-chunk Epic files mirrors the GOG fix — when all files have zero chunks, the chunk loop never executes and assembly never runs without a trailing pass. * fix: allow all-zero-chunk Epic manifests to reach assembly * Resolved conflicts, sped up GOG, made resuming downloads for GOG work better, made downloading UI progress smoother * handle retries correctly for assembly for GOG * addressed coderabbit comments * More AI fixes --------- Co-authored-by: Jeremy Bernstein <jeremy.d.bernstein@googlemail.com> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Aligned epic downloads to GOG to make it faster from eg India (#1220) * Aligned epic downloads to GOG to make it faster from eg India * coderabbit comments, removed xserverscreen mistake changes --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Revert "feat: added multi-controller support (#1047)" (#1224) This reverts commit 2334981. * Create ROADMAP.md * Update ROADMAP.md * tests: Added unit tests for new key parts of Gamenative (#1143) * Added launch dependency tests * Added game fix registry tests * Added preinstall step tests * Some AI improvements + moved gamefixes tests to new types folder * Added test to keep canonical root at the correct location (#1144) * fix: preserve aspect-correct viewport for screen effects (#1213) * Create pr-label-command.yml * Recommendation page (#1235) * Added recommendations to game page + library, added toggle to hide recommendations, * Added review scores to recommended games * Added date to recommended app screen like the others * coderabit comments --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * fix: skip spurious conflict when cache lost but local==remote (#1228) destructive db migration wipes file_change_lists cache, making every steam game trigger conflict on first launch post-update. check if local state is byte-identical to remote manifest (by filename + SHA) before declaring conflict; if so, rehydrate cache and report UpToDate silently. also populates real timestamps on the genuine-divergence path (was showing epoch). test: dbCleared_localMatchesRemote_rehydratesSilently_noConflict * chore(): openApi specs for Gog, Epic & Amazon (#1234) * chore(): openApi specs for Gog, Epic & Amazon * chore(): Update the epic token to look more fake. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * added toggle to disable posthog tracking (#1236) * added toggle to disable posthog tracking * Updated readme to include analytics info --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * refactor: Moved Proton downloading to launch deps (again, but mirroring original behaviour + tests) (#1052) * Reapply "Refactored default Proton downloads to launch deps" (#1050) This reverts commit 1cd84b4. * Moved proton download to original location by moving launch deps call * Removed deletion since previously we didnt do that either. * Added test for new launch dep * Added codeonwers file * fix(): toggle showing achievements (#1251) * fix(): toggle showing achievements * fix(): fixed imports and state on settings. Testing now. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: mouse movement in games that use raw mouse input and clipcursor (#1084) * refactor: register X extensions with event and error id assignment * add writeFP3232 to XOutputStream * feat: add XInput2 Extension and associated events * Implement ClipCursor behavior and fix XWarpPointer to include soft margin in the window calculations * add logging to help extension debugging * fix: correct confinement off by one * fix: throw BadValue if no mask as per XI2 spec * fix: change Bitmask to hold 64 bits to be able to read XI2 masks * More fallout game fixes (#1134) * fix: reject config with missing components, show dialog with apply-anyway option (#801) * fix: reject config with missing components, offer apply-anyway with defaults * fix: pass storeMatch to force-apply path for cross-store configs * Added kingdom hearts 3 (EPIC) gamefix (#1161) * feat: Add Steam save import and export actions (#966) * Add Steam save import and export actions * fix: harden Steam save import and export * fix: correct manifest driver id * fix: stabilize Steam save archive roots * fix: make Steam save root ids collision resistant * fix: simplify Steam save transfer to userdata * feat: add multi-root save discovery and translations * refactor: use string resources for app option menu labels * Workshop Update: Manual Mod Folder Dialog (#1072) * Workshop Update: Manual Mod Folder Dialog - Full-screen workshop manager dialog with hero image, mod list, select-all/deselect-all, and per-mod toggle switches - FolderPickerDialog for manually choosing mod installation paths when automatic detection fails - Improved mod path detection: binary scanning, config file parsing, AppData walking with fuzzy matching - CKM (Creation Kit Module) extraction for Skyrim mods - LZMA decompression with concurrent processing - ZIP extraction for single-archive workshop uploads - Magic-byte file type detection and extension fixing - Disk space checking before downloads - allSelected derivedStateOf optimization (removed wasteful toMap key) - Added KNOWN_EXTENSIONS to WorkshopItem for file type validation * Fix folder picker breadcrumb for multi-level paths * Guard folder picker directory listing with try/catch/finally * Rethrow CancellationException in folder picker LaunchedEffect * feat: task manager from qam (#1121) * feat(quick-menu): replace tools tab with task manager launcher * feat(quick-menu): show running exe memory usage * feat(ui): streamline quick menu task manager * refactor: inline process user lookup in ProcessHelper * fix/feat: extract XAudio DLLs from DirectX redistributables (#1184) * feat: extract XAudio DLLs from DirectX redistributables Adds support for decompressing and installing DirectX audio components (XAudio, XACT, X3DAudio) from game cabinet files into the Wine prefix. This uses 7-Zip bindings to extract the necessary DLLs to system folders, helping resolve audio compatibility issues in games that rely on specific redistributable versions. * refactor replaceXAudioDllsFromRedistributable to XServerScreenUtils add other gamesource detection * fix gameId detection * surround gameId detection with try catch * update use FileOutputStream for dll extraction * add log when appDirPath detection failed * move SevenZip init outside per file function * ai comments * only apply for proton 10, fix proton 9.0 compatibility * revert SteamUtils changes * fix directXDir detection logic * fix directXDir detection logic * update proton 10 logic * fix: kill stale wine processes before launch (#1195) * fix: kill stale wine processes before launch * fix: wait for stale wine processes to exit * fix: block back during prelaunch loading * refactor: move stale wine process kill logic to ProcessHelper * fix: GOG cloud save fetch failure handling (#1201) * Fix GOG cloud save fetch handling * Add GOG cloud save regression tests * Clarify GOG cloud save fallback comment * feat: Parallelize Steam cloud save downloads (#1226) * Refactor Steam cloud download flow No logic changes. Extract the per-file download body from the forEach loop in downloadFiles into a new private downloadSingleFile function to make the upcoming parallelisation diff easier to read. The httpClient is moved from steamInstance.steamClient.configuration.httpClient (pulled inline) to a parameter so the caller controls which client to use. * Parallelize Steam cloud save downloads Replace the sequential forEach loop in downloadFiles with a coroutineScope { map { async { semaphore.withPermit { ... } } }.awaitAll() } pattern, capping concurrency at PrefManager.downloadSpeed via a Semaphore. A dedicated OkHttpClient is created per sync via Net.httpForParallelDownloads so each parallel call gets its own Dispatcher thread pool. filesDownloaded and bytesDownloaded are promoted from plain vars to AtomicInteger and AtomicLong to handle concurrent updates safely. Per-file streaming progress is added: downloadedRawBytes (incremented per chunk via a CAS loop) drives onProgress during the download, while a separate lastReportedPercent AtomicInteger deduplicates callbacks so only strictly increasing percentages are emitted. The upfront indeterminate "Downloading filename" callback is removed in favour of this. downloadSingleFile gains httpClient, totalRawBytes, downloadedRawBytes, lastReportedPercent, completedFiles, totalFiles, and progressMessage parameters to support the above. The unused steamInstance parameter is removed. copyTo now returns total bytes read and passes chunkBytes to the progress callback. Adds steam_cloud_sync_downloading_save_files string to all 14 locale files for the X/Y files in-progress message. * Fix cloud save download edge cases Wrap the connection phase (httpClient.newCall.execute) in a try/catch for SocketTimeoutException and IOException, returning null on failure instead of propagating an uncaught exception. Capture the withTimeout(responseTimeout) block as a Boolean result and return null if the response body stream was absent. Previously a null body silently completed without writing any file; now both the compressed and uncompressed paths guard with ?: return@withTimeout false. Move response.close() to a finally block so it fires on every exit path. Remove the redundant explicit close that was on the !isSuccessful path. Fix UserFilesDownloadResult to report rawFileSize (uncompressed bytes) instead of fileSize (compressed bytes). The mismatch caused bytesDownloaded to undercount for compressed files and allowed the download progress to transiently exceed 100%. Emit "Download complete" unconditionally after awaitAll() rather than only when filesDownloaded == totalFiles, so a partial failure no longer stalls the UI at the last reported percentage. Add IOException and SocketTimeoutException catches inside the streaming try block (distinct from the outer connection-phase catches) with a shared finally for response.close(). * Fix cloud save download robustness issues Close response on unsuccessful HTTP to prevent connection leaks, catch TimeoutCancellationException so one download timeout doesn't cancel all parallel downloads, treat short reads as failures and clean up partial files, and only report "Download complete" when all files succeeded. * fix: address Steam cloud review feedback Handle Steam cloud metadata fetch failures per file without swallowing coroutine cancellation, so the reviewed exception path no longer cancels sibling downloads while structured cancellation still works correctly. Also tear down the per-sync Steam cloud download client after the batch completes to release dispatcher threads and pooled connections, while keeping failed-download file handling aligned with current master behavior. * fix: use stored installPath in GOGManager.deleteGame to prevent uninstall failures (#1255) * added new turnip drivers to manifest (#1263) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * chore(): add new box64 to GN. (#1262) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Revert "fix/feat: extract XAudio DLLs from DirectX redistributables (#1184)" (#1266) This reverts commit 3a4cb3d. * Added some changes for rockstar launcher (#1274) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Updated manifest to include new protons (#1275) * Updated manifest to include new protons * Fixed manifest values * fixed proton 10 x86-64 id --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Added THIRD_PARTY_NOTICES * feat/refactor: Improve GOGDownloadManager download efficiency (#1277) * refactor: Improve GOGDownloadManager download efficiency 1. Adopt Flow queuing concept from JavaSteam 2. add DownloadSpeedConfig to be used later for other store enhancement 3. update kotlinx-coroutines-core version to match JavaSteam version using 4. Update NetworkUtils httpForParallelDownloads for timeout and http protocol config * ai comments * add retry logic when same pendingChunks appear 10 times in a row * fix: extract XAudio DLLs using native cabarc instead of 7-Zip binding (#1269) * Reapply "fix/feat: extract XAudio DLLs from DirectX redistributables (#1184)" (#1266) This reverts commit 93793fa. * fix: extract XAudio DLLs using native cabarc instead of 7-Zip binding Replaces the 7-Zip JBinding library with a Wine-based batch script that uses the native cabarc utility to extract DirectX DLLs. This removes the dependency on JitPack and the external 7-Zip library while maintaining the fix for Proton 10. * ai comments * ai comments * ai comments, refactor to XAudioUtils * guard batchCommand with BATCH_SUCCESS_CHECK * move guard code location after all extraction * remove useless comment * add splash text when extracting dlls * fix(workshop): force standard Steam UGC path for Tale of Immortal (#1260) - Add AppID 1468810 (Tale of Immortal) to `forceStandardAppIds` to ensure workshop items are handled via the standard ISteamUGC path. * Move Touchscreen Mode toggle to in-game sidebar (#1249) Moved Touchscreen Mode toggle from Edit Container > Controller section to the in-game sidebar, right below the existing Edit On-screen Controller line. Added gear icon for gesture settings that appears when touchscreen mode is active. * fix: late release single tap in touchscreen mode to fix clicking in some games (#1212) * fix: late release single tap in touchscreen mode to fix clicking in some games * fix: immediately release click before a new single tap * clear delayedPress state after execution * flush pending single tap release on handleTsDown * Update README.md * feat(): Silly draft for ideation of EOS. * Added sidecar for EOS, made downloading EOS launch dependency, Deliver at all Costs working * addressed AI comments * fix: gog download pause / resume handling logic * fix unit test * revert downloadChunk logic on md5 checking before downloading file * Made layouts for appscreen and libraryscreen cutout/notch aware * Merge pull request #1300 from utkarshdalal/unpack-more made unpack files more aggressive * fix: resolve cloud save path for Danganronpa 2 (app 413420) (#1297) Danganronpa 2 stores saves in WinMyDocuments/My Games/Danganronpa2/ via a Windows rootoverride, but GameNative was placing downloaded cloud saves in the game install directory instead, so the game never found them. Two bugs fixed: 1. KeyValueUtils: treat PICS path '/' as empty (same as '.') A lone forward-slash means 'root of this path type' with no subdir. Keeping the literal '/' caused uploadPath='/' which put a trailing slash on the cloudPrefixToLocalPath map key ('%GameInstall%/') while the lookup trimmed it ('%GameInstall%'), causing a miss. With the fix, uploadPath='' and path='My Games/Danganronpa2' (no trailing slash). Also bumps CURRENT_UFS_PARSE_VERSION 2->3 to force cache refresh. 2. SteamAutoCloud getFullFilePath: consult cloudPrefixToLocalPath when Steam embeds the placeholder in the filename (prefix=[], filename='%GameInstall%savedata.vfs'). The previous early-return hardcoded the destination as the game install dir, bypassing all rootoverride remapping. Now checks cloudPrefixToLocalPath['%GameInstall%'] first so the file lands in WinMyDocuments/My Games/Danganronpa2/. Also adds .trimEnd('/') to cloudKey construction in cloudPrefixToLocalPath so map keys are always slash-free (matching the existing lookup behaviour). Tests added: - KeyValueUtilsTest: danganronpa2SlashPathWithWindowsRootOverrideIsNormalizedToEmpty - SteamAutoCloudTest: downloadWithEmbeddedGameInstallPrefixUsesRootoverrideLocalPath - keyvalues/Danganronpa 2 Goodbye Despair.txt: PICS reference documentation * fix/tabbar-scrolling-clip (#1293) * fix: copy a new dll generated with proton 11 (#1287) * fix: open download details fullscreen (#1270) * fix: repair steam save export (#1265) * feat: move Disable Mouse Input to in-game Quick Menu overlay (#1267) * feat: move Disable Mouse Input to in-game Quick Menu overlay Removes the Disable Mouse Input toggle from the container settings Controller tab and adds it to the in-game Quick Menu, where it can be toggled during gameplay without leaving the game. State is persisted to the container config on toggle. * fix: address code review feedback - Remove unconditional setCursorVisible call; cursor state is managed by existing pointer-availability logic and should not be overridden when a physical mouse may be present - Key isDisableMouseInput state to container.id to prevent stale state if container changes * fix: restore cursor visibility on mouse input toggle Show cursor when re-enabling mouse input (unless touchscreen mode is also active), hide it when disabling. Required for touch-as-mouse users who have no physical pointer device. * fix: use mouse icon and pink accent for Disable Mouse quick menu item * fix: join prealloc job before polling so zero-chunk files are created before return (#1308) * fix: use consistent purple accent color for all quick menu items (#1311) * Stop overwriting wine prefix when switching between containers of dif… (#1310) * Stop overwriting wine prefix when switching between containers of different variants/archs, only extract xaudio dlls once * do reinstall of mono and preinstallsteps on wine version change (not arch), fixed bugs with wincomponents, audio driver, and startup selection being overwritten on wine version change --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * fix: soften boot splash hero backdrop * fix: resolve boot splash hero image off main thread * made booting splash image greyscale background instead of having inconsistent color that doesn't gel with GN --------- Co-authored-by: xXJsonDeruloXx <danielhimebauch@gmail.com> Co-authored-by: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> Co-authored-by: Luboš V. <tridosm@gmail.com> Co-authored-by: UnbelievableFlavour <bart.zaalberg@shift2.nl> Co-authored-by: Joshua Tam <297250+joshuatam@users.noreply.github.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Jeremy Bernstein <jeremy.d.bernstein@googlemail.com> Co-authored-by: Phobos665 <5970062+phobos665@users.noreply.github.com> Co-authored-by: CatPotatos <catarinaleal123@gmail.com> Co-authored-by: AnikethanVA <82267223+AnikethanVA@users.noreply.github.com> Co-authored-by: Dan Brooke <mail@danbrooke.net> Co-authored-by: Misazam <60115666+Misazam@users.noreply.github.com> Co-authored-by: bllendev <113651082+bllendev@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: André Vitor <90573731+AndreVto@users.noreply.github.com> Co-authored-by: Nightwalker743 <Hillardjoseph43@gmail.com> Co-authored-by: linkq <mrlinkq@hotmail.com> Co-authored-by: Daniel Joyce <danielalexanderjoyce@gmail.com> Co-authored-by: tlt21 <travistryba@gmail.com> Co-authored-by: Almond <88301593+sdkahal@users.noreply.github.com> Co-authored-by: Ben Pearson <ben@buriza.co.uk>
* Implementing SettingsListDropdownSearchable. A Searchable ListDropDown for Dropdowns with a lot of items. Exchanged SettingsListDropdown with SettingsListDropdownSearchable in following dialogs GraphicsTab->Graphic-Driver Winetab->Renderer WineTab->GPU-Name Added Translations for Label. * Resolving issues from AI-Codereview * Resolving Translation Issuis from AI-Codereview * Update app/src/main/res/values-ko/strings.xml Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * Feat/hero bg booting splash utkarsh (#1587) * feat: use game hero image as booting splash background * fix: add drop shadow to booting splash status and tip text * feat: resolve hero image for all game sources on booting splash * Update app/src/main/java/app/gamenative/ui/model/MainViewModel.kt Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Added verify files to GOG, clear prerequisite markers on verify, allow submitting feedback for non-steam, non-custom games * fix: do not crash on game start on Meta Quest (#1105) * Don't show logged out steam splash when offline and steam games are installed (#1138) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Hide local saves only setting (#1139) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Added back best config for non steam games, except remove executable path if it's a different store (#1141) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * bumped version code for 0.9 full release * fix: prevent carousel touch loss during pagination (#1127) * fix: prevent carousel touch loss during pagination by removing touch-conflicting draggable modifier * fix: address bot review feedback on carousel mouse input handler * fix: add drag slop to carousel mouse drag to prevent accidental scrolls on click * fix: Download support files for gen 2 (#1130) * Download support files for gen 2 * Added tests to verify downloading support and game files for gen 1 and 2 * fix: include shared redistributables when resolving steam depots (#1166) * fix: include shared redistributables when resolving steam depots Merges depot IDs from the shared license (ID 0) with app-specific depots to ensure common redistributables and dependencies are correctly identified and downloaded along with game-specific files. * Update app/src/main/java/app/gamenative/service/SteamService.kt Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix: use horizontal tab row for downloads screen in portrait mode (#1153) * Added wine env var fix type + fix for stardew (#1156) * fix: improve download memory handling on CaseInsensitiveFileSystem (#1142) * do less caching for god of war download * bump js version 1.8.0.1-18-SNAPSHOT, update CaseInsensitiveFileSystem to implement BaseCaseInsensitiveFileSystem * only remove the file from cache inside removeFileCache * fix: nested segment cache + pre-populated listings in CaseInsensitiveFileSystem * update resolveAndCache only cache directory and skip file * add log option to CaseInsensitiveFileSystem, handle deleteRecursively properly * coderabbitai comments --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> Co-authored-by: Jeremy Bernstein <jeremy.d.bernstein@googlemail.com> * chore: re-order downloads & storage tabs (#1079) * Reorder sidebar: Storage Manager first, Downloads second; fix header title on Downloads tab * Default selected tab to Storage Manager * Add downloads_section_title translations for all 13 locales * fix: swap Settings before Downloads in System sidebar * chore: add fexcore 2604 (#1170) Co-authored-by: Phobos665 <5970062+phobos665@users.noreply.github.com> * feat: empty Wine/XDG trash on container shutdown (#1151) * Feat: Update wine-mono version to 11.0.0 in installer scripts (#1133) * feat: update wine-mono version to 11.0.0 in installer scripts * fix: bump_version in ImageFsInstaller.java, will trigger extraction for all existing containers that are on Mono 9.0.0 and install 11.0.0. * Added additional directory for xna msi (#1125) * feat: warn-before-exit preference with double-back confirmation (#993) * Update README.md * fix: match UFS save file globs case-insensitively (#1183) * feat: ludashi style vivid screen effect (#1106) * feat: add fake HDR screen effect * fix: remove quick menu darkening scrim * chore: shorten HDR effect description * refactor: rename HDR effect to vivid mode * i18n: add vivid mode translations * Add GOG force cloud save and related string updates. (#812) * fix: library view not updating after game uninstall (#956) DownloadService caches directory listings for 5s. After deleteApp, the cache still holds the deleted directory, so the subsequent LibraryInstallStatusChanged refresh sees stale data. Invalidate the cache after deletion so the next scan picks up the change. * fix: correct steam game dlc licensing logic and enhance dlc display (#1191) * fix: correct steam game dlc licensing logic and enhance dlc display in content Cross-references resolved depots with owned DLC package information to ensure depots are attributed to the correct DLC app ID. This ensures accurate DLC identification for titles like Don't Starve, Halo MCC, and Cyberpunk 2077. * refactor getMainAppDepots to calculate the logic to be used in getDownloadableDepots * fix: suppress connection banner during initial Steam connect (#918) Also use state.isSteamConnected (Compose-observable StateFlow) instead of SteamService.isConnected (static boolean invisible to recomposition) for banner visibility. * Devil blade reboot utkarsh (#1198) * fix: case-insensitive .exe filter in getWindowsLaunchInfos * removed bug around appLaunchInfo null opening wfm.exe * fixed build * addressed coderabbit * more coderabbit --------- Co-authored-by: Dan Brooke <mail@danbrooke.net> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * fix: Migrate GSE Saves to steam userdata, always upload userdata files to steamcloud (#1100) * migrate GSE Saves to steam userdata, always upload userdata files to steam cloud fix tests * move migrateGSESavesToSteamUserdata just before beginLaunchApp * also migrateGSESavesToSteamUserdata just before forceSyncUserFiles * also migrateGSESavesToSteamUserdata in SteamUtils ensureSteamSettings * use Files.move for migrating files * check dir empty to exit earlier, update logging * preserve file attributes like timestamp and permission during migration * Add reusable INI game fix for Imperivm (#1009) * Add reusable ini game fix for Imperivm * Avoid rereading ini fixes after migration * Remove ini migration marker tracking * feat: disable IME extract UI and centralize singleLine keyboard behavior (#1014) * feat: disable IME extract UI and centralize singleLine keyboard behavior * fix: convert remaining OutlinedTextField to NoExtractOutlinedTextField * fix: preserve file timestamps during Steam Cloud download (#1199) Maintains the original modification time from Steam Cloud for downloaded files. This ensures that games which rely on file timestamps for save loading and ordering, such as Skyrim, function correctly. * feat: added multi-controller support (#1047) * feat: added multi-controller support - physical controller handler services now acommodate multi controller state management via deviceId - new autoassign func - windhandler accomodated MAX_PLAYERS = 4 suppot, multi-controller state management - new MultiControllerTest.kt test suite fix: address multi-controller rumble and device identifier bugs - prevent missed rumble on secondary slots when controller is adopted after a rumble command arrives by deferring the "delivered" marker - remove unreachable vendor/product fallback in device identifier lookup since getDescriptor() is available on all supported API levels revert to original controller manager handling legacy cases and added test case * handled respect disabled slots when reusing an existing assignment * reset rumble state when a slot adopts a new controller * magic number removed using dedicated WinHandler.MAX_PLAYERS const * removed more magic numbers - using dedicated MAX_PLAYERS const and remove null controller phone vibrate case with some docs on why --------- Co-authored-by: = <=> * fix: use container language for install size estimate (#1054) size estimate used PrefManager.containerLanguage (global default) but download uses container.language (per-container). mismatch causes wrong depot count and size when container language differs from default. * feat: FSR 1.0 & Scaling Modes (#1112) * feat: add quick menu fsr and sharpness controls * refactor: port fsr passes from official gpuopen source * feat: add true fsr render-scale upscaling * chore: remove fsr toggle description * refactor: derive fsr input from container resolution * feat: add live scaling modes * chore: move scaling controls to top of screen effects * fix: match default fsr rcas denoise behavior * fix: save quick menu scrim removal before master sync * fix(renderer): only override render target size for scaled scenes * fix: clear stale container state on task swipe and app restart (#1136) * fix: clear stale container state on task swipe and app restart when the user swipes the app from the task switcher while a container is running, keepAlive stays true but xEnvironment is gone. on next launch the app is stuck thinking a container is running. extract shutdownEnvironment() from XServerScreen.exit() so the same full teardown runs in both the normal exit path and the crash recovery path. each step is wrapped in runCatching so one failure doesn't prevent the rest. - onCreate: if keepAlive is set but xEnvironment is null, run shutdownEnvironment() to clear stale state - onDestroy: emit ActivityDestroyed before super (so exit() listeners still fire), then force shutdownEnvironment() if keepAlive persists - exit(): delegates teardown to shutdownEnvironment(), keeps only winHandler.stop() and trash cleanup (container-specific) * fix: stop all foreground services on task swipe when idle Steam/GOG/Epic services had no onTaskRemoved — foreground notification persisted after swipe because nothing told the service to stop itself. * fix: recognize unhandled UFS path types and fix save pattern parsing edge cases (#1157) * fix: recognize WindowsHome UFS root as PathType.Root for cloud save sync Steam PICS can specify `root: WindowsHome` in save file patterns (e.g. Stellar Blade, app 3489700). PathType.from() did not handle this token, causing it to fall through to PathType.None. None.isWindows is false, so the pattern was silently dropped in getLocalUserFilesAsPrefixMap and the saves were never scanned or synced. WindowsHome is the Windows user home directory (C:\users\xuser\ in Wine), which is exactly what PathType.Root maps to. Fix by recognising "windowshome", "%windowshome%", and "root" in PathType.from() as Root, and adding Root to the isWindows set so it passes the save pattern filter. * fix: recognize SteamCloudDocuments UFS root as WinMyDocuments for cloud save sync Steam PICS can specify `root: SteamCloudDocuments` in save file patterns (e.g. Sonic Mania, app 584400). PathType.from() did not handle this token, causing it to fall through to PathType.None and be silently dropped during save pattern filtering. SteamCloudDocuments is Steam's name for the user's Documents folder, which maps to WinMyDocuments (C:\users\xuser\Documents\) in Wine. Fix by recognising "steamclouddocuments" and "%steamclouddocuments%" in PathType.from() as WinMyDocuments. * fix: normalize '.' save path to empty string to prevent broken cloud keys Steam PICS manifests sometimes use `path: .` to mean "root of this path type, no subdirectory" (common in Unity games). When a Windows rootoverride also has a non-empty addpath, the dot was appended literally — producing paths like "Thunder Lotus Games/Spiritfarer/." and uploadPath = "." — which caused cloudPrefixToLocalPath to build a key like "%GameInstall%." that never matches the bare "%GameInstall%" prefix the cloud API returns, so downloaded files landed in the wrong directory. Fix by normalising "." to "" at parse time in KeyValueUtils, consistent with how UserFileInfo.prefix already treats cloudPath == ".". Affected games: Spiritfarer and CrossCode. * fix: recognize WinProgramData and SteamUserBaseStorage UFS path types, handle oslist in rootoverrides - Add WinProgramData PathType mapping to drive_c/ProgramData/ - Alias SteamUserBaseStorage to SteamUserData in PathType.from() - Check oslist field alongside os when filtering Windows rootoverrides * fix: bump CURRENT_UFS_PARSE_VERSION to 2 to force re-parse of cached UFS data Ensures existing cached SteamApp rows are re-parsed to pick up the path normalization and oslist rootoverride fixes from this branch. * fix: lowercase Root/ROOT_MOD aliases and add wrapped %root% form in PathType.from() * fix: add %steamuserbasestorage% as suggested by coderabbit * fix: perf hud fps fix for other wrappers (#1164) * fix(hud): measure fps from render frames * fix(hud): track fps against topmost app window * Fix silent cloud save overwrite when sync cache is missing (#1169) * fix: show conflict dialog when cloud sync cache is missing, regardless of change number the old gate (localAppChangeNumber >= 0) skipped the conflict dialog for first-time offline players whose change number is -1. this meant local saves were silently overwritten by cloud on reconnect. remove the gate: if cache is absent and local files exist, always treat as conflict. * test: cloud sync decision matrix covering all cache/CN/cloud states 12 scenarios covering: cache present/absent, local changes/none, cloud ahead/same, preferred save location, first-time offline play. also fixes existing download test (cloud filenames, mock params, deprecated API). * fix: split cache-absent conflict into upgrade vs first-offline cases * test: revert modifications to existing tests, keep only new additions * fixed steam intent launches, no need to check for offline mode * Added option to toggle button hints bar (#811) * fix crashes on migrateGSESavesToSteamUserdata (#1207) * GOG chunk URL broken when CDN token is in query string (#1215) * Update CONTRIBUTING.md to reduce ambiguity * Update pull_request_template.md to reduce ambiguity * Jb/streaming assembly utkarsh (#1219) * feat: streaming download+assembly for Epic/GOG to reduce disk usage replace two-phase (download all chunks → assemble all files) with a unified loop that assembles files front-to-back as their chunks land and deletes consumed chunks immediately. peak disk usage drops from ~2x install size to ~1x. - StreamingAssembly: shared pure logic for chunk ordering, last-file tracking, readiness checks, and safe deletion decisions - EpicDownloadManager: downloadAndAssembleEpicChunks replaces separate download+assembly phases for both base game and DLC - GOGDownloadManager: downloadAndAssembleChunks with secure link refresh, used by both main game and dependency downloads. removed dead downloadChunksSimple and assembleFiles. - 14 unit tests covering ordering, deduplication, shared chunks, cleanup safety, and full batch-loop simulations * fix: run final assembly pass for zero-chunk Epic files mirrors the GOG fix — when all files have zero chunks, the chunk loop never executes and assembly never runs without a trailing pass. * fix: allow all-zero-chunk Epic manifests to reach assembly * Resolved conflicts, sped up GOG, made resuming downloads for GOG work better, made downloading UI progress smoother * handle retries correctly for assembly for GOG * addressed coderabbit comments * More AI fixes --------- Co-authored-by: Jeremy Bernstein <jeremy.d.bernstein@googlemail.com> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Aligned epic downloads to GOG to make it faster from eg India (#1220) * Aligned epic downloads to GOG to make it faster from eg India * coderabbit comments, removed xserverscreen mistake changes --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Revert "feat: added multi-controller support (#1047)" (#1224) This reverts commit 2334981. * Create ROADMAP.md * Update ROADMAP.md * tests: Added unit tests for new key parts of Gamenative (#1143) * Added launch dependency tests * Added game fix registry tests * Added preinstall step tests * Some AI improvements + moved gamefixes tests to new types folder * Added test to keep canonical root at the correct location (#1144) * fix: preserve aspect-correct viewport for screen effects (#1213) * Create pr-label-command.yml * Recommendation page (#1235) * Added recommendations to game page + library, added toggle to hide recommendations, * Added review scores to recommended games * Added date to recommended app screen like the others * coderabit comments --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * fix: skip spurious conflict when cache lost but local==remote (#1228) destructive db migration wipes file_change_lists cache, making every steam game trigger conflict on first launch post-update. check if local state is byte-identical to remote manifest (by filename + SHA) before declaring conflict; if so, rehydrate cache and report UpToDate silently. also populates real timestamps on the genuine-divergence path (was showing epoch). test: dbCleared_localMatchesRemote_rehydratesSilently_noConflict * chore(): openApi specs for Gog, Epic & Amazon (#1234) * chore(): openApi specs for Gog, Epic & Amazon * chore(): Update the epic token to look more fake. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * added toggle to disable posthog tracking (#1236) * added toggle to disable posthog tracking * Updated readme to include analytics info --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * refactor: Moved Proton downloading to launch deps (again, but mirroring original behaviour + tests) (#1052) * Reapply "Refactored default Proton downloads to launch deps" (#1050) This reverts commit 1cd84b4. * Moved proton download to original location by moving launch deps call * Removed deletion since previously we didnt do that either. * Added test for new launch dep * Added codeonwers file * fix(): toggle showing achievements (#1251) * fix(): toggle showing achievements * fix(): fixed imports and state on settings. Testing now. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: mouse movement in games that use raw mouse input and clipcursor (#1084) * refactor: register X extensions with event and error id assignment * add writeFP3232 to XOutputStream * feat: add XInput2 Extension and associated events * Implement ClipCursor behavior and fix XWarpPointer to include soft margin in the window calculations * add logging to help extension debugging * fix: correct confinement off by one * fix: throw BadValue if no mask as per XI2 spec * fix: change Bitmask to hold 64 bits to be able to read XI2 masks * More fallout game fixes (#1134) * fix: reject config with missing components, show dialog with apply-anyway option (#801) * fix: reject config with missing components, offer apply-anyway with defaults * fix: pass storeMatch to force-apply path for cross-store configs * Added kingdom hearts 3 (EPIC) gamefix (#1161) * feat: Add Steam save import and export actions (#966) * Add Steam save import and export actions * fix: harden Steam save import and export * fix: correct manifest driver id * fix: stabilize Steam save archive roots * fix: make Steam save root ids collision resistant * fix: simplify Steam save transfer to userdata * feat: add multi-root save discovery and translations * refactor: use string resources for app option menu labels * Workshop Update: Manual Mod Folder Dialog (#1072) * Workshop Update: Manual Mod Folder Dialog - Full-screen workshop manager dialog with hero image, mod list, select-all/deselect-all, and per-mod toggle switches - FolderPickerDialog for manually choosing mod installation paths when automatic detection fails - Improved mod path detection: binary scanning, config file parsing, AppData walking with fuzzy matching - CKM (Creation Kit Module) extraction for Skyrim mods - LZMA decompression with concurrent processing - ZIP extraction for single-archive workshop uploads - Magic-byte file type detection and extension fixing - Disk space checking before downloads - allSelected derivedStateOf optimization (removed wasteful toMap key) - Added KNOWN_EXTENSIONS to WorkshopItem for file type validation * Fix folder picker breadcrumb for multi-level paths * Guard folder picker directory listing with try/catch/finally * Rethrow CancellationException in folder picker LaunchedEffect * feat: task manager from qam (#1121) * feat(quick-menu): replace tools tab with task manager launcher * feat(quick-menu): show running exe memory usage * feat(ui): streamline quick menu task manager * refactor: inline process user lookup in ProcessHelper * fix/feat: extract XAudio DLLs from DirectX redistributables (#1184) * feat: extract XAudio DLLs from DirectX redistributables Adds support for decompressing and installing DirectX audio components (XAudio, XACT, X3DAudio) from game cabinet files into the Wine prefix. This uses 7-Zip bindings to extract the necessary DLLs to system folders, helping resolve audio compatibility issues in games that rely on specific redistributable versions. * refactor replaceXAudioDllsFromRedistributable to XServerScreenUtils add other gamesource detection * fix gameId detection * surround gameId detection with try catch * update use FileOutputStream for dll extraction * add log when appDirPath detection failed * move SevenZip init outside per file function * ai comments * only apply for proton 10, fix proton 9.0 compatibility * revert SteamUtils changes * fix directXDir detection logic * fix directXDir detection logic * update proton 10 logic * fix: kill stale wine processes before launch (#1195) * fix: kill stale wine processes before launch * fix: wait for stale wine processes to exit * fix: block back during prelaunch loading * refactor: move stale wine process kill logic to ProcessHelper * fix: GOG cloud save fetch failure handling (#1201) * Fix GOG cloud save fetch handling * Add GOG cloud save regression tests * Clarify GOG cloud save fallback comment * feat: Parallelize Steam cloud save downloads (#1226) * Refactor Steam cloud download flow No logic changes. Extract the per-file download body from the forEach loop in downloadFiles into a new private downloadSingleFile function to make the upcoming parallelisation diff easier to read. The httpClient is moved from steamInstance.steamClient.configuration.httpClient (pulled inline) to a parameter so the caller controls which client to use. * Parallelize Steam cloud save downloads Replace the sequential forEach loop in downloadFiles with a coroutineScope { map { async { semaphore.withPermit { ... } } }.awaitAll() } pattern, capping concurrency at PrefManager.downloadSpeed via a Semaphore. A dedicated OkHttpClient is created per sync via Net.httpForParallelDownloads so each parallel call gets its own Dispatcher thread pool. filesDownloaded and bytesDownloaded are promoted from plain vars to AtomicInteger and AtomicLong to handle concurrent updates safely. Per-file streaming progress is added: downloadedRawBytes (incremented per chunk via a CAS loop) drives onProgress during the download, while a separate lastReportedPercent AtomicInteger deduplicates callbacks so only strictly increasing percentages are emitted. The upfront indeterminate "Downloading filename" callback is removed in favour of this. downloadSingleFile gains httpClient, totalRawBytes, downloadedRawBytes, lastReportedPercent, completedFiles, totalFiles, and progressMessage parameters to support the above. The unused steamInstance parameter is removed. copyTo now returns total bytes read and passes chunkBytes to the progress callback. Adds steam_cloud_sync_downloading_save_files string to all 14 locale files for the X/Y files in-progress message. * Fix cloud save download edge cases Wrap the connection phase (httpClient.newCall.execute) in a try/catch for SocketTimeoutException and IOException, returning null on failure instead of propagating an uncaught exception. Capture the withTimeout(responseTimeout) block as a Boolean result and return null if the response body stream was absent. Previously a null body silently completed without writing any file; now both the compressed and uncompressed paths guard with ?: return@withTimeout false. Move response.close() to a finally block so it fires on every exit path. Remove the redundant explicit close that was on the !isSuccessful path. Fix UserFilesDownloadResult to report rawFileSize (uncompressed bytes) instead of fileSize (compressed bytes). The mismatch caused bytesDownloaded to undercount for compressed files and allowed the download progress to transiently exceed 100%. Emit "Download complete" unconditionally after awaitAll() rather than only when filesDownloaded == totalFiles, so a partial failure no longer stalls the UI at the last reported percentage. Add IOException and SocketTimeoutException catches inside the streaming try block (distinct from the outer connection-phase catches) with a shared finally for response.close(). * Fix cloud save download robustness issues Close response on unsuccessful HTTP to prevent connection leaks, catch TimeoutCancellationException so one download timeout doesn't cancel all parallel downloads, treat short reads as failures and clean up partial files, and only report "Download complete" when all files succeeded. * fix: address Steam cloud review feedback Handle Steam cloud metadata fetch failures per file without swallowing coroutine cancellation, so the reviewed exception path no longer cancels sibling downloads while structured cancellation still works correctly. Also tear down the per-sync Steam cloud download client after the batch completes to release dispatcher threads and pooled connections, while keeping failed-download file handling aligned with current master behavior. * fix: use stored installPath in GOGManager.deleteGame to prevent uninstall failures (#1255) * added new turnip drivers to manifest (#1263) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * chore(): add new box64 to GN. (#1262) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Revert "fix/feat: extract XAudio DLLs from DirectX redistributables (#1184)" (#1266) This reverts commit 3a4cb3d. * Added some changes for rockstar launcher (#1274) Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Updated manifest to include new protons (#1275) * Updated manifest to include new protons * Fixed manifest values * fixed proton 10 x86-64 id --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * Added THIRD_PARTY_NOTICES * feat/refactor: Improve GOGDownloadManager download efficiency (#1277) * refactor: Improve GOGDownloadManager download efficiency 1. Adopt Flow queuing concept from JavaSteam 2. add DownloadSpeedConfig to be used later for other store enhancement 3. update kotlinx-coroutines-core version to match JavaSteam version using 4. Update NetworkUtils httpForParallelDownloads for timeout and http protocol config * ai comments * add retry logic when same pendingChunks appear 10 times in a row * fix: extract XAudio DLLs using native cabarc instead of 7-Zip binding (#1269) * Reapply "fix/feat: extract XAudio DLLs from DirectX redistributables (#1184)" (#1266) This reverts commit 93793fa. * fix: extract XAudio DLLs using native cabarc instead of 7-Zip binding Replaces the 7-Zip JBinding library with a Wine-based batch script that uses the native cabarc utility to extract DirectX DLLs. This removes the dependency on JitPack and the external 7-Zip library while maintaining the fix for Proton 10. * ai comments * ai comments * ai comments, refactor to XAudioUtils * guard batchCommand with BATCH_SUCCESS_CHECK * move guard code location after all extraction * remove useless comment * add splash text when extracting dlls * fix(workshop): force standard Steam UGC path for Tale of Immortal (#1260) - Add AppID 1468810 (Tale of Immortal) to `forceStandardAppIds` to ensure workshop items are handled via the standard ISteamUGC path. * Move Touchscreen Mode toggle to in-game sidebar (#1249) Moved Touchscreen Mode toggle from Edit Container > Controller section to the in-game sidebar, right below the existing Edit On-screen Controller line. Added gear icon for gesture settings that appears when touchscreen mode is active. * fix: late release single tap in touchscreen mode to fix clicking in some games (#1212) * fix: late release single tap in touchscreen mode to fix clicking in some games * fix: immediately release click before a new single tap * clear delayedPress state after execution * flush pending single tap release on handleTsDown * Update README.md * feat(): Silly draft for ideation of EOS. * Added sidecar for EOS, made downloading EOS launch dependency, Deliver at all Costs working * addressed AI comments * fix: gog download pause / resume handling logic * fix unit test * revert downloadChunk logic on md5 checking before downloading file * Made layouts for appscreen and libraryscreen cutout/notch aware * Merge pull request #1300 from utkarshdalal/unpack-more made unpack files more aggressive * fix: resolve cloud save path for Danganronpa 2 (app 413420) (#1297) Danganronpa 2 stores saves in WinMyDocuments/My Games/Danganronpa2/ via a Windows rootoverride, but GameNative was placing downloaded cloud saves in the game install directory instead, so the game never found them. Two bugs fixed: 1. KeyValueUtils: treat PICS path '/' as empty (same as '.') A lone forward-slash means 'root of this path type' with no subdir. Keeping the literal '/' caused uploadPath='/' which put a trailing slash on the cloudPrefixToLocalPath map key ('%GameInstall%/') while the lookup trimmed it ('%GameInstall%'), causing a miss. With the fix, uploadPath='' and path='My Games/Danganronpa2' (no trailing slash). Also bumps CURRENT_UFS_PARSE_VERSION 2->3 to force cache refresh. 2. SteamAutoCloud getFullFilePath: consult cloudPrefixToLocalPath when Steam embeds the placeholder in the filename (prefix=[], filename='%GameInstall%savedata.vfs'). The previous early-return hardcoded the destination as the game install dir, bypassing all rootoverride remapping. Now checks cloudPrefixToLocalPath['%GameInstall%'] first so the file lands in WinMyDocuments/My Games/Danganronpa2/. Also adds .trimEnd('/') to cloudKey construction in cloudPrefixToLocalPath so map keys are always slash-free (matching the existing lookup behaviour). Tests added: - KeyValueUtilsTest: danganronpa2SlashPathWithWindowsRootOverrideIsNormalizedToEmpty - SteamAutoCloudTest: downloadWithEmbeddedGameInstallPrefixUsesRootoverrideLocalPath - keyvalues/Danganronpa 2 Goodbye Despair.txt: PICS reference documentation * fix/tabbar-scrolling-clip (#1293) * fix: copy a new dll generated with proton 11 (#1287) * fix: open download details fullscreen (#1270) * fix: repair steam save export (#1265) * feat: move Disable Mouse Input to in-game Quick Menu overlay (#1267) * feat: move Disable Mouse Input to in-game Quick Menu overlay Removes the Disable Mouse Input toggle from the container settings Controller tab and adds it to the in-game Quick Menu, where it can be toggled during gameplay without leaving the game. State is persisted to the container config on toggle. * fix: address code review feedback - Remove unconditional setCursorVisible call; cursor state is managed by existing pointer-availability logic and should not be overridden when a physical mouse may be present - Key isDisableMouseInput state to container.id to prevent stale state if container changes * fix: restore cursor visibility on mouse input toggle Show cursor when re-enabling mouse input (unless touchscreen mode is also active), hide it when disabling. Required for touch-as-mouse users who have no physical pointer device. * fix: use mouse icon and pink accent for Disable Mouse quick menu item * fix: join prealloc job before polling so zero-chunk files are created before return (#1308) * fix: use consistent purple accent color for all quick menu items (#1311) * Stop overwriting wine prefix when switching between containers of dif… (#1310) * Stop overwriting wine prefix when switching between containers of different variants/archs, only extract xaudio dlls once * do reinstall of mono and preinstallsteps on wine version change (not arch), fixed bugs with wincomponents, audio driver, and startup selection being overwritten on wine version change --------- Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> * fix: soften boot splash hero backdrop * fix: resolve boot splash hero image off main thread * made booting splash image greyscale background instead of having inconsistent color that doesn't gel with GN --------- Co-authored-by: xXJsonDeruloXx <danielhimebauch@gmail.com> Co-authored-by: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> Co-authored-by: Luboš V. <tridosm@gmail.com> Co-authored-by: UnbelievableFlavour <bart.zaalberg@shift2.nl> Co-authored-by: Joshua Tam <297250+joshuatam@users.noreply.github.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Jeremy Bernstein <jeremy.d.bernstein@googlemail.com> Co-authored-by: Phobos665 <5970062+phobos665@users.noreply.github.com> Co-authored-by: CatPotatos <catarinaleal123@gmail.com> Co-authored-by: AnikethanVA <82267223+AnikethanVA@users.noreply.github.com> Co-authored-by: Dan Brooke <mail@danbrooke.net> Co-authored-by: Misazam <60115666+Misazam@users.noreply.github.com> Co-authored-by: bllendev <113651082+bllendev@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: André Vitor <90573731+AndreVto@users.noreply.github.com> Co-authored-by: Nightwalker743 <Hillardjoseph43@gmail.com> Co-authored-by: linkq <mrlinkq@hotmail.com> Co-authored-by: Daniel Joyce <danielalexanderjoyce@gmail.com> Co-authored-by: tlt21 <travistryba@gmail.com> Co-authored-by: Almond <88301593+sdkahal@users.noreply.github.com> Co-authored-by: Ben Pearson <ben@buriza.co.uk> * Removing Comments like wanted in Codereview --------- Co-authored-by: Utkarsh Dalal <dalal.utkarsh@gmail.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: xXJsonDeruloXx <danielhimebauch@gmail.com> Co-authored-by: Kurt Himebauch <136133082+xXJSONDeruloXx@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Utkarsh Dalal <utkarsh.dalal@toptal.com> Co-authored-by: Luboš V. <tridosm@gmail.com> Co-authored-by: UnbelievableFlavour <bart.zaalberg@shift2.nl> Co-authored-by: Joshua Tam <297250+joshuatam@users.noreply.github.com> Co-authored-by: Jeremy Bernstein <jeremy.d.bernstein@googlemail.com> Co-authored-by: Phobos665 <5970062+phobos665@users.noreply.github.com> Co-authored-by: CatPotatos <catarinaleal123@gmail.com> Co-authored-by: AnikethanVA <82267223+AnikethanVA@users.noreply.github.com> Co-authored-by: Dan Brooke <mail@danbrooke.net> Co-authored-by: Misazam <60115666+Misazam@users.noreply.github.com> Co-authored-by: bllendev <113651082+bllendev@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: André Vitor <90573731+AndreVto@users.noreply.github.com> Co-authored-by: Nightwalker743 <Hillardjoseph43@gmail.com> Co-authored-by: linkq <mrlinkq@hotmail.com> Co-authored-by: Daniel Joyce <danielalexanderjoyce@gmail.com> Co-authored-by: tlt21 <travistryba@gmail.com> Co-authored-by: Almond <88301593+sdkahal@users.noreply.github.com> Co-authored-by: Ben Pearson <ben@buriza.co.uk>
Description
adds
NoExtractOutlinedTextFieldwrapper that setsIME_FLAG_NO_EXTRACT_UI, opting out of the IME's fullscreen extract editing mode. centralizesImeAction.Done+clearFocus()forsingleLinefields, removing per-callsite boilerplate. migrates allOutlinedTextFieldusages across the app (11 files).closes #1013.
Recording
before:
https://github.com/user-attachments/assets/c195692d-3120-44bb-8221-a6fc94844d3e
after:
https://github.com/user-attachments/assets/b96dcd62-6adc-4b44-a26c-66b3969b2695
Test plan
Checklist
#code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.CONTRIBUTING.md.Summary by CodeRabbit
New Features
Refactor