Compare commits

..

40 Commits

Author SHA1 Message Date
xbzk fc2569a724 [android,ui] background support 2026-03-08 16:58:52 -03:00
xbzk 7a17fd8c71 [android,ui] chore: minor standardization layout (#3694)
Amost no visual differences, but tons of layout cleanups and fixes
Most notable change, Freedreno option only show on Adreno GPUs

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3694
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-08 16:16:23 +01:00
xbzk 9423a33fc2 [android,ui] fix addons list not refresh upon rotation (#3687)
Fixes a bug reported by Pavel, in which an RC as returning empty patchList after phone rotated.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3687
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-08 00:41:40 +01:00
lizzie afec66f598 core/hle/services/audio] Fix audioctl being started before audout/audin (which are required for ctor) (#3695)
`audctl` depends on `audout`, simply start `audout` and `audin` before!

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3695
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-07 23:44:58 +01:00
SchweGELBin a022560991 [desktop] tas: add option to disable file overwrite dialog (#3657)
Hello everybody, thank you for letting me participate in the development of the Eden emulator!

I've been playing around with the TAS functionality and didn't want to always click "Yes" in the dialog that askes if I want to "Overwrite file of player 1?" after recording the inputs.
So I can't record and play TAS files with keybinds only, because I'd still need to switching from my contoller to my keyboard and back.

So I added the option "Show recording dialog" into the configure_tas screen.
(The final naming and string can be changed of course.)
It's a checkbox that is enabled by default (so no changes if ignored), but can be unchecked to disable the popup.
The change has been tested on top of the current master branch.

I've also created a commit to add the relevant translation data, where german is translated and the rest unfinished.
I'm not sure how this would be handled as this project uses transifex for it localization, so I can remove this commit if preferred.

Have a great day!
- Michi

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3657
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: SchweGELBin <abramjannikmichael06@gmail.com>
Co-committed-by: SchweGELBin <abramjannikmichael06@gmail.com>
2026-03-07 20:08:47 +01:00
lizzie 11ad71b1e7 [docs] Obtanium, installing mods, external ES-DE config, section about CFW and settings (#3678)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3678
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-07 18:16:05 +01:00
xbzk ddac8c8eb5 [vk] fix crash introduced in 9a07bd0570 (#3685)
Fix for current crash on master.
Just reverted only the necessary stuff so that PresentManager can hold a reference to khr and resist death upon application hold/restore.
@Lizzie shall judge.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3685
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-06 19:52:17 +01:00
lizzie c062931c9b [qt] add translation table entry for debug_knobs,serial_battery and serial_unit (#3682)
trivial qt change

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3682
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-06 16:38:39 +01:00
crueter e4122dae1d [desktop] addons: open mod folder in rc menu (#3662)
also fixed the multiselection being absolutely horrendous

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3662
2026-03-06 16:38:21 +01:00
lizzie b75e81af5e [video_core/engines] implement stub NV01 timer, inline other channel engines (#3640)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3640
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-06 15:05:39 +01:00
lizzie 2ed1328c93 [vk] use static_vector instead of small_vector for TFB and other bindings (#3641)
MK8D is a big offender, taking up lots of time memcpy'ing and memmov'ing small_vector<> AND to add salt to the wound it doesn't even do heap allocations (no game does I think) - so basically useless waste of compute time in hot path for NO reason :^)

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3641
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-06 15:05:05 +01:00
lizzie c70b857c4f [video_core/engines] Macro HLE inline (#3653)
Should slightly boost perf on android, Desktop is mainly unaffected (for now)

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3653
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-06 15:04:38 +01:00
MaranBr 23566a1f7d [prepo] Add support for missing PlayReport commands (#3674)
This fixes:

`[ 433.095195] Debug <Critical> core\hle\service\service.cpp:operator ():69: Assertion Failed!
Unknown / unimplemented function '10107': port='prepo:u' cmd_buf={[0]=0x110006, [1]=0x80000014, [2]=0x1, [3]=0x0, [4]=0x0, [5]=0x191080, [6]=0x5A7350F8, [7]=0x112, [8]=0x5A735158}`

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3674
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2026-03-06 15:02:59 +01:00
xbzk 529b069499 [android,ui] fixed top disalignment between buttons of each column in settings fragment (#3675)
this silly little thing tickles obsessive compulsive disturbed fellas a lot hu3
was shipped along PR 3660, which was rediscussed for other reason, hence this tiny lonely PR.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3675
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-05 13:58:46 +01:00
lizzie 9a07bd0570 [vk] unify VkSurfaceKHR with Android and the rest of platforms; remove technically incorrect nullptr() ctor for handles (#2971)
Removes some odd #ifdef-ing that just can use a shrimple opaque type.

Also removes nullptr() ctor'ing for vulkan handles and such; it's not incorrect per se like how `void *p = 0;` isn't incorrect, just that, y'know, any static analyzer will go "woah". Also there isn't any guarantee that handles `sizeof(Handle) == sizeof(void*)` so may as well :)

Signed-off-by: lizzie lizzie@eden-emu.dev

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2971
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-05 07:32:18 +01:00
xbzk 05f6942bef [android, ui] fixed setting reset to defaults infinite loop (#3659)
fixed a bug discovered by Pavel in which the settings' "reset to defaults" dialog would get stuck in a infinite loop, due to a recall prior to cleaning state.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3659
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-05 00:58:49 +01:00
nekle 70c1e9abed [android] Try and fix SD Card storage mount points for external paths (#3436)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3436
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: nekle <nekle@protonmail.com>
Co-committed-by: nekle <nekle@protonmail.com>
2026-03-05 00:56:25 +01:00
wildcard 69e47bd2c0 [vulkan] Fix wrong stage index in prepare_stage render area check (#3672)
The OpenGL correctly uses const auto& info{stage_infos[stage]};

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3672
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-03-05 00:54:48 +01:00
wildcard cdf9b556b2 [vulkan]fix vuid 02751 (#3573)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3573
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-03-05 00:54:26 +01:00
xbzk 7f5de6bcd6 [android/fs] external content loader + nca/xci patches (#3596)
Foreword: WHY DON'T EVERYBODY USE ONE FOLDER FOR EACH GAME+CONTENTS? AIN'T THIS THE FORMAT GAMES COME WHEN YOU BUE THEM? DO YOU LIVE WITH ALL YOUR FRIENDS AND HAVE A 2ND HOUSE FOR ALL THE CHILDREN?

Nice, i feel better now.

This feat extends Maufeat's work on external content loading. It harmonically additions:
"...also, if in each game folder X, you find a folder Y, and in this folder Y you detect ONLY a single game, then mount all external content for that game found in that folder Y and its subfolders."
Permanent (not toggleable). External Content folders are supported equally.

Also:
-Reworked several routines for preserving single source of truth between android and other systems;
-Fixed the annoying unknown format error for content files, by providing proper format detection.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3596
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-04 22:51:35 +01:00
wildcard c682306788 [vulkan] Implement push descriptors for compute pipelines (#3666)
Implements push descriptor for compute pipelines along with a bug fix, the increment logic was, offset += sizeof(DescriptorUpdateEntry);
This only advances the byte offset by a single descriptor slot, regardless of the array's size (descriptorCount).Now suppose if a shader utilized an array of descriptors (eg, layout(binding = 0) uniform sampler2D textures[4]) and if this happened to fit within the MaxPushDescriptors limit, the template would consume 4 * sizeof(DescriptorUpdateEntry) bytes, but the offset for the next binding would only advance by 1 slot.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3666
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-03-04 22:46:55 +01:00
PavelBARABANOV 9d2341eaea [vk] Disable float16 math on non-MESA AMD drivers as 2026+ versions are broken (#3661)
thanks MaranBR

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3661
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Co-committed-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
2026-03-03 14:27:47 +01:00
tarako d720a7b4b4 [vulkan] Fixed dual-source blending to correctly map shader outputs. (#3637)
Fixes Skyward Sword HD eye gitch and a related MoltenVK crash due to the incorrect output mapping. Verified working on mac and android.

The test in vk_pipeline_cache.cpp is a bit ugly, but it didn't seem worth it to go lambda/macro just to make it look cleaner. Could change if necessary.

Co-authored-by: tarako <none@none.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3637
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: tarako <r76036296@gmail.com>
Co-committed-by: tarako <r76036296@gmail.com>
2026-03-03 01:54:57 +01:00
crueter 464212393e [gitignore] add *.tar.zst (#3663)
the amount of times I've accidentally committed a tar.zst to this
repository...

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3663
2026-03-02 05:28:26 +01:00
MaranBr ea209e6dab [vulkan] Fine-tuning of frame pacing logic (#3628)
It makes fine adjustments to the frame pacing, ensuring better stability and precision.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3628
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2026-03-02 02:53:01 +01:00
MaranBr b5f9f8b743 [vulkan] Fix Vulkan rendering, image layout, and synchronization issues (#3511)
This fixes a visual corruption issue that occurred intermittently after loading screens, where some games would start the scene with vertex explosions, artifacts or with all colors blown out, resembling neon.

Among the known games affected by this bug are Mario Kart 8 Deluxe, The Legend of Zelda: Breath of the Wild, The Legend of Zelda: Tears of the Kingdom, Kirby and the Forgotten Land, Luigi's Mansion 3, Xenoblade Chronicles 3 and possibly others as well.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3511
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2026-03-02 02:51:50 +01:00
xbzk a8fc994c0b pr3655 gradientbordercardview fix (#3658)
This complements PR3655, where a change in theme setting caused gradientbordercardview theme color setting mismatch.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3658
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-01 23:21:26 +01:00
lizzie 2991bd18ef [vk] Enable VK_IMG_filter_cubic on powervr (#3643)
in powervr, the enum for cubic filtering is an alias for an ext, however in true powervr fashion they want you to use their stupid VK_IMG

and knowing powevr it probably bugs out if you dont

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3643
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-01 01:53:15 +01:00
lizzie 281d7a468e [ports] Remove ENABLE_OPENSSL and mbedtls nixos remnants (#3638)
shell.nix still had references to mbedtls

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3638
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-01 01:53:04 +01:00
PavelBARABANOV 12f89745be [android] add IntSetting for static theme and set green as default (#3655)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3655
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Co-committed-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
2026-02-28 19:34:55 +01:00
xXJSONDeruloXx 7de5eb6884 [android] fix persist manual game pause after android sleep/wake (#3651)
if user invokes the "pause game" option from the menu while in game, as expected this suspends the process till user manually hits resume.. except for one case: Android sleep/wake lifecycle.

If user manually pauses a running game, then sleeps their device, then wakes their device; the game will self-resume without user pressing "resume game".

Expected behavior IMO is that if user left the game process in manually paused state, app should respect this and persist the pause on system wake, so that user may manually press "resume game" to unfreeze the process.

Simple fix is to have a few params for user initiated pause and resume, and update the pause and run methods to handle as described above.

Please let me know if there is a cleaner way to implement!

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3651
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: xXJSONDeruloXx <danielhimebauch@gmail.com>
Co-committed-by: xXJSONDeruloXx <danielhimebauch@gmail.com>
2026-02-28 16:05:06 +01:00
John ac181b756f [Config] Update Rescale Toggle Description to Include Intel GPUs (#3650)
The toggle hack has benefits for Intel GPU users in Luigi Mansion 3 as they also suffer from line artifacts.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3650
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: John <john@eden-emu.dev>
Co-committed-by: John <john@eden-emu.dev>
2026-02-28 01:07:40 +01:00
smiRaphi 4a833e7206 [desktop] port IR Camera to Qt6 & fix camera saving on windows (#3630)
The camera was previously saved without escaping the name which made the values unusable after a settings load, for whatever reason replacing the backslashes when saving with / doesn't work but replacing them with | does.

Also note that the OBS virtual cam (and any other cameras that only have directshow drivers) won't work because Qt6 dropped support for that and the ffmpeg backend doesn't seem to support it either.

Closes #3468

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3630
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: smiRaphi <neogt404@gmail.com>
Co-committed-by: smiRaphi <neogt404@gmail.com>
2026-02-28 01:06:59 +01:00
lizzie 06a08de68a [core/loader] prevent program_image reallocations in NSO+KIP loading methods (#3639)
also changes some methods to std::span<> as well, but mainly std::vector<> in the NSO/KIP loading stuff is not needed to be memcpy'ed and memmove'd around
this should save a marginal amount of loading time (RDR1)

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3639
Reviewed-by: DraVee <dravee@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-02-28 01:06:33 +01:00
JPikachu f8712e50e6 [audio] stub SetAudioDeviceOutputVolumeAutoTuneEnabled and IsAudioDeviceOutputVolumeAutoTuneEnabled (#3654)
For Pokémon LeafGreen Version and Pokémon FireRed Version

Co-authored-by: JPikachu <jpikachu.eden@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3654
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: JPikachu <jpikachu@eden-emu.dev>
Co-committed-by: JPikachu <jpikachu@eden-emu.dev>
2026-02-28 01:06:22 +01:00
crueter fc63de39dd [docs] Bring back the Options page, and clean up LLM policy (#3649)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3649
2026-02-27 03:33:36 +01:00
crueter bf25058dbd [docs] SIGNUP: Add spam/junk notice, email patch info, and clarify some things (#3648)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3648
2026-02-27 03:33:29 +01:00
lizzie 75104b6103 [hle] Implement IApplicationManagerInterface::GetTotalSpaceSize (#3642)
oops

Signed-off-by: lizzie <lizzie@eden-emu.dev>

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3642
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-02-26 16:48:04 +01:00
John 0d950195e9 [Settings] Add "Enable Legacy Rescale Pass" Toggle (#3582)
This PR introduces an optional Legacy Rescale Compatibility Mode that restores the previous rescale‑pass behavior for titles that rely on its quirks. While the new rescale logic is generally more correct, some games exhibit visual issues that the legacy behavior incidentally avoids.
Enabling this mode can mitigate line artifacts on AMD GPUs and reduce grey‑texture flickering on Nvidia GPUs in Luigi’s Mansion 3. This is a compatibility workaround rather than a full fix, and should only be used for titles affected by these rare edge‑case rendering problems.

Original Logic from MaranBR

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3582
Co-authored-by: John <john@eden-emu.dev>
Co-committed-by: John <john@eden-emu.dev>
2026-02-26 03:57:25 +01:00
PavelBARABANOV 04e88ab82c [qt] Remove QEvent::Polish from titlebar filter to fix Applets tab (#3644)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3644
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
Co-committed-by: PavelBARABANOV <pavelbarabanov94@gmail.com>
2026-02-26 03:15:32 +01:00
191 changed files with 4237 additions and 2439 deletions
+1
View File
@@ -63,3 +63,4 @@ artifacts
*.AppImage*
/install*
vulkansdk*.exe
*.tar.zst
+7 -7
View File
@@ -70,7 +70,7 @@ endif()
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
option(ENABLE_UPDATE_CHECKER "Enable update checker (for Qt and Android)" OFF)
# option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
cmake_dependent_option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF "NOT YUZU_USE_BUNDLED_QT" OFF)
cmake_dependent_option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF "NOT YUZU_USE_BUNDLED_QT" OFF)
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
@@ -577,9 +577,9 @@ if (ENABLE_QT)
find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets Charts Concurrent)
# if (YUZU_USE_QT_MULTIMEDIA)
# find_package(Qt6 REQUIRED COMPONENTS Multimedia)
# endif()
if (YUZU_USE_QT_MULTIMEDIA)
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
endif()
if (PLATFORM_LINUX OR PLATFORM_FREEBSD)
# yes Qt, we get it
@@ -618,9 +618,9 @@ if (ENABLE_QT)
if (PLATFORM_LINUX)
list(APPEND YUZU_QT_COMPONENTS DBus)
endif()
# if (YUZU_USE_QT_MULTIMEDIA)
# list(APPEND YUZU_QT_COMPONENTS Multimedia)
# endif()
if (YUZU_USE_QT_MULTIMEDIA)
list(APPEND YUZU_QT_COMPONENTS Multimedia)
endif()
if (YUZU_USE_QT_WEB_ENGINE)
list(APPEND YUZU_QT_COMPONENTS WebEngineCore WebEngineWidgets)
endif()
+7 -1
View File
@@ -61,6 +61,10 @@ See the [sign-up instructions](docs/SIGNUP.md) for information on registration.
Alternatively, if you wish to add translations, go to the [Eden project on Transifex](https://app.transifex.com/edenemu/eden-emulator) and review [the translations README](./dist/languages).
## Documentation
We have a user manual! See our [User Handbook](./docs/user/README.md).
## Building
See the [General Build Guide](docs/Build.md)
@@ -69,7 +73,9 @@ For information on provided development tooling, see the [Tools directory](./too
## Download
You can download the latest releases from [here](https://github.com/eden-emulator/Releases/releases).
You can download the latest releases from [here](https://git.eden-emu.dev/eden-emu/eden/releases).
Save us some bandwidth! We have [mirrors available](./docs/user/ThirdParty.md#mirrors) as well.
## Support
+100
View File
@@ -0,0 +1,100 @@
# CMake Options
To change these options, add `-DOPTION_NAME=NEWVALUE` to the command line.
- On Qt Creator, go to Project -> Current Configuration
Notes:
- Defaults are marked per-platform.
- "Non-UNIX" just means Windows/MSVC and Android (yes, macOS is UNIX
- Android generally doesn't need to change anything; if you do, go to `src/android/app/build.gradle.kts`
- To set a boolean variable to on, use `ON` for the value; to turn it off, use `OFF`
- If a variable is mentioned as being e.g. "ON" for a specific platform(s), that means it is defaulted to OFF on others
- TYPE is always boolean unless otherwise specified
- Format:
- `OPTION_NAME` (TYPE DEFAULT) DESCRIPTION
## Options
### Dependencies
These options control dependencies.
- `YUZU_USE_BUNDLED_FFMPEG` (ON for non-UNIX) Download a pre-built and configured FFmpeg
- `YUZU_USE_EXTERNAL_FFMPEG` (ON for Solaris) Build FFmpeg from source
- `YUZU_DOWNLOAD_ANDROID_VVL` (ON) Download validation layer binary for Android
- `YUZU_DOWNLOAD_TIME_ZONE_DATA` (ON) Always download time zone binaries
- Currently, build fails without this
- `YUZU_TZDB_PATH` (string) Path to a pre-downloaded timezone database (useful for nixOS and Gentoo)
- `YUZU_USE_BUNDLED_MOLTENVK` (ON, macOS only) Download bundled MoltenVK lib
- `YUZU_USE_BUNDLED_OPENSSL` (ON for MSVC, Android, Solaris, and OpenBSD) Download bundled OpenSSL build
- `YUZU_USE_EXTERNAL_SDL2` (OFF) Compiles SDL2 from source
- `YUZU_USE_BUNDLED_SDL2` (ON for MSVC) Download a prebuilt SDL2
### Miscellaneous
- `ENABLE_WEB_SERVICE` (ON) Enable multiplayer service
- `ENABLE_WIFI_SCAN` (OFF) Enable WiFi scanning (requires iw on Linux) - experimental
- `ENABLE_CUBEB` (ON) Enables the cubeb audio backend
- This option is subject for removal.
- `YUZU_TESTS` (ON) Compile tests - requires Catch2
- `ENABLE_LTO` (OFF) Enable link-time optimization
- Not recommended on Windows
- UNIX may be better off appending `-flto=thin` to compiler args
- `USE_FASTER_LINKER` (OFF) Check if a faster linker is available
- Not recommended outside of Linux
### Flavors
These options control executables and build flavors.
- `YUZU_LEGACY` (OFF): Apply patches to improve compatibility on some older GPUs at the cost of performance
- `NIGHTLY_BUILD` (OFF): This is only used by CI. Do not use this unless you're making your own distribution and know what you're doing.
- `YUZU_STATIC_BUILD` (OFF) Attempt to build using static libraries if possible
- Not supported on Linux
- Automatically set if `YUZU_USE_BUNDLED_QT` is on for non-Linux
- `ENABLE_UPDATE_CHECKER` (OFF) Enable update checking functionality
- `YUZU_DISABLE_LLVM` (OFF) Do not attempt to link to the LLVM demangler
- Really only useful for CI or distribution builds
**Desktop only**:
- `YUZU_CMD` (ON) Compile the SDL2 frontend (eden-cli)
- `YUZU_ROOM` (OFF) Compile dedicated room functionality into the main executable
- `YUZU_ROOM_STANDALONE` (OFF) Compile a separate executable for room functionality
- `YUZU_STATIC_ROOM` (OFF) Compile the room executable *only* as a static, portable executable
- This is only usable on Alpine Linux.
### Desktop
The following options are desktop only.
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input frontend (HIGHLY RECOMMENDED)
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics frontend
- Unavailable on Windows/ARM64
- You probably shouldn't turn this off.
### Qt
Also desktop-only, but apply strictly to Qt
- `ENABLE_QT` (ON) Enable the Qt frontend (recommended)
- `ENABLE_QT_TRANSLATION` (OFF) Enable translations for the Qt frontend
- `YUZU_USE_BUNDLED_QT` (ON for MSVC) Download bundled Qt binaries
- Not recommended on Linux. For Windows and macOS, the provided build is statically linked.
- `YUZU_QT_MIRROR` (string) What mirror to use for downloading the bundled Qt libraries
- `YUZU_USE_QT_MULTIMEDIA` (OFF) Use QtMultimedia for camera support
- `YUZU_USE_QT_WEB_ENGINE` (OFF) Use QtWebEngine for web applet implementation (requires the huge QtWebEngine dependency; not recommended)
- `USE_DISCORD_PRESENCE` (OFF) Enables Discord Rich Presence (Qt frontend only)
### Retired Options
The following options were a part of Eden at one point, but have since been retired.
- `ENABLE_OPENSSL` - MbedTLS was fully replaced with OpenSSL in [#3606](https://git.eden-emu.dev/eden-emu/eden/pulls/3606), because OpenSSL straight-up performs better.
- `ENABLE_SDL2` - While technically possible to *not* use SDL2 on desktop, this is **NOT** a supported configuration under any means, and adding this matrix to our build system was not worth the effort.
- `YUZU_USE_CPM` - This option once had a purpose, but that purpose has long since passed us by. *All* builds use CPMUtil to manage dependencies now.
- If you want to *force* the usage of system dependencies, use `-DCPMUTIL_FORCE_SYSTEM=ON`.
See `src/dynarmic/CMakeLists.txt` for additional options--usually, these don't need changed
+3 -1
View File
@@ -1,8 +1,11 @@
# Eden Build Documentation
Are you just a casual user? Take a look at our [User Handbook](./user) then!
This contains documentation created by developers. This contains build instructions, guidelines, instructions/layouts for [cool stuff we made](./CPMUtil), and more.
- **[General Build Instructions](Build.md)**
- **[CMake Options](Options.md)**
- **[Cross Compiling](CrossCompile.md)**
- **[Development Guidelines](Development.md)**
- **[Dependencies](Deps.md)**
@@ -10,7 +13,6 @@ This contains documentation created by developers. This contains build instructi
- **[CPM - CMake Package Manager](./CPMUtil)**
- **[Platform-Specific Caveats](Caveats.md)**
- **[The NVIDIA SM86 (Maxwell) GPU](./NvidiaGpu.md)**
- **[User Handbook](./user)**
- **[Dynarmic](./dynarmic)**
- **[Cross compilation](./CrossCompile.md)**
- **[Driver Bugs](./DriverBugs.md)**
+23 -4
View File
@@ -18,7 +18,7 @@ First of all, you MUST have a valid reason to sign up for our Git. Valid reasons
The following are not valid reasons to sign up:
- I want to contribute to Eden.
* Be at least somewhat specific!
* Be at least somewhat specific! We always welcome contributors and developers, but generic "I want to contribute" messages don't give us enough information.
- I want to support Eden.
* If you wish to support us through development, be more specific; otherwise, to support us, check out our [donations page](https://eden-emu.dev/donations).
- I want to report issues.
@@ -41,17 +41,36 @@ Email: <Your Desired Email>
I wish to sign up because... <your reason here>
```
Email notifications are disabled for the time being, so you don't have to use a real email. If you wish to remain anonymous, either send a separate email asking for access to a shared anonymous account, *or* create a fake username and email.
Email notifications are disabled for the time being, so you don't have to use a real email. If you wish to remain anonymous, either send a separate email asking for access to a shared anonymous account, *or* create a fake username and email. Do note that the email you sign up with is used to accredit commits on the web UI, and *must* match your configured GPG key.
## Patches
In general, PRs are the preferred method of tracking patches, as they allow us to go through our standard triage, CI, and testing process without having to deal with the minutiae of incremental patches. However, we also understand that many people prefer to use raw patches, and that's totally okay! While we currently don't have a mailing list, we do accept email patches. To do so:
1. Make your changes on a clean copy of the master branch
2. Commit your changes with a descriptive, well-formed message (see the [commit message docs](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/Development.md#pull-requests)), and a proper description thoroughly explaining your changes.
* Note that we don't need to know all the individual details about your code. A description explaining the motivation and general implementation of your changes is enough, alongside caveats and any potential blockers.
3. Format your patch with `git format-patch -1 HEAD`.
4. Email us with the subject `[Eden] [PATCH] <brief patch description...>`, with a brief description of your patch, and the previously-formatted patch file as an attachment.
* If you don't include the first two bracketed parts, your email may be lost!
The following emails are currently set up to receive and process patches:
- [eden@eden-emu.dev](mailto:eden@eden-emu.dev]
- [crueter@eden-emu.dev](mailto:eden@eden-emu.dev)
## Instructions
If you have read everything above and affirm that you will not abuse your access, click the summary below to get the email to send your request to.
<details>
<summary>I affirm that I have read ALL of the information above, and will not abuse my access to Eden, nor will I send unnecessary spam requests or the following email.</summary>
<summary>I affirm that I have read ALL of the information above, and will not abuse my access to Eden, nor will I send unnecessary spam to the following email.</summary>
Email [crueter@crueter.xyz](mailto:crueter@crueter.xyz) with the format above.
Once your request is processed, you should receive a confirmation email from crueter with your password alongside a link to a repository containing instructions on SSH, etc. Note that you are required to change your password. If your request is rejected, you will receive a notice as such, asking for clarification if needed. If you do not receive a response in 48 hours, you may send another email.
</details>
> [!WARNING]
> Some email providers may place the response email in your spam/junk folder; notable offenders include Gmail and Outlook. *Always* ensure to check your Spam/Junk folder, until Google/Microsoft finally end their vendetta against the great evil of my `.xyz` domain.
</details>
+7 -2
View File
@@ -17,7 +17,9 @@ AI is notorious for hallucinating facts out of thin air and sometimes outright l
- Code that works, but is extraordinarily verbose or not nearly as efficient as it can be
- Code that works well and is written well, but solves a different problem than was intended, or solves the same problem but in a completely incorrect way that will break other things horribly.
Human-written code will, without exception, always be of infinitely higher quality when properly researched and implemented by someone both familiar with the surrounding code and the programming language in use. LLMs may produce a "good enough" result, but this result is often subpar. Keep in mind: all code is held under a standard of excellence. If your code sucks, it will be rejected. AI-generated code just so happens to be a particularly sucky genre of code, and will thus be held to this same standard.
Human-written code will, without exception, always be of infinitely higher quality when properly researched and implemented by someone familiar with *both* the surrounding code and the programming language in use. LLMs may produce a "good enough" result, but this result is often subpar.
**All code is held under a STRICT STANDARD OF EXCELLENCE**. AI code is no different, and since it often produces subpar or outright terrible code, it will often fail to meet this excellence standard.
On a lesser-known note, LLM outputs often contain unicode symbols such as emojis or the arrow symbol. Please don't put Unicode symbols in your code. It messes with many an IDE, and the three people viewing your code on Lynx will be very unhappy.
@@ -25,7 +27,8 @@ On a lesser-known note, LLM outputs often contain unicode symbols such as emojis
## Acceptable Use
- As stated previously, AI is good in a few *very specific* cases. In these cases, it's usually fine to use AI, as long as you **explicitly provide notice that it was used**.
As stated previously, AI is good in a few *very specific* cases. In these cases, it's usually fine to use AI, as long as you **explicitly provide notice that it was used**.
- Anything directly outside of the realm of the code written in your PR or patch is none of our business.
- This primarily covers research.
- However, we *still* strongly discourage this for the reasons mentioned above.
@@ -104,4 +107,6 @@ This consolidates profile removal behavior, fixes potential race conditions in t
This has all of the same problems as the other one. Needlessly verbose, doesn't address *what* it actually fixes ("consolidates profile removal behavior"... okay, why? What does it fix?), etc. It even has the bonus of totally hallucinating the addition of a method!
On a more "philosophical" note, LLMs tend to be geared towards *corporate language*, as that's what they're trained on. This is why AI-generated commit messages feel like "word salad", and typically pad out the commit message to make it *look* like a lot of things were changed (trust me, it's like that in the corporate world). They typically also drift towards unneeded buzzwords and useless implementation details.
**Don't use AI for commit messages**.
-100
View File
@@ -1,100 +0,0 @@
# Importing Games into Steam with Steam Rom Manager
Use this when you want to import your games inside Eden into Steam to launch with artwork from Steam Game Mode without needing to launch Eden first.
**Click [Here](https://evilperson1337.notion.site/Importing-Games-into-Steam-with-Steam-Rom-Manager-2b757c2edaf680d7a491c92b138f1fcc) for a version of this guide with images & visual elements.**
---
### Pre-Requisites
- Steam Deck Set up and Configured
- Eden set up and Configured
- Internet Access
---
## Steps
1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
1. Install ***Steam ROM Manager***, there are 2 ways you can accomplish this, either manually or through [*EmuDeck*](https://www.emudeck.com/#downloads).
---
### Manual Installation
1. Open the *Discover Store* and search for *Steam ROM Manager.*
2. Select the **Install** button to install the program.
---
### Installing Through *EmuDeck*
<aside>
***NOTE***: This assumes you have already set up EmuDeck, if not - just run through the guided installation and select *Steam ROM Manager* as one of the options.
</aside>
1. Open **EmuDeck**, then navigate to *Manage Emulators.*
2. Scroll down to the bottom of the page to the *Manage your Tools & Frontends* section. Click **Steam ROM Manager**.
3. Click the **Install** button on the right hand side to install it.
---
2. Open the Start Menu and Launch ***Steam ROM Manager***
1. The program will now launch and show you a window with parsers.
<aside>
***TIP***: Your layout may look different depending on how you installed *Steam ROM Manager*. You may need to go to **Settings → Theme** and change it to *Classic* to follow along.
</aside>
2. Switch off all Parsers by hitting the *Toggle Parsers* switch.
3. Scroll down the list on the left-hand side and look for a parser called *Nintendo Switch - Eden* and switch it on. This parser may not exist depending on how you installed *Steam ROM Manager* (EmuDeck creates it for you). Follow these steps to create it if it is missing.
---
### Creating the Eden Parser
1. Select Create Parser and in the *Community Presets* option look for **Nintendo Switch - Yuzu**.
2. Change the **Parser title** from *Nintendo Switch - Yuzu* to *Nintendo Switch - Eden.*
3. Hit the **Browse** option under the *ROMs directory* section. Select the directory containing your Switch ROMs.
4. Under *Steam collections*, you can add a Steam category name. This just organizes the games under a common category in your Steam Library, this is optional but recommended.
5. Scroll down slightly to the **Executable Configuration → Executable**, select **Browse** and select the Eden AppImage.
6. Leave everything else the same and hit **Save** to save the parser.
---
4. Click the Eden parser to view the options on the right, select **Test** at the bottom of the screen to ensure that *Steam ROM Manager* detects your games correctly.
1. *Steam ROM Manager* will start to scan the specified ROMs directory and match them to games. Look over the results to ensure they are accurate. If you do not see any entries - check your parsers ROMs directory field.
1. When you are happy with the results, click the **Add Games****Parse** to start the actual Parsing.
1. The program will now identify the games and pull artwork from [*SteamGridDB*](https://www.steamgriddb.com/).
2. Review the game matches and ensure everything is there.
---
### Correcting a Mismatch
If the game is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
1. Hover over the game card and click the magnifying glass icon.
2. Search for the game on the *Search SteamGridDB* section and scroll through the results, selecting the one you want.
3. Ensure the *Name* and *Game ID* update in the **Per-App Exceptions** and press **Save and close**. The game should now update.
---
### Excluding Matches
You may want to tell Steam ROM Manager to ignore some files (updates/DLC/etc.) that it finds in the directory. This is how you do so.
1. Hit the **Exclude Games** button in the bottom right.
2. Deselect the game you want to exclude, the poster artwork should go dim and the **Number Excluded** number should increment up. Repeat with any other exclusions you want to add.
3. Hit **Save Excludes** when you are happy with your selections.
---
3. When you are happy with the results, select **Save to Steam** to save the results.
1. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
2. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
3. Try to launch a game and ensure everything is working. You are now good to go.
+11
View File
@@ -0,0 +1,11 @@
# User Handbook - Custom Firmware (CFW)
At the moment of writing, we do not support CFW such as Atmosphere, due to:
- Lacking the required LLE emulation capabilities to properly emulate the full firmware.
- Lack of implementation on some of the key internals.
- Nobody has bothered to do it (PRs always welcome!)
We do however, maintain HLE compatibility with the former mentioned CFW, applications that require Atmosphere to run will run fine in the emulator without any adjustments.
If they don't run - then that's a bug!
+3 -1
View File
@@ -1,5 +1,7 @@
# User Handbook - Graphics
Graphical enhancements and visual quality improvments. This doesn't cover texture mods.
## Visual Enhancements
### Anti-aliasing
@@ -89,7 +91,7 @@ The OpenGL backend would invoke behaviour that would result in swarst/LLVMpipe w
### HaikuOS compatibility
HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purpouses `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through.
HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purposes `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through.
### Fixes for Windows 10 and above having "Device loss"
+206
View File
@@ -0,0 +1,206 @@
# User Handbook - Installing Mods
## General Notes
**Note:** When installing a mod, always read the mod's installation instructions.
This is especially important if a mod uses a framework such as **ARCropolis**, **Skyline**, or **Atmosphere plugins**. In those cases, follow the framework's instructions instead of using Eden's normal mod folder.
For example, **Super Smash Bros. Ultimate** uses such a framework. See the related section below for details.
---
# Installing Mods for Most Games
1. Right click a game in the game list.
2. Click **"Open Mod Data Location"**.
3. Extract the mod into that folder.
Each mod should be placed inside **its own subfolder**.
---
# Enabling or Disabling Mods
1. Right click the game in the game list.
2. Click **Configure Game**.
3. In the **Add-Ons** tab, enable or disable mods, updates, and DLC by ticking or unticking their boxes.
---
# Important Note About SD Card Paths
Some mods are designed for real Nintendo Switch consoles and refer to the **SD card root**.
The emulated SD card is located at:
```
%AppData%\eden\sdmc
```
Example:
```
Switch instruction: sd:/ultimate/mods
Eden equivalent: sdmc/ultimate/mods
```
---
# Framework-Based Mods (Super Smash Bros. Ultimate)
Some games require external mod frameworks instead of the built-in mod loader.
The most common example is **Super Smash Bros. Ultimate**.
These mods are installed directly to the **emulated SD card**, not the normal Eden mod folder.
---
# Installing the ARCropolis Modding Framework
**Note:** Some mod packs bundle ARCropolis with their installer (for example, Smash Ult-S).
---
## 1. Download ARCropolis
Download the latest release:
https://github.com/Raytwo/ARCropolis/releases/
---
## 2. Install ARCropolis
Extract the **`atmosphere`** folder into:
```
%AppData%\eden\sdmc
```
This is the **emulated SD card directory**.
Verify installation by checking that the following file exists:
```
sdmc\atmosphere\contents\01006A800016E000\romfs\skyline\plugins\libarcropolis.nro
```
---
## 3. Download Skyline
Download the latest Skyline release:
https://github.com/skyline-dev/skyline/releases
Skyline used to be bundled with ARCropolis but is now distributed separately to avoid compatibility issues caused by outdated bundled versions.
---
## 4. Install Skyline
Extract the **`exefs`** folder into:
```
sdmc\atmosphere\contents\01006A800016E000
```
The `exefs` folder should be **next to the `romfs` folder**.
Verify installation by checking that the following file exists:
```
%AppData%\eden\sdmc\atmosphere\contents\01006A800016E000\exefs\subsdk9
```
---
## 5. Launch the Game Once
Start the game and make sure you see the **ARCropolis version text on the title screen**.
This will also create the folders required for installing mods.
---
## 6. Install Smash Ultimate Mods
Install mods inside:
```
sdmc\ultimate\mods
```
Each mod must be placed inside **its own subfolder**.
Example:
```
sdmc\ultimate\mods\ExampleMod
```
---
# Troubleshooting
## ARCropolis text does not appear on startup
Check the following:
- `libarcropolis.nro` exists in:
```
sdmc\atmosphere\contents\01006A800016E000\romfs\skyline\plugins
```
- `subsdk9` exists in:
```
sdmc\atmosphere\contents\01006A800016E000\exefs
```
- Files were extracted to:
```
%AppData%\eden\sdmc
```
---
## Mods are not loading
Make sure mods are installed inside:
```
sdmc\ultimate\mods
```
Each mod must have its **own subfolder**.
Correct example:
```
sdmc\ultimate\mods\ExampleMod
```
Incorrect example:
```
sdmc\ultimate\mods\ExampleMod\ExampleMod
```
---
## Installing mods in the wrong folder
ARCropolis mods **do not go in Eden's normal mod folder**.
Do **not** install Smash mods here:
```
user\load\01006A800016E000
```
That folder is only used for traditional **RomFS mods**, not ARCropolis.
+15 -4
View File
@@ -4,10 +4,14 @@ The "FAQ".
This handbook is primarily aimed at the end-user - baking useful knowledge for enhancing their emulation experience.
A copy of this handbook is [available online](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/README.md).
## Basics
- **[The Basics](Basics.md)**
- **[Quickstart](./QuickStart.md)**
- **[Settings](./Settings.md)**
- **[Installing Mods](./Mods.md)**
- **[Run On macOS](./RunOnMacOS.md)**
- **[Audio](Audio.md)**
- **[Graphics](Graphics.md)**
@@ -17,22 +21,29 @@ This handbook is primarily aimed at the end-user - baking useful knowledge for e
- **[Using Amiibo](./UsingAmiibo.md)**
- **[Using Cheats](./UsingCheats.md)**
- **[Importing Saves](./ImportingSaves.md)**
- **[Add Eden to Steam ROM Manager](./AddEdenToSRM.md)**
- **[Add Games to Steam ROM Manager](./AddGamesToSRM.md)**
- **[Installing Atmosphere Mods](./InstallingAtmosphereMods.md)**
- **[Installing Updates & DLCs](./InstallingUpdatesDLC.md)**
- **[Controller Profiles](./ControllerProfiles.md)**
- **[Alter Date & Time](./AlterDateTime.md)**
## 3rd-party Integration
- **[Configuring Steam ROM Manager](./SteamROM.md)**
- **[Server hosting](ServerHosting.md)**
- **[Syncthing Guide](./SyncthingGuide.md)**
- **[Third Party](./ThirdParty.md)**
- **[Obtainium](./ThirdParty.md#configuring-obtainium)**
- **[ES-DE](./ThirdParty.md#configuring-es-de)**
- **[Mirrors](./ThirdParty.md#mirrors)**
## Advanced
- **[Custom Firmware](./CFW.md)**
- **[How To Access Logs](./HowToAccessLogs.md)**
- **[Gyro Controls](./GyroControls.md)**
- **[Platforms and Architectures](Architectures.md)**
- **[Server hosting](ServerHosting.md)**
- **[Command Line](CommandLine.md)**
- **[Native Application Development](Native.md)**
- **[Adding Boolean Settings Toggles](AddingBooleanToggles.md)**
- **[Adding Debug Knobs](./AddingDebugKnobs.md)**
- **[Syncthing Guide](./SyncthingGuide.md)**
- **[Testing](Testing.md)**
+54
View File
@@ -0,0 +1,54 @@
# User Handbook - Settings
As the emulator continues to grow, so does the number of settings that come and go.
Most of the development adds new settings that enhance performance/compatibility, only to be removed later in newer versions due to newfound discoveries or because they were "a hacky workaround".
As such, this guide will NOT mention those kind of settings, we'd rather mention settings which have a long shelf time (i.e won't get removed in future releases) and are likely to be unchanged.
Some of the options are self explainatory, and they do exactly what they say they do (i.e "Pause when not in focus"); such options will be also skipped due to triviality.
## Foreword
Before touching the settings, please see the game boots with stock options. We try our best to ensure users can boot any game using the default settings. If they don't work, then you may try fiddling with options - but please, first use stock options.
## General
- `General/Force X11 as Graphics Backend`: Wayland on *NIX has prominent issues that are unlikely to be resolved; the kind that are "not our fault, it's Wayland issue", this "temporary" hack forces X11 as the backend, regardless of the desktop manager's default.
- `General/Enable Gamemode`: This only does anything when you have Feral Interactive's Gamemode library installed somewhere, if you do, this will help boost FPS by telling the OS to explicitly prioritize *this* application for "gaming" - only for *NIX systems.
- `Hotkeys`: Deceptively to remove a hotkey you must right click and a menu will appear to remove that specific hotkey.
- `UI/Language`: Changes language *of the interface* NOT the emulated program!
- `Debug/Enable Auto Stub`: May help to "fix" some games by just lying and saying that everything they do returns "success" instead of outright crashing for any function/service that is NOT implemented.
- `Debug/Show log in console`: Does as said, note that the program may need to be reopened (Windows) for changes to take effect.
- `Debug/Flush log output`: Classically, every write to the log is "buffered", that is, changes aren't written to the disk UNTIL the program has decided it is time to write, until then it keeps data in a buffer which resides on RAM. If the program crashes, the OS will automatically discard said buffer (any RAM associated with a dead process is automatically discarded/reused for some other purpose); this means critical data may not be logged to the disk on time, which may lead to missing log lines. Use this if you're wanting to remove that factor when debugging, sometimes a hard crash may "eat" some of the log lines IF this option isn't enabled.
- `Debug/Disable Macro HLE:` The emulator has HLE emulation of macro programs for Maxwell, this means that some details are purpousefully skipped; this option forces all macro programs to be ran without skipping anything.
## System
- `System/RNG Seed`: Set to 0 (and uncheck) to disable ASLR systemwide (this makes mods like CTGP to stop working); by default it enables ASLR to replicate console behaviour.
- `Network/Enable Airplane Mode`: Enable this if a game is crashing before loading AND the logs mention anything related to "web" or "internet" services.
## CPU
- `CPU/Virtual table bouncing`: Some games have the tendency to crash on loading due to an indirect bad jump (Pokemon ZA being the worst offender); this option lies to the game and tells it to just pretend it never executed a given function. This is fine for most casual users, but developers of switch applications **must** disable this. This temporary "hack" should hopefully be gone in 6-7 months from now on.
- `Fastmem`, aka. `CPU/Enable Host MMU`: Enables "fastmem"; a detailed description of fastmem can be found [here](../dynarmic/Design.md#fast-memory-fastmem).
- `CPU/Unsafe FMA`: Enables deliberate innacurate FMA behaviour which may affect how FMA returns any given operation - this may introduce tiny floating point errors which can cascade in sensitive code (i.e FFmpeg).
- `CPU/Faster FRSQRTE and FRECPE`: Introduces accuracy errors on square root and reciprocals in exchange for less checks - this introduces inaccuracies with some cases but it's mostly safe.
- `CPU/Faster ASIMD Instructions`: Skips rounding mode checks for ARM ASIMD instructions - this means some code dpeending on these rounding modes may misbehave.
- `CPU/Disable address space checks`: Before each memory access, the emulator checks the address is in range, if not it faults; this option makes it so the emulator skips the check entirely (which may be expensive for a myriad of reasons). However at the same time this allows the guest program to "break out" of the emulation context by writing to arbitrary addresses.
- `CPU/Ignore global monitor`: This relies on a quirk present on x86 to avoid the ARM global monitor emulation, this may increase performance in mutex-heavy contexts (i.e games waiting for next frames or such); but also can cause deadlocks and fun to debug issues.
It is important to note the majority of precision-reducing instructions do not benefit cases where they are not used, which means the performance gains will vary per game.
# Graphics
See also [an extended breakdown of some options](./Graphics.md).
- `Extras/Extended Dynamic State` and `Extras/Vertex Input Dynamic State`: These Vulkan extensions essentially allow you to reuse the same pipeline but just change the state between calls (so called "dynamic state"); the "extended" levels signifies how much state can be placed on this "dynamic" range, for example the amount of depth culling to use can be placed on the dynamic state, avoiding costly reloads and flushes. While this by itself is a fine option, SOME vendors (notably PowerVR and Mali) have problems with anything related to EDS3. EDS3 contains EDS2, and EDS2 contains EDS1. Essentially this means more extended data the driver has to keep track of, at the benefit of avoiding costly flushes.
- `Advanced/Use persistent cache`: This saves compiled shaders onto the disk, independent of any driver's own disk saved shaders (yes, some drivers, notably NVIDIA, save a secondary shader cache onto disk) - disable this only if you're debugging or working on the GPU backend. This option is meant to massively help to reduce shader stutters (after playing for one session that compiles them).
- `Advanced/Use Vulkan pipeline cache`: This is NOT the same as `Use persistent cache`; it's a separate flag that tells the Vulkan backend to create pipeline caches, which are a detail that can be used to massively improve performance and remove pipeline creation overhead. This is a Vulkan feature.
## Controls
Most of the controls should work out of the box. If not, please use a joystick calibrator to ensure it's not an issue with your own controller, for example:
- https://github.com/dkosmari/calibrate-joystick
@@ -1,4 +1,6 @@
# Importing Eden into Steam with Steam Rom Manager
# User Handbook - Configuring Steam ROM Manager
## Importing Eden into Steam with Steam Rom Manager
Use this when you want to import the Eden AppImage into your Steam Library along with artwork using *Steam ROM Manager.*
@@ -6,7 +8,7 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
### Pre-Requisites
#### Pre-Requisites
- Eden set up and configured
- Internet Connection
@@ -14,9 +16,9 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
## Steps
### Steps
### Initial Setup
#### Initial Setup
1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
@@ -24,14 +26,14 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
### Manual Installation
#### Manual Installation
1. Open the *Discover Store* and search for *Steam ROM Manager.*
2. Select the **Install** button to install the program.
---
### Installing Through *EmuDeck*
#### Installing Through *EmuDeck*
<aside>
@@ -45,9 +47,9 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
### Adding Eden into *Steam ROM Manager*
#### Adding Eden into *Steam ROM Manager*
### EmuDeck Users
#### EmuDeck Users
EmuDeck will automatically create an *Emulators - Emulators* parser for ***Steam ROM Manager*** that uses shell scripts to launch them. We will follow this convention.
@@ -87,7 +89,7 @@ EmuDeck will automatically create an *Emulators - Emulators* parser for ***Steam
---
### Non-EmuDeck Users
#### Non-EmuDeck Users
We will need to create a new parser for the Emulators. Unlike with the EmuDeck model, we will have the parser look for AppImages.
@@ -126,7 +128,7 @@ We will need to create a new parser for the Emulators. Unlike with the EmuDeck
---
### Adding Eden to Steam
#### Adding Eden to Steam
Now that we have the parser or shell script created, we can actually add it to Steam.
@@ -137,7 +139,7 @@ Now that we have the parser or shell script created, we can actually add it to S
---
### Correcting a Mismatch
#### Correcting a Mismatch
If the emulator is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
@@ -147,7 +149,7 @@ Now that we have the parser or shell script created, we can actually add it to S
---
### Excluding Matches
#### Excluding Matches
You may want to tell Steam ROM Manager to ignore some files that it finds in the directory. This is how you do so.
@@ -159,4 +161,105 @@ Now that we have the parser or shell script created, we can actually add it to S
5. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
6. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
7. Try to launch the Emulator from Steam and ensure everything is working. You are now good to go.
7. Try to launch the Emulator from Steam and ensure everything is working. You are now good to go.
## Importing Games into Steam with Steam Rom Manager
Use this when you want to import your games inside Eden into Steam to launch with artwork from Steam Game Mode without needing to launch Eden first.
**Click [Here](https://evilperson1337.notion.site/Importing-Games-into-Steam-with-Steam-Rom-Manager-2b757c2edaf680d7a491c92b138f1fcc) for a version of this guide with images & visual elements.**
---
#### Pre-Requisites
- Steam Deck Set up and Configured
- Eden set up and Configured
- Internet Access
---
### Steps
1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
1. Install ***Steam ROM Manager***, there are 2 ways you can accomplish this, either manually or through [*EmuDeck*](https://www.emudeck.com/#downloads).
---
#### Manual Installation
1. Open the *Discover Store* and search for *Steam ROM Manager.*
2. Select the **Install** button to install the program.
---
#### Installing Through *EmuDeck*
<aside>
***NOTE***: This assumes you have already set up EmuDeck, if not - just run through the guided installation and select *Steam ROM Manager* as one of the options.
</aside>
1. Open **EmuDeck**, then navigate to *Manage Emulators.*
2. Scroll down to the bottom of the page to the *Manage your Tools & Frontends* section. Click **Steam ROM Manager**.
3. Click the **Install** button on the right hand side to install it.
---
2. Open the Start Menu and Launch ***Steam ROM Manager***
1. The program will now launch and show you a window with parsers.
<aside>
***TIP***: Your layout may look different depending on how you installed *Steam ROM Manager*. You may need to go to **Settings → Theme** and change it to *Classic* to follow along.
</aside>
2. Switch off all Parsers by hitting the *Toggle Parsers* switch.
3. Scroll down the list on the left-hand side and look for a parser called *Nintendo Switch - Eden* and switch it on. This parser may not exist depending on how you installed *Steam ROM Manager* (EmuDeck creates it for you). Follow these steps to create it if it is missing.
---
#### Creating the Eden Parser
1. Select Create Parser and in the *Community Presets* option look for **Nintendo Switch - Yuzu**.
2. Change the **Parser title** from *Nintendo Switch - Yuzu* to *Nintendo Switch - Eden.*
3. Hit the **Browse** option under the *ROMs directory* section. Select the directory containing your Switch ROMs.
4. Under *Steam collections*, you can add a Steam category name. This just organizes the games under a common category in your Steam Library, this is optional but recommended.
5. Scroll down slightly to the **Executable Configuration → Executable**, select **Browse** and select the Eden AppImage.
6. Leave everything else the same and hit **Save** to save the parser.
---
4. Click the Eden parser to view the options on the right, select **Test** at the bottom of the screen to ensure that *Steam ROM Manager* detects your games correctly.
1. *Steam ROM Manager* will start to scan the specified ROMs directory and match them to games. Look over the results to ensure they are accurate. If you do not see any entries - check your parsers ROMs directory field.
1. When you are happy with the results, click the **Add Games****Parse** to start the actual Parsing.
1. The program will now identify the games and pull artwork from [*SteamGridDB*](https://www.steamgriddb.com/).
2. Review the game matches and ensure everything is there.
---
#### Correcting a Mismatch
If the game is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
1. Hover over the game card and click the magnifying glass icon.
2. Search for the game on the *Search SteamGridDB* section and scroll through the results, selecting the one you want.
3. Ensure the *Name* and *Game ID* update in the **Per-App Exceptions** and press **Save and close**. The game should now update.
---
#### Excluding Matches
You may want to tell Steam ROM Manager to ignore some files (updates/DLC/etc.) that it finds in the directory. This is how you do so.
1. Hit the **Exclude Games** button in the bottom right.
2. Deselect the game you want to exclude, the poster artwork should go dim and the **Number Excluded** number should increment up. Repeat with any other exclusions you want to add.
3. Hit **Save Excludes** when you are happy with your selections.
---
3. When you are happy with the results, select **Save to Steam** to save the results.
1. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
2. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
3. Try to launch a game and ensure everything is working. You are now good to go.
+59
View File
@@ -7,3 +7,62 @@ While most of the links mentioned in this guide are relatively "safe"; we urge u
- [Nightly Eden builds](https://github.com/pflyly/eden-nightly)
- [NixOS Eden Flake](https://github.com/Grantimatter/eden-flake)
- [ES-DE Frontend Support](https://github.com/GlazedBelmont/es-de-android-custom-systems)
## Mirrors
The main origin repository is always at https://git.eden-emu.dev/eden-emu/eden.
- https://github.com/eden-emulator/mirror
- https://git.crueter.xyz/mirror/eden
- https://collective.taymaerz.de/eden/eden
Other mirrors obviously exist on the internet, but we can't guarantee their reliability and/or availability.
If you're someone wanting to make a mirror, simply setup forgejo and automatically mirror from the origin repository. Or you could mirror a mirror to save us bandwidth... your choice!
## Configuring Obtainium
Very nice handy app, here's a quick rundown how to configure:
1. Copy the URL: https://git.eden-emu.dev/eden-emu/eden/ (or one of your favourite mirrors)
2. Open Obtainium and tap `Add App`.
3. Paste the URL into the `App Source URL` field.
4. Override Source: Look for the `Override Source` dropdown menu and select `Forgejo (Codeberg)`.
5. Click `Add:` Obtainium should now be able to parse the releases and find the APK files.
Note: Even though the site isn't Codeberg, it uses the same Forgejo/Gitea backend, and this setting tells Obtainium how to read the release data.
## Configuring ES-DE
### Method 1
1. Download ZIP from [here](https://github.com/GlazedBelmont/es-de-android-custom-systems)
2. Unzip the file and extract `es_systems.xml` and `es_find_rules.xml` to `\Odin2\Internal shared storage\ES-DE\custom_systems`.
3. Press `Start -> Other Settings -> Alternative Emulators` and set it to Eden (Standalone).
### Method 2
1. Navigate to `\Odin2\Internal shared storage\ES-DE\custom_systems`.
2. Add this to your `es_find_rules.xml`:
```xml
<!-- Standard aka. normal release -->
<emulator name="EDEN">
<rule type="androidpackage">
<entry>dev.eden.eden_emulator/org.yuzu.yuzu_emu.activities.EmulationActivity</entry>
</rule>
</emulator>
<!-- Optimized -->
<emulator name="EDEN">
<rule type="androidpackage">
<entry>com.miHoYo.Yuanshen/org.yuzu.yuzu_emu.activities.EmulationActivity</entry>
</rule>
</emulator>
```
3. Add this line of text to your `es_systems.xml` underneath where the rest of your switch system entries are:
```xml
<command label="Eden (Standalone)">%EMULATOR_EDEN% %ACTION%=android.nfc.action.TECH_DISCOVERED %DATA%=%ROMPROVIDER%</command>
```
+1 -1
View File
@@ -9,7 +9,7 @@ pkgs.mkShellNoCC {
# libraries
openssl boost fmt nlohmann_json lz4 zlib zstd
enet libopus vulkan-headers vulkan-utility-libraries
spirv-tools spirv-headers vulkan-loader unzip mbedtls
spirv-tools spirv-headers vulkan-loader unzip
glslang python3 httplib cpp-jwt ffmpeg-headless
libusb1 cubeb
# eden
-1
View File
@@ -80,7 +80,6 @@ android {
listOf(
"-DENABLE_QT=0", // Don't use QT
"-DENABLE_WEB_SERVICE=1", // Enable web service
"-DENABLE_OPENSSL=ON",
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
"-DYUZU_USE_CPM=ON",
"-DCPMUTIL_FORCE_BUNDLED=ON",
@@ -152,6 +152,10 @@ object NativeLibrary {
external fun surfaceDestroyed()
external fun getAppletCaptureBuffer(): ByteArray
external fun getAppletCaptureWidth(): Int
external fun getAppletCaptureHeight(): Int
/**
* Unpauses emulation from a paused state.
*/
@@ -603,6 +607,12 @@ object NativeLibrary {
*/
external fun addFileToFilesystemProvider(path: String)
/**
* Adds a game-folder file to the manual filesystem provider, respecting the internal gate for
* game-folder external-content mounting.
*/
external fun addGameFolderFileToFilesystemProvider(path: String)
/**
* Clears all files added to the manual filesystem provider in our EmulationSession instance
*/
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -204,9 +204,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
}
override fun onPause() {
super.onPause()
nfcReader.stopScanning()
stopMotionSensorListener()
super.onPause()
}
override fun onDestroy() {
@@ -339,6 +339,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
}
override fun onSensorChanged(event: SensorEvent) {
if (!NativeLibrary.isRunning() || NativeLibrary.isPaused()) {
return
}
val rotation = this.display?.rotation
if (rotation == Surface.ROTATION_90) {
flipMotionOrientation = true
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -10,6 +10,8 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.LifecycleOwner
import com.google.android.material.button.MaterialButton
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.GameProperty
@@ -89,29 +91,33 @@ class GamePropertiesAdapter(
val hasVisibleActions = submenuProperty.secondaryActions?.any { it.isShown } == true
binding.layoutSecondaryActions.removeAllViews()
binding.dividerSecondaryActions.setVisible(false)
if (hasVisibleActions) {
binding.dividerSecondaryActions.setVisible(true)
binding.layoutSecondaryActions.setVisible(true)
submenuProperty.secondaryActions!!.forEach { secondaryAction ->
if (secondaryAction.isShown) {
val button = com.google.android.material.button.MaterialButton(
binding.root.context,
null,
com.google.android.material.R.attr.materialButtonOutlinedStyle
).apply {
setIconResource(secondaryAction.iconId)
iconSize = (18 * binding.root.context.resources.displayMetrics.density).toInt()
text = binding.root.context.getString(secondaryAction.descriptionId)
contentDescription = binding.root.context.getString(secondaryAction.descriptionId)
setOnClickListener { secondaryAction.action.invoke() }
}
binding.layoutSecondaryActions.addView(button)
val visibleActions = submenuProperty.secondaryActions!!.filter { it.isShown }
val inflater = LayoutInflater.from(binding.root.context)
visibleActions.forEachIndexed { index, secondaryAction ->
val button = inflater.inflate(
R.layout.item_secondary_action_button,
binding.layoutSecondaryActions,
false
) as MaterialButton
button.setIconResource(secondaryAction.iconId)
button.text = ""
button.contentDescription = binding.root.context
.getString(secondaryAction.descriptionId)
button.tooltipText = binding.root.context
.getString(secondaryAction.descriptionId)
if (index == visibleActions.lastIndex) {
(button.layoutParams as ViewGroup.MarginLayoutParams).marginEnd = 0
}
button.setOnClickListener { secondaryAction.action.invoke() }
binding.layoutSecondaryActions.addView(button)
}
} else {
binding.dividerSecondaryActions.setVisible(false)
binding.layoutSecondaryActions.setVisible(false)
}
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.dialogs
@@ -14,6 +14,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
import androidx.core.content.getSystemService
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.DividerItemDecoration
@@ -30,6 +31,7 @@ import org.yuzu.yuzu_emu.databinding.DialogLobbyBrowserBinding
import org.yuzu.yuzu_emu.databinding.ItemLobbyRoomBinding
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.network.NetPlayManager
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import java.util.Locale
class LobbyBrowser(context: Context) : BottomSheetDialog(context) {
@@ -46,6 +48,7 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) {
binding = DialogLobbyBrowserBinding.inflate(layoutInflater)
setContentView(binding.root)
BackgroundHelper.applyBackground(binding.backgroundLogo, context)
binding.emptyRefreshButton.setOnClickListener {
binding.progressBar.visibility = View.VISIBLE
@@ -58,6 +61,30 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) {
setupSearchBar()
}
override fun onStart() {
super.onStart()
window?.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
val bottomSheet =
findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
if (bottomSheet != null) {
bottomSheet.layoutParams = bottomSheet.layoutParams.apply {
width = ViewGroup.LayoutParams.MATCH_PARENT
height = ViewGroup.LayoutParams.MATCH_PARENT
}
bottomSheet.requestLayout()
}
behavior.isFitToContents = false
behavior.expandedOffset = 0
behavior.skipCollapsed = true
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
private fun setupRecyclerView() {
adapter = LobbyRoomAdapter { room -> handleRoomSelection(room) }
@@ -1,10 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.fetcher
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
class SpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecoration() {
@@ -15,8 +16,20 @@ class SpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecorat
state: RecyclerView.State
) {
outRect.bottom = spacing
if (parent.getChildAdapterPosition(view) == 0) {
val position = parent.getChildAdapterPosition(view)
if (position == RecyclerView.NO_POSITION) return
if (position == 0) {
outRect.top = spacing
return
}
// If the item is in the first row, but NOT in first column add top spacing as well
val layoutManager = parent.layoutManager
if (layoutManager is GridLayoutManager && layoutManager.spanSizeLookup.getSpanGroupIndex(position, layoutManager.spanCount) == 0) {
outRect.top = spacing
return
}
}
}
@@ -34,6 +34,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
MAX_ANISOTROPY("max_anisotropy"),
THEME("theme"),
THEME_MODE("theme_mode"),
STATIC_THEME_COLOR("static_theme_color"),
APP_LANGUAGE("app_language"),
OVERLAY_SCALE("control_scale"),
OVERLAY_OPACITY("control_opacity"),
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model
@@ -27,7 +27,7 @@ object Settings {
SECTION_APP_SETTINGS(R.string.app_settings),
SECTION_CUSTOM_PATHS(R.string.preferences_custom_paths),
SECTION_DEBUG(R.string.preferences_debug),
SECTION_FREEDRENO(R.string.gpu_driver_settings),
SECTION_FREEDRENO(R.string.freedreno_settings_title),
SECTION_APPLETS(R.string.applets_menu);
}
@@ -105,6 +105,14 @@ object Settings {
const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds"
const val PREF_STATIC_THEME_COLOR = "StaticThemeColor"
// App background preference keys
const val PREF_HOME_BACKGROUND_STYLE = "HomeBackgroundStyle"
const val HOME_BACKGROUND_STYLE_NONE = 0
const val HOME_BACKGROUND_STYLE_EDEN = 1
const val HOME_BACKGROUND_STYLE_DEFAULT = HOME_BACKGROUND_STYLE_NONE
const val PREF_HOME_BACKGROUND_ALPHA = "HomeBackgroundAlpha"
const val HOME_BACKGROUND_ALPHA_DEFAULT = 40
enum class EmulationOrientation(val int: Int) {
Unspecified(0),
SensorLandscape(5),
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -111,10 +111,18 @@ class SettingsActivity : AppCompatActivity() {
if (navHostFragment.childFragmentManager.backStackEntryCount > 0) {
navHostFragment.navController.popBackStack()
} else {
finish()
finishWithFragmentLikeAnimation()
}
}
private fun finishWithFragmentLikeAnimation() {
finish()
overridePendingTransition(
androidx.navigation.ui.R.anim.nav_default_pop_enter_anim,
androidx.navigation.ui.R.anim.nav_default_pop_exit_anim
)
}
override fun onStart() {
super.onStart()
if (!DirectoryInitialization.areDirectoriesReady) {
@@ -170,7 +178,7 @@ class SettingsActivity : AppCompatActivity() {
getString(R.string.settings_reset),
Toast.LENGTH_LONG
).show()
finish()
finishWithFragmentLikeAnimation()
}
private fun setInsets() {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -68,7 +68,9 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
MaterialAlertDialogBuilder(requireContext())
.setMessage(R.string.reset_setting_confirmation)
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
when (val item = settingsViewModel.clickedItem) {
val item = settingsViewModel.clickedItem ?: return@setPositiveButton
clearDialogState()
when (item) {
is AnalogInputSetting -> {
val stickParam = NativeInput.getStickParam(
item.playerIndex,
@@ -107,12 +109,17 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
}
else -> {
settingsViewModel.clickedItem!!.setting.reset()
item.setting.reset()
settingsViewModel.setAdapterItemChanged(position)
}
}
}
.setNegativeButton(android.R.string.cancel, null)
.setNegativeButton(android.R.string.cancel) { _: DialogInterface, _: Int ->
clearDialogState()
}
.setOnCancelListener {
clearDialogState()
}
.create()
}
@@ -186,27 +193,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
updateButtonState(isValid)
}
/*
* xbzk: these two events, along with attachRepeat feature,
* were causing spinbox buttons to respond twice per press
* cutting these out to retain accelerated press functionality
* TODO: clean this out later if no issues arise
*
spinboxBinding.buttonDecrement.setOnClickListener {
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
val newValue = current - 1
spinboxBinding.editValue.setText(newValue.toString())
updateValidity(newValue)
}
spinboxBinding.buttonIncrement.setOnClickListener {
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
val newValue = current + 1
spinboxBinding.editValue.setText(newValue.toString())
updateValidity(newValue)
}
*/
fun attachRepeat(button: View, delta: Int) {
val handler = Handler(Looper.getMainLooper())
var runnable: Runnable? = null
@@ -439,9 +425,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
private fun closeDialog() {
settingsViewModel.setAdapterItemChanged(position)
clearDialogState()
dismiss()
}
private fun clearDialogState() {
settingsViewModel.clickedItem = null
settingsViewModel.setSliderProgress(-1f)
dismiss()
}
private fun getValueForSingleChoiceSelection(item: SingleChoiceSetting, which: Int): Int {
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -33,6 +33,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.view.PathSetting
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.PathUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.*
@@ -98,23 +99,8 @@ class SettingsFragment : Fragment() {
activity
)
binding.toolbarSettingsLayout.title = if (args.menuTag == Settings.MenuTag.SECTION_ROOT &&
args.game != null
) {
args.game!!.title
} else {
when (args.menuTag) {
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1)
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2)
Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3)
Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4)
Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5)
Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6)
Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7)
Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8)
else -> getString(args.menuTag.titleId)
}
}
val toolbarTitle = resolveToolbarTitle()
configureToolbar(toolbarTitle)
binding.listSettings.apply {
adapter = settingsAdapter
@@ -193,10 +179,16 @@ class SettingsFragment : Fragment() {
}
presenter.onViewCreated()
applyBackgroundPreference()
setInsets()
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
private fun getPlayerIndex(): Int =
when (args.menuTag) {
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> 0
@@ -210,6 +202,27 @@ class SettingsFragment : Fragment() {
else -> -1
}
private fun resolveToolbarTitle(): String {
if (args.menuTag == Settings.MenuTag.SECTION_ROOT && args.game != null) {
return args.game!!.title
}
return when (args.menuTag) {
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1)
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2)
Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3)
Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4)
Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5)
Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6)
Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7)
Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8)
else -> getString(args.menuTag.titleId)
}
}
private fun configureToolbar(title: String) {
binding.toolbarSettings.title = title
}
private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
@@ -228,6 +241,10 @@ class SettingsFragment : Fragment() {
}
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
private fun hasAllFilesPermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Environment.isExternalStorageManager()
@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.features.settings.ui
import android.annotation.SuppressLint
import android.os.Build
import android.widget.Toast
import androidx.preference.PreferenceManager
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
@@ -27,11 +26,10 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import androidx.core.content.edit
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import androidx.fragment.app.FragmentActivity
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
@@ -183,16 +181,6 @@ class SettingsFragmentPresenter(
menuKey = MenuTag.SECTION_DEBUG
)
)
if (GpuDriverHelper.isAdrenoGpu() && !NativeConfig.isPerGameConfigLoaded()) {
add(
SubmenuSetting(
titleId = R.string.gpu_driver_settings,
descriptionId = R.string.freedreno_settings_title,
iconId = R.drawable.ic_graphics,
menuKey = MenuTag.SECTION_FREEDRENO
)
)
}
add(
SubmenuSetting(
titleId = R.string.applets_menu,
@@ -1066,7 +1054,10 @@ class SettingsFragmentPresenter(
IntSetting.THEME.getValueAsString()
override val defaultValue: Int = IntSetting.THEME.defaultValue
override fun reset() = IntSetting.THEME.setInt(defaultValue)
override fun reset() {
IntSetting.THEME.setInt(defaultValue)
settingsViewModel.setShouldRecreate(true)
}
}
add(HeaderSetting(R.string.app_settings))
@@ -1081,7 +1072,6 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.theme_and_color))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
add(
SingleChoiceSetting(
@@ -1123,28 +1113,6 @@ class SettingsFragmentPresenter(
}
}
val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting {
val preferences = PreferenceManager.getDefaultSharedPreferences(
YuzuApplication.appContext
)
override fun getInt(needsGlobal: Boolean): Int =
preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0)
override fun setInt(value: Int) {
preferences.edit() { putInt(Settings.PREF_STATIC_THEME_COLOR, value) }
settingsViewModel.setShouldRecreate(true)
}
override val key: String = Settings.PREF_STATIC_THEME_COLOR
override val isRuntimeModifiable: Boolean = true
override fun getValueAsString(needsGlobal: Boolean): String =
preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0).toString()
override val defaultValue: Any = 0
override fun reset() {
preferences.edit() { putInt(Settings.PREF_STATIC_THEME_COLOR, 0) }
settingsViewModel.setShouldRecreate(true)
}
}
add(
SingleChoiceSetting(
themeMode,
@@ -1154,6 +1122,29 @@ class SettingsFragmentPresenter(
)
)
val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int =
IntSetting.STATIC_THEME_COLOR.getInt(needsGlobal)
override fun setInt(value: Int) {
IntSetting.STATIC_THEME_COLOR.setInt(value)
settingsViewModel.setShouldRecreate(true)
}
override val key: String = IntSetting.STATIC_THEME_COLOR.key
override val isRuntimeModifiable: Boolean = true
override fun getValueAsString(needsGlobal: Boolean): String =
IntSetting.STATIC_THEME_COLOR.getValueAsString(needsGlobal)
override val defaultValue: Any = IntSetting.STATIC_THEME_COLOR.defaultValue
override fun reset() {
IntSetting.STATIC_THEME_COLOR.reset()
settingsViewModel.setShouldRecreate(true)
}
}
if (IntSetting.THEME.getInt() != 1) {
add(
SingleChoiceSetting(
@@ -1197,6 +1188,79 @@ class SettingsFragmentPresenter(
)
)
val backgroundStyleSetting: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int =
BackgroundHelper.getBackgroundStyle(context)
override fun setInt(value: Int) {
BackgroundHelper.setBackgroundStyle(context, value)
settingsViewModel.setShouldRecreate(true)
}
override val key: String = Settings.PREF_HOME_BACKGROUND_STYLE
override val isRuntimeModifiable: Boolean = true
override val pairedSettingKey: String = ""
override val isSwitchable: Boolean = false
override var global: Boolean = true
override val isSaveable: Boolean = true
override val defaultValue: Int = Settings.HOME_BACKGROUND_STYLE_DEFAULT
override fun getValueAsString(needsGlobal: Boolean): String =
getInt(needsGlobal).toString()
override fun reset() {
setInt(defaultValue)
}
}
add(
SingleChoiceSetting(
backgroundStyleSetting,
titleId = R.string.home_background,
descriptionId = R.string.home_background_description,
choicesId = R.array.homeBackgroundEntries,
valuesId = R.array.homeBackgroundValues
)
)
val backgroundAlphaSetting: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int =
(BackgroundHelper.getBackgroundAlpha(context) * 100).toInt()
override fun setInt(value: Int) {
BackgroundHelper.setBackgroundAlpha(context, value)
settingsViewModel.setShouldRecreate(true)
}
override val key: String = Settings.PREF_HOME_BACKGROUND_ALPHA
override val isRuntimeModifiable: Boolean = true
override val pairedSettingKey: String = ""
override val isSwitchable: Boolean = false
override var global: Boolean = true
override val isSaveable: Boolean = true
override val defaultValue: Int = Settings.HOME_BACKGROUND_ALPHA_DEFAULT
override fun getValueAsString(needsGlobal: Boolean): String =
getInt(needsGlobal).toString()
override fun reset() {
setInt(defaultValue)
}
}
if (BackgroundHelper.getBackgroundStyle(context) != Settings.HOME_BACKGROUND_STYLE_NONE) {
add(
SliderSetting(
backgroundAlphaSetting,
titleId = R.string.home_background_opacity,
descriptionId = R.string.home_background_opacity_description,
min = 0,
max = 100,
units = "%"
)
)
}
add(HeaderSetting(R.string.buttons))
add(BooleanSetting.ENABLE_FOLDER_BUTTON.key)
add(BooleanSetting.ENABLE_QLAUNCH_BUTTON.key)
@@ -1,7 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -28,6 +25,7 @@ import org.yuzu.yuzu_emu.BuildConfig
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentAboutBinding
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.NativeLibrary
@@ -54,7 +52,9 @@ class AboutFragment : Fragment() {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
applyBackgroundPreference()
binding.toolbarAbout.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
@@ -108,6 +108,11 @@ class AboutFragment : Fragment() {
setInsets()
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
private fun openLink(link: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link))
startActivity(intent)
@@ -130,4 +135,8 @@ class AboutFragment : Fragment() {
windowInsets
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -19,13 +19,13 @@ import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.AddonAdapter
import org.yuzu.yuzu_emu.databinding.FragmentAddonsBinding
import org.yuzu.yuzu_emu.model.AddonViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.AddonUtil
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
@@ -42,7 +42,7 @@ class AddonsFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addonViewModel.onOpenAddons(args.game)
addonViewModel.onAddonsViewCreated(args.game)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
@@ -60,6 +60,7 @@ class AddonsFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(false)
applyBackgroundPreference()
binding.toolbarAddons.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
@@ -122,12 +123,15 @@ class AddonsFragment : Fragment() {
override fun onResume() {
super.onResume()
addonViewModel.refreshAddons()
addonViewModel.onAddonsViewStarted(args.game)
applyBackgroundPreference()
}
override fun onDestroy() {
if (activity?.isChangingConfigurations != true) {
addonViewModel.onCloseAddons()
}
super.onDestroy()
addonViewModel.onCloseAddons()
}
val installAddon =
@@ -167,7 +171,7 @@ class AddonsFragment : Fragment() {
} catch (_: Exception) {
return@newInstance errorMessage
}
addonViewModel.refreshAddons()
addonViewModel.refreshAddons(force = true)
return@newInstance getString(R.string.addon_installed_successfully)
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
} else {
@@ -201,4 +205,8 @@ class AddonsFragment : Fragment() {
windowInsets
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -21,6 +21,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentAppletLauncherBinding
import org.yuzu.yuzu_emu.model.Applet
import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class AppletLauncherFragment : Fragment() {
@@ -48,6 +49,7 @@ class AppletLauncherFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
applyBackgroundPreference()
binding.toolbarApplets.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
@@ -91,6 +93,11 @@ class AppletLauncherFragment : Fragment() {
setInsets()
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
@@ -108,4 +115,8 @@ class AppletLauncherFragment : Fragment() {
windowInsets
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -29,6 +29,8 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentDriverFetcherBinding
import org.yuzu.yuzu_emu.features.fetcher.DriverGroupAdapter
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import java.io.IOException
@@ -87,6 +89,7 @@ class DriverFetcherFragment : Fragment() {
private lateinit var driverGroupAdapter: DriverGroupAdapter
private val driverViewModel: DriverViewModel by activityViewModels()
private val homeViewModel: HomeViewModel by activityViewModels()
private fun parseAdrenoModel(): Int {
if (gpuModel == null) {
@@ -138,6 +141,8 @@ class DriverFetcherFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
applyBackgroundPreference()
binding.toolbarDrivers.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
@@ -152,6 +157,11 @@ class DriverFetcherFragment : Fragment() {
fetchDrivers()
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
private fun fetchDrivers() {
binding.loadingIndicator.isVisible = true
@@ -240,6 +250,10 @@ class DriverFetcherFragment : Fragment() {
windowInsets
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
data class Artifact(val url: URL, val name: String)
data class Release(
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -33,6 +33,7 @@ import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.File
@@ -66,6 +67,7 @@ class DriverManagerFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
applyBackgroundPreference()
driverViewModel.onOpenDriverManager(args.game)
if (NativeConfig.isPerGameConfigLoaded()) {
@@ -138,6 +140,11 @@ class DriverManagerFragment : Fragment() {
driverViewModel.onCloseDriverManager(args.game)
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
@@ -256,4 +263,8 @@ class DriverManagerFragment : Fragment() {
.setCancelable(false)
.show()
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -15,6 +15,7 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.graphics.Bitmap
import android.net.Uri
import android.os.BatteryManager
import android.os.BatteryManager.*
@@ -97,6 +98,7 @@ import org.yuzu.yuzu_emu.utils.collect
import org.yuzu.yuzu_emu.utils.CustomSettingsHandler
import java.io.ByteArrayOutputStream
import java.io.File
import java.nio.ByteBuffer
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlin.or
@@ -141,6 +143,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private var wasInputOverlayAutoHidden = false
private var overlayTouchActive = false
private var pausedFrameBitmap: Bitmap? = null
var shouldUseCustom = false
private var isQuickSettingsMenuOpen = false
@@ -703,6 +706,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.inGameMenu.menu.findItem(R.id.menu_quick_settings)?.isVisible =
BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean()
binding.pausedIcon.setOnClickListener {
if (this::emulationState.isInitialized && emulationState.isPaused) {
resumeEmulationFromUi()
}
}
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
val lockMode = IntSetting.LOCK_DRAWER.getInt()
val titleId = if (lockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
@@ -728,11 +737,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
when (it.itemId) {
R.id.menu_pause_emulation -> {
if (emulationState.isPaused) {
emulationState.run(false)
updatePauseMenuEntry(false)
resumeEmulationFromUi()
} else {
emulationState.pause()
updatePauseMenuEntry(true)
pauseEmulationAndCaptureFrame()
}
binding.inGameMenu.requestFocus()
true
@@ -826,6 +833,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
R.id.menu_exit -> {
clearPausedFrame()
emulationState.stop()
NativeConfig.reloadGlobalConfig()
emulationViewModel.setIsEmulationStopping(true)
@@ -1197,6 +1205,71 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
private fun pauseEmulationAndCaptureFrame() {
emulationState.pause()
updatePauseMenuEntry(true)
capturePausedFrameFromCore()
updatePausedFrameVisibility()
}
private fun capturePausedFrameFromCore() {
lifecycleScope.launch(Dispatchers.Default) {
val frameData = NativeLibrary.getAppletCaptureBuffer()
val width = NativeLibrary.getAppletCaptureWidth()
val height = NativeLibrary.getAppletCaptureHeight()
if (frameData.isEmpty() || width <= 0 || height <= 0) {
Log.warning(
"[EmulationFragment] Paused frame capture returned empty/invalid data. " +
"size=${frameData.size}, width=$width, height=$height"
)
return@launch
}
val expectedSize = width * height * 4
if (frameData.size < expectedSize) {
Log.warning(
"[EmulationFragment] Paused frame buffer smaller than expected. " +
"size=${frameData.size}, expected=$expectedSize"
)
return@launch
}
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(frameData, 0, expectedSize))
withContext(Dispatchers.Main) {
pausedFrameBitmap?.recycle()
pausedFrameBitmap = bitmap
updatePausedFrameVisibility()
}
}
}
private fun updatePausedFrameVisibility() {
val b = _binding ?: return
val showPausedUi = this::emulationState.isInitialized && emulationState.isPaused
b.pausedIcon.setVisible(showPausedUi)
val bitmap = if (showPausedUi) pausedFrameBitmap else null
b.pausedFrameImage.setImageBitmap(bitmap)
b.pausedFrameImage.setVisible(bitmap != null)
}
private fun resumeEmulationFromUi() {
clearPausedFrame()
emulationState.resume()
updatePauseMenuEntry(emulationState.isPaused)
updatePausedFrameVisibility()
}
private fun clearPausedFrame() {
val b = _binding
b?.pausedFrameImage?.setVisible(false)
b?.pausedFrameImage?.setImageDrawable(null)
pausedFrameBitmap?.recycle()
pausedFrameBitmap = null
}
private fun handleLoadAmiiboSelection(): Boolean {
val binding = _binding ?: return true
@@ -1290,8 +1363,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
override fun onPause() {
if (this::emulationState.isInitialized) {
if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) {
emulationState.pause()
updatePauseMenuEntry(true)
pauseEmulationAndCaptureFrame()
} else {
updatePausedFrameVisibility()
}
}
super.onPause()
@@ -1301,6 +1375,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
super.onDestroyView()
amiiboLoadJob?.cancel()
amiiboLoadJob = null
clearPausedFrame()
_binding?.surfaceInputOverlay?.touchEventListener = null
_binding = null
isAmiiboPickerOpen = false
@@ -1321,6 +1396,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
b.inGameMenu.post {
if (!this::emulationState.isInitialized || _binding == null) return@post
updatePauseMenuEntry(emulationState.isPaused)
updatePausedFrameVisibility()
}
}
@@ -1760,6 +1836,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
// Only update surface reference, don't trigger state changes
emulationState.updateSurfaceReference(holder.surface)
}
updatePausedFrameVisibility()
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
@@ -2090,6 +2167,29 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
@Synchronized
fun resume() {
if (state != State.PAUSED) {
Log.warning("[EmulationFragment] Resume called while emulation is not paused.")
return
}
if (!emulationCanStart.invoke()) {
Log.warning("[EmulationFragment] Resume blocked by emulationCanStart check.")
return
}
val currentSurface = surface
if (currentSurface == null || !currentSurface.isValid) {
Log.debug("[EmulationFragment] Resume requested with invalid surface.")
return
}
NativeLibrary.surfaceChanged(currentSurface)
Log.debug("[EmulationFragment] Resuming emulation.")
NativeLibrary.unpauseEmulation()
NativeLibrary.playTimeManagerStart()
state = State.RUNNING
}
@Synchronized
fun changeProgram(programIndex: Int) {
emulationThread.join()
@@ -2111,7 +2211,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@Synchronized
fun updateSurface() {
if (surface != null) {
if (surface != null && state == State.RUNNING) {
NativeLibrary.surfaceChanged(surface)
}
}
@@ -2127,20 +2227,20 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@Synchronized
fun clearSurface() {
if (surface == null) {
Log.warning("[EmulationFragment] clearSurface called, but surface already null.")
Log.debug("[EmulationFragment] clearSurface called, but surface already null.")
} else {
if (state == State.RUNNING) {
pause()
}
NativeLibrary.surfaceDestroyed()
surface = null
Log.debug("[EmulationFragment] Surface destroyed.")
when (state) {
State.RUNNING -> {
state = State.PAUSED
}
State.PAUSED -> Log.warning(
State.PAUSED -> Log.debug(
"[EmulationFragment] Surface cleared while emulation paused."
)
else -> Log.warning(
else -> Log.debug(
"[EmulationFragment] Surface cleared while emulation stopped."
)
}
@@ -2148,29 +2248,35 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
private fun runWithValidSurface(programIndex: Int = 0) {
NativeLibrary.surfaceChanged(surface)
if (!emulationCanStart.invoke()) {
return
}
val currentSurface = surface
if (currentSurface == null || !currentSurface.isValid) {
Log.debug("[EmulationFragment] runWithValidSurface called with invalid surface.")
return
}
when (state) {
State.STOPPED -> {
NativeLibrary.surfaceChanged(currentSurface)
emulationThread = Thread({
Log.debug("[EmulationFragment] Starting emulation thread.")
NativeLibrary.run(gamePath, programIndex, true)
}, "NativeEmulation")
emulationThread.start()
state = State.RUNNING
}
State.PAUSED -> {
Log.debug("[EmulationFragment] Resuming emulation.")
NativeLibrary.unpauseEmulation()
NativeLibrary.playTimeManagerStart()
Log.debug(
"[EmulationFragment] Surface restored while emulation paused; " +
"waiting for explicit resume."
)
}
else -> Log.debug("[EmulationFragment] Bug, run called while already running.")
}
state = State.RUNNING
}
private enum class State {
@@ -20,8 +20,10 @@ import org.yuzu.yuzu_emu.adapters.FreedrenoPresetAdapter
import org.yuzu.yuzu_emu.adapters.FreedrenoVariableAdapter
import org.yuzu.yuzu_emu.databinding.FragmentFreedrenoSettingsBinding
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
import org.yuzu.yuzu_emu.utils.FreedrenoPresets
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class FreedrenoSettingsFragment : Fragment() {
@@ -67,6 +69,7 @@ class FreedrenoSettingsFragment : Fragment() {
setupAdapters()
loadCurrentSettings()
setupButtonListeners()
applyBackgroundPreference()
setupWindowInsets()
}
@@ -74,10 +77,15 @@ class FreedrenoSettingsFragment : Fragment() {
binding.toolbarFreedreno.setNavigationOnClickListener {
requireActivity().onBackPressedDispatcher.onBackPressed()
}
if (isPerGameConfig) {
binding.toolbarFreedreno.title = getString(R.string.freedreno_per_game_title)
binding.toolbarFreedreno.subtitle = game!!.title
}
binding.toolbarFreedreno.title = getString(
if (isPerGameConfig) {
R.string.freedreno_per_game_title
} else {
R.string.freedreno_settings_title
}
)
binding.toolbarFreedreno.subtitle = null
}
private fun setupAdapters() {
@@ -175,16 +183,28 @@ class FreedrenoSettingsFragment : Fragment() {
private fun setupWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
val systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
binding.root.updatePadding(
left = systemInsets.left,
right = systemInsets.right,
bottom = systemInsets.bottom
)
val barInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = insets.getInsets(WindowInsetsCompat.Type.displayCutout())
val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right
binding.appbarFreedreno.updateMargins(left = leftInsets, right = rightInsets)
binding.scrollFreedreno.updateMargins(left = leftInsets, right = rightInsets)
binding.scrollFreedreno.updatePadding(bottom = barInsets.bottom)
insets
}
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
private fun showSnackbar(message: String) {
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
}
@@ -26,6 +26,7 @@ import org.yuzu.yuzu_emu.model.GameDir
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
@@ -57,6 +58,7 @@ class GameFoldersFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
applyBackgroundPreference()
binding.toolbarFolders.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
@@ -100,6 +102,11 @@ class GameFoldersFragment : Fragment() {
setInsets()
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
override fun onStop() {
super.onStop()
gamesViewModel.onCloseGameFoldersFragment()
@@ -133,4 +140,8 @@ class GameFoldersFragment : Fragment() {
windowInsets
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -26,6 +26,7 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentGameInfoBinding
import org.yuzu.yuzu_emu.model.GameVerificationResult
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.GameMetadata
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
@@ -60,6 +61,7 @@ class GameInfoFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(false)
applyBackgroundPreference()
binding.apply {
toolbarInfo.title = args.game.title
@@ -143,6 +145,11 @@ class GameInfoFragment : Fragment() {
setInsets()
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
private fun copyToClipboard(label: String, body: String) {
val clipBoard =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
@@ -175,4 +182,8 @@ class GameInfoFragment : Fragment() {
windowInsets
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -48,6 +48,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
@@ -83,6 +84,7 @@ class GamePropertiesFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(true)
applyBackgroundPreference()
binding.buttonBack.setOnClickListener {
view.findNavController().popBackStack()
@@ -310,6 +312,21 @@ class GamePropertiesFragment : Fragment() {
)
)
if (!args.game.isHomebrew) {
add(
SubmenuProperty(
R.string.add_ons,
R.string.add_ons_description,
R.drawable.ic_edit,
action = {
val action = GamePropertiesFragmentDirections
.actionPerGamePropertiesFragmentToAddonsFragment(args.game)
binding.root.findNavController().navigate(action)
}
)
)
}
if (GpuDriverHelper.supportsCustomDriverLoading()) {
add(
SubmenuProperty(
@@ -341,18 +358,6 @@ class GamePropertiesFragment : Fragment() {
}
if (!args.game.isHomebrew) {
add(
SubmenuProperty(
R.string.add_ons,
R.string.add_ons_description,
R.drawable.ic_edit,
action = {
val action = GamePropertiesFragmentDirections
.actionPerGamePropertiesFragmentToAddonsFragment(args.game)
binding.root.findNavController().navigate(action)
}
)
)
add(
InstallableProperty(
R.string.save_data,
@@ -484,6 +489,7 @@ class GamePropertiesFragment : Fragment() {
override fun onResume() {
super.onResume()
applyBackgroundPreference()
driverViewModel.updateDriverNameForGame(args.game)
getPlayTime()
reloadList()
@@ -708,4 +714,8 @@ class GamePropertiesFragment : Fragment() {
).show()
}
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -1,9 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.Manifest
@@ -43,8 +40,11 @@ import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class HomeSettingsFragment : Fragment() {
private var _binding: FragmentHomeSettingsBinding? = null
@@ -71,8 +71,13 @@ class HomeSettingsFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = true)
homeViewModel.setStatusBarShadeVisibility(visible = false)
mainActivity = requireActivity() as MainActivity
binding.toolbarHomeSettings.setNavigationOnClickListener {
findNavController().popBackStack()
}
binding.toolbarHomeSettings.title = getString(R.string.preferences_settings)
applyBackgroundPreference()
val optionsList: MutableList<HomeSetting> = mutableListOf<HomeSetting>().apply {
add(
@@ -144,6 +149,18 @@ class HomeSettingsFragment : Fragment() {
driverViewModel.selectedDriverTitle
)
)
if (GpuDriverHelper.isAdrenoGpu()) {
add(
HomeSetting(
R.string.freedreno_settings_title,
R.string.gpu_driver_settings,
R.drawable.ic_graphics,
{
binding.root.findNavController().navigate(R.id.freedrenoSettingsFragment)
}
)
)
}
add(
HomeSetting(
R.string.multiplayer,
@@ -300,6 +317,7 @@ class HomeSettingsFragment : Fragment() {
override fun onResume() {
super.onResume()
driverViewModel.updateDriverNameForGame(null)
applyBackgroundPreference()
}
override fun onDestroyView() {
@@ -465,21 +483,28 @@ class HomeSettingsFragment : Fragment() {
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
binding.appbarHomeSettings.updateMargins(
left = barInsets.left + cutoutInsets.left,
right = barInsets.right + cutoutInsets.right
)
binding.scrollViewSettings.updatePadding(
top = barInsets.top
bottom = barInsets.bottom
)
binding.homeSettingsList.updatePadding(
left = barInsets.left + cutoutInsets.left,
top = cutoutInsets.top,
right = barInsets.right + cutoutInsets.right,
bottom = barInsets.bottom
right = barInsets.right + cutoutInsets.right
)
windowInsets
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.logoImage, requireContext())
}
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@@ -32,6 +32,7 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.BufferedOutputStream
@@ -68,6 +69,7 @@ class InstallableFragment : Fragment() {
val mainActivity = requireActivity() as MainActivity
homeViewModel.setStatusBarShadeVisibility(visible = false)
applyBackgroundPreference()
binding.toolbarInstallables.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
@@ -162,6 +164,11 @@ class InstallableFragment : Fragment() {
setInsets()
}
override fun onResume() {
super.onResume()
applyBackgroundPreference()
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
@@ -325,4 +332,8 @@ class InstallableFragment : Fragment() {
}
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -21,6 +21,7 @@ import org.yuzu.yuzu_emu.adapters.ProfileAdapter
import org.yuzu.yuzu_emu.databinding.FragmentProfileManagerBinding
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.UserProfile
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.NativeConfig
class ProfileManagerFragment : Fragment() {
@@ -49,6 +50,7 @@ class ProfileManagerFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
applyBackgroundPreference()
binding.toolbarProfiles.setNavigationOnClickListener {
findNavController().popBackStack()
@@ -75,6 +77,7 @@ class ProfileManagerFragment : Fragment() {
override fun onResume() {
super.onResume()
loadProfiles()
applyBackgroundPreference()
}
private fun setupRecyclerView() {
@@ -187,4 +190,8 @@ class ProfileManagerFragment : Fragment() {
NativeConfig.saveGlobalConfig()
_binding = null
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
}
@@ -18,7 +18,7 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
import java.util.concurrent.atomic.AtomicBoolean
class AddonViewModel : ViewModel() {
private val _patchList = MutableStateFlow(mutableListOf<Patch>())
private val _patchList = MutableStateFlow<List<Patch>>(emptyList())
val addonList get() = _patchList.asStateFlow()
private val _showModInstallPicker = MutableStateFlow(false)
@@ -31,34 +31,62 @@ class AddonViewModel : ViewModel() {
val addonToDelete = _addonToDelete.asStateFlow()
var game: Game? = null
private var loadedGameKey: String? = null
private val isRefreshing = AtomicBoolean(false)
private val pendingRefresh = AtomicBoolean(false)
fun onOpenAddons(game: Game) {
fun onAddonsViewCreated(game: Game) {
this.game = game
refreshAddons()
refreshAddons(commitEmpty = false)
}
fun refreshAddons() {
if (isRefreshing.get() || game == null) {
fun onAddonsViewStarted(game: Game) {
this.game = game
val hasLoadedCurrentGame = loadedGameKey == gameKey(game)
refreshAddons(force = !hasLoadedCurrentGame)
}
fun refreshAddons(force: Boolean = false, commitEmpty: Boolean = true) {
val currentGame = game ?: return
val currentGameKey = gameKey(currentGame)
if (!force && loadedGameKey == currentGameKey) {
return
}
isRefreshing.set(true)
if (!isRefreshing.compareAndSet(false, true)) {
if (force) {
pendingRefresh.set(true)
}
return
}
viewModelScope.launch {
withContext(Dispatchers.IO) {
val patchList = (
NativeLibrary.getPatchesForFile(game!!.path, game!!.programId)
?: emptyArray()
).toMutableList()
try {
val patches = withContext(Dispatchers.IO) {
NativeLibrary.getPatchesForFile(currentGame.path, currentGame.programId)
} ?: return@launch
val patchList = patches.toMutableList()
patchList.sortBy { it.name }
// Ensure only one update is enabled
ensureSingleUpdateEnabled(patchList)
removeDuplicates(patchList)
if (patchList.isEmpty() && !commitEmpty) {
return@launch
}
if (gameKey(game ?: return@launch) != currentGameKey) {
return@launch
}
_patchList.value = patchList
_patchList.value = patchList.toList()
loadedGameKey = currentGameKey
} finally {
isRefreshing.set(false)
if (pendingRefresh.compareAndSet(true, false)) {
refreshAddons(force = true)
}
}
}
}
@@ -119,28 +147,33 @@ class AddonViewModel : ViewModel() {
PatchType.DLC -> NativeLibrary.removeDLC(patch.programId)
PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name)
}
refreshAddons()
refreshAddons(force = true)
}
fun onCloseAddons() {
if (_patchList.value.isEmpty()) {
val currentGame = game ?: run {
_patchList.value = emptyList()
loadedGameKey = null
return
}
val currentList = _patchList.value
if (currentList.isEmpty()) {
_patchList.value = emptyList()
loadedGameKey = null
game = null
return
}
// Check if there are multiple update versions
val updates = _patchList.value.filter { PatchType.from(it.type) == PatchType.Update }
val hasMultipleUpdates = updates.size > 1
NativeConfig.setDisabledAddons(
game!!.programId,
_patchList.value.mapNotNull {
currentGame.programId,
currentList.mapNotNull {
if (it.enabled) {
null
} else {
if (PatchType.from(it.type) == PatchType.Update) {
if (it.name.contains("(NAND)") || it.name.contains("(SDMC)")) {
it.name
} else if (hasMultipleUpdates) {
} else if (it.numericVersion != 0L) {
"Update@${it.numericVersion}"
} else {
it.name
@@ -152,7 +185,8 @@ class AddonViewModel : ViewModel() {
}.toTypedArray()
)
NativeConfig.saveGlobalConfig()
_patchList.value.clear()
_patchList.value = emptyList()
loadedGameKey = null
game = null
}
@@ -163,4 +197,8 @@ class AddonViewModel : ViewModel() {
fun showModNoticeDialog(show: Boolean) {
_showModNoticeDialog.value = show
}
private fun gameKey(game: Game): String {
return "${game.programId}|${game.path}"
}
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.overlay
@@ -20,7 +20,6 @@ import android.os.Looper
import android.util.AttributeSet
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import android.view.SurfaceView
import android.view.View
import android.view.View.OnTouchListener
import android.view.WindowInsets
@@ -42,10 +41,10 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
/**
* Draws the interactive input overlay on top of the
* [SurfaceView] that is rendering emulation.
* emulation rendering surface.
*/
class InputOverlay(context: Context, attrs: AttributeSet?) :
SurfaceView(context, attrs),
View(context, attrs),
OnTouchListener {
private val overlayButtons: MutableSet<InputOverlayDrawableButton> = HashSet()
private val overlayDpads: MutableSet<InputOverlayDrawableDpad> = HashSet()
@@ -40,6 +40,7 @@ import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.BackgroundHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
import info.debatty.java.stringsimilarity.Jaccard
@@ -106,6 +107,7 @@ class GamesFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(true)
mainActivity = requireActivity() as MainActivity
applyBackgroundPreference()
if (savedInstanceState != null) {
binding.searchText.setText(savedInstanceState.getString(SEARCH_TEXT))
@@ -252,6 +254,7 @@ class GamesFragment : Fragment() {
override fun onResume() {
super.onResume()
applyBackgroundPreference()
if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) {
(binding.gridGames as? CarouselRecyclerView)?.setupCarousel(true)
(binding.gridGames as? CarouselRecyclerView)?.restoreScrollState(gamesViewModel.lastScrollPosition)
@@ -497,6 +500,10 @@ class GamesFragment : Fragment() {
binding.addDirectory.visibility = if (showFolder) View.VISIBLE else View.GONE
}
private fun applyBackgroundPreference() {
BackgroundHelper.applyBackground(binding.backgroundLogo, requireContext())
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
@@ -424,7 +424,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
)
val uriString = result.toString()
val folder = gamesViewModel.folders.value.firstOrNull { it.uriString == uriString }
val folder = gamesViewModel.folders.value.firstOrNull {
it.uriString == uriString && it.type == org.yuzu.yuzu_emu.model.DirectoryType.EXTERNAL_CONTENT
}
if (folder != null) {
Toast.makeText(
applicationContext,
@@ -640,7 +642,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}
addonViewModel.refreshAddons()
addonViewModel.refreshAddons(force = true)
val separator = System.lineSeparator() ?: "\n"
val installResult = StringBuilder()
@@ -0,0 +1,64 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.utils
import android.content.Context
import android.view.View
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.Settings
object BackgroundHelper {
fun getBackgroundStyle(context: Context): Int {
return PreferenceManager.getDefaultSharedPreferences(context).getInt(
Settings.PREF_HOME_BACKGROUND_STYLE,
Settings.HOME_BACKGROUND_STYLE_DEFAULT
)
}
fun setBackgroundStyle(context: Context, style: Int) {
PreferenceManager.getDefaultSharedPreferences(context).edit {
putInt(Settings.PREF_HOME_BACKGROUND_STYLE, style)
}
}
fun getBackgroundAlpha(context: Context): Float {
val alphaPercent = PreferenceManager.getDefaultSharedPreferences(context).getInt(
Settings.PREF_HOME_BACKGROUND_ALPHA,
Settings.HOME_BACKGROUND_ALPHA_DEFAULT
).coerceIn(0, 100)
return alphaPercent / 100f
}
fun setBackgroundAlpha(context: Context, alphaPercent: Int) {
PreferenceManager.getDefaultSharedPreferences(context).edit {
putInt(Settings.PREF_HOME_BACKGROUND_ALPHA, alphaPercent.coerceIn(0, 100))
}
}
fun applyBackground(view: View, context: Context) {
val isEnabled = getBackgroundStyle(context) != Settings.HOME_BACKGROUND_STYLE_NONE
val visibilityStrength = getBackgroundAlpha(context)
val parent = view.parent as? View
val scrim = parent?.findViewById<View>(R.id.background_scrim)
view.visibility = if (isEnabled) View.VISIBLE else View.GONE
if (!isEnabled) {
scrim?.visibility = View.GONE
return
}
if (scrim != null) {
// Keep background image opaque; control perceived intensity through a cheap flat-color scrim.
view.alpha = 1f
scrim.visibility = View.VISIBLE
scrim.alpha = (1f - visibilityStrength).coerceIn(0f, 1f)
} else {
view.alpha = visibilityStrength
}
}
}
@@ -61,6 +61,12 @@ object DirectoryInitialization {
saveConfig = true
}
val staticThemeColor = preferences.migratePreference<Int>(Settings.PREF_STATIC_THEME_COLOR)
if (staticThemeColor != null) {
IntSetting.STATIC_THEME_COLOR.setInt(staticThemeColor)
saveConfig = true
}
val blackBackgrounds =
preferences.migratePreference<Boolean>(Settings.PREF_BLACK_BACKGROUNDS)
if (blackBackgrounds != null) {
@@ -51,11 +51,24 @@ object GameHelper {
// Scan External Content directories and register all NSP/XCI files
val externalContentDirs = NativeConfig.getExternalContentDirs()
for (externalDir in externalContentDirs) {
val uniqueExternalContentDirs = linkedSetOf<String>()
externalContentDirs.forEach { externalDir ->
if (externalDir.isNotEmpty()) {
uniqueExternalContentDirs.add(externalDir)
}
}
val mountedContainerUris = mutableSetOf<String>()
for (externalDir in uniqueExternalContentDirs) {
if (externalDir.isNotEmpty()) {
val externalDirUri = externalDir.toUri()
if (FileUtil.isTreeUriValid(externalDirUri)) {
scanExternalContentRecursive(FileUtil.listFiles(externalDirUri), 3)
scanContentContainersRecursive(FileUtil.listFiles(externalDirUri), 3) {
val containerUri = it.uri.toString()
if (mountedContainerUris.add(containerUri)) {
NativeLibrary.addFileToFilesystemProvider(containerUri)
}
}
}
}
}
@@ -65,10 +78,13 @@ object GameHelper {
val gameDirUri = gameDir.uriString.toUri()
val isValid = FileUtil.isTreeUriValid(gameDirUri)
if (isValid) {
val scanDepth = if (gameDir.deepScan) 3 else 1
addGamesRecursive(
games,
FileUtil.listFiles(gameDirUri),
if (gameDir.deepScan) 3 else 1
scanDepth,
mountedContainerUris
)
} else {
badDirs.add(index)
@@ -103,9 +119,10 @@ object GameHelper {
// be done better imo.
private val externalContentExtensions = setOf("nsp", "xci")
private fun scanExternalContentRecursive(
private fun scanContentContainersRecursive(
files: Array<MinimalDocumentFile>,
depth: Int
depth: Int,
onContainerFound: (MinimalDocumentFile) -> Unit
) {
if (depth <= 0) {
return
@@ -113,14 +130,15 @@ object GameHelper {
files.forEach {
if (it.isDirectory) {
scanExternalContentRecursive(
scanContentContainersRecursive(
FileUtil.listFiles(it.uri),
depth - 1
depth - 1,
onContainerFound
)
} else {
val extension = FileUtil.getExtension(it.uri).lowercase()
if (externalContentExtensions.contains(extension)) {
NativeLibrary.addFileToFilesystemProvider(it.uri.toString())
onContainerFound(it)
}
}
}
@@ -129,7 +147,8 @@ object GameHelper {
private fun addGamesRecursive(
games: MutableList<Game>,
files: Array<MinimalDocumentFile>,
depth: Int
depth: Int,
mountedContainerUris: MutableSet<String>
) {
if (depth <= 0) {
return
@@ -140,11 +159,20 @@ object GameHelper {
addGamesRecursive(
games,
FileUtil.listFiles(it.uri),
depth - 1
depth - 1,
mountedContainerUris
)
} else {
if (Game.extensions.contains(FileUtil.getExtension(it.uri))) {
val game = getGame(it.uri, true)
val extension = FileUtil.getExtension(it.uri).lowercase()
val filePath = it.uri.toString()
if (externalContentExtensions.contains(extension) &&
mountedContainerUris.add(filePath)) {
NativeLibrary.addGameFolderFileToFilesystemProvider(filePath)
}
if (Game.extensions.contains(extension)) {
val game = getGame(it.uri, true, false)
if (game != null) {
games.add(game)
}
@@ -153,14 +181,20 @@ object GameHelper {
}
}
fun getGame(uri: Uri, addedToLibrary: Boolean): Game? {
fun getGame(
uri: Uri,
addedToLibrary: Boolean,
registerFilesystemProvider: Boolean = true
): Game? {
val filePath = uri.toString()
if (!GameMetadata.getIsValid(filePath)) {
return null
}
// Needed to update installed content information
NativeLibrary.addFileToFilesystemProvider(filePath)
if (registerFilesystemProvider) {
// Needed to update installed content information
NativeLibrary.addFileToFilesystemProvider(filePath)
}
var name = GameMetadata.getTitle(filePath)
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.utils
@@ -80,16 +80,14 @@ object PathUtil {
}
}
// This really shouldn't be necessary, but the Android API seemingly
// doesn't have a way of doing this?
// Apparently, on certain devices the mount location can vary, so add
// extra cases here if we discover any new ones.
fun getRemovableStoragePath(idString: String): String? {
var pathFile: File
val possibleMountPaths = listOf("/mnt/media_rw/$idString", "/storage/$idString")
pathFile = File("/mnt/media_rw/$idString");
if (pathFile.exists()) {
return pathFile.absolutePath
for (mountPath in possibleMountPaths) {
val pathFile = File(mountPath);
if (pathFile.exists()) {
return pathFile.absolutePath
}
}
return null
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.utils
@@ -52,7 +52,7 @@ object ThemeHelper {
}
private fun getSelectedStaticThemeColor(): Int {
val themeIndex = preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0)
val themeIndex = IntSetting.STATIC_THEME_COLOR.getInt(false)
val themes = arrayOf(
R.style.Theme_Eden_Main,
R.style.Theme_Yuzu_Main_Violet,
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -11,8 +11,7 @@ import android.graphics.*
import android.util.AttributeSet
import com.google.android.material.card.MaterialCardView
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.settings.model.Settings
import androidx.preference.PreferenceManager
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
class GradientBorderCardView @JvmOverloads constructor(
context: Context,
@@ -44,12 +43,7 @@ class GradientBorderCardView @JvmOverloads constructor(
}
private fun updateThemeState() {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val themeIndex = try {
prefs.getInt(Settings.PREF_STATIC_THEME_COLOR, 0)
} catch (e: Exception) {
0 // Default to Eden theme if error
}
val themeIndex = IntSetting.STATIC_THEME_COLOR.getInt(false)
isEdenTheme = themeIndex == 0
invalidate()
}
+2 -5
View File
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -27,10 +27,7 @@ if (ARCHITECTURE_arm64)
target_link_libraries(yuzu-android PRIVATE adrenotools)
endif()
if (ENABLE_OPENSSL OR ENABLE_WEB_SERVICE)
target_link_libraries(yuzu-android PRIVATE OpenSSL::SSL cpp-jwt::cpp-jwt)
endif()
target_link_libraries(yuzu-android PRIVATE OpenSSL::SSL cpp-jwt::cpp-jwt)
if (ENABLE_UPDATE_CHECKER)
target_compile_definitions(yuzu-android PUBLIC ENABLE_UPDATE_CHECKER)
endif()
@@ -33,6 +33,12 @@ void AndroidConfig::ReadAndroidValues() {
if (global) {
ReadAndroidUIValues();
ReadUIValues();
BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage));
Settings::values.ext_content_from_game_dirs = ReadBooleanSetting(
std::string("ext_content_from_game_dirs"),
std::make_optional(
Settings::values.ext_content_from_game_dirs.GetDefault()));
EndGroup();
ReadOverlayValues();
}
ReadDriverValues();
@@ -56,6 +56,7 @@ namespace AndroidSettings {
Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android};
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
Settings::Setting<s32> static_theme_color{linkage, 5, "static_theme_color", Settings::Category::Android};
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
Settings::Category::Android};
Settings::Setting<s32> app_language{linkage, 0, "app_language", Settings::Category::Android};
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@@ -14,6 +17,14 @@
#include "jni/native.h"
void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
if (!surface) {
LOG_INFO(Frontend, "EmuWindow_Android::OnSurfaceChanged received null surface");
m_window_width = 0;
m_window_height = 0;
window_info.render_surface = nullptr;
return;
}
m_window_width = ANativeWindow_getWidth(surface);
m_window_height = ANativeWindow_getHeight(surface);
@@ -96,6 +96,11 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj
return false;
}
if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) &&
!Loader::IsBootableGameContainer(file, file_type)) {
return false;
}
u64 program_id = 0;
Loader::ResultStatus res = loader->ReadProgramId(program_id);
if (res != Loader::ResultStatus::Success) {
+54 -103
View File
@@ -89,6 +89,8 @@
#include "jni/native.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/capture.h"
#include "video_core/textures/decoders.h"
#include "video_core/vulkan_common/vulkan_instance.h"
#include "video_core/vulkan_common/vulkan_surface.h"
#include "video_core/shader_notify.h"
@@ -215,107 +217,8 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath)
return;
}
const auto extension = Common::ToLower(filepath.substr(filepath.find_last_of('.') + 1));
if (extension == "nsp") {
auto nsp = std::make_shared<FileSys::NSP>(file);
if (nsp->GetStatus() == Loader::ResultStatus::Success) {
std::map<u64, u32> nsp_versions;
std::map<u64, std::string> nsp_version_strings;
for (const auto& [title_id, nca_map] : nsp->GetNCAs()) {
for (const auto& [type_pair, nca] : nca_map) {
const auto& [title_type, content_type] = type_pair;
if (content_type == FileSys::ContentRecordType::Meta) {
const auto meta_nca = std::make_shared<FileSys::NCA>(nca->GetBaseFile());
if (meta_nca->GetStatus() == Loader::ResultStatus::Success) {
const auto section0 = meta_nca->GetSubdirectories();
if (!section0.empty()) {
for (const auto& meta_file : section0[0]->GetFiles()) {
if (meta_file->GetExtension() == "cnmt") {
FileSys::CNMT cnmt(meta_file);
nsp_versions[cnmt.GetTitleID()] = cnmt.GetTitleVersion();
}
}
}
}
}
if (content_type == FileSys::ContentRecordType::Control &&
title_type == FileSys::TitleType::Update) {
auto romfs = nca->GetRomFS();
if (romfs) {
auto extracted = FileSys::ExtractRomFS(romfs);
if (extracted) {
auto nacp_file = extracted->GetFile("control.nacp");
if (!nacp_file) {
nacp_file = extracted->GetFile("Control.nacp");
}
if (nacp_file) {
FileSys::NACP nacp(nacp_file);
auto ver_str = nacp.GetVersionString();
if (!ver_str.empty()) {
nsp_version_strings[title_id] = ver_str;
}
}
}
}
}
}
}
for (const auto& [title_id, nca_map] : nsp->GetNCAs()) {
for (const auto& [type_pair, nca] : nca_map) {
const auto& [title_type, content_type] = type_pair;
if (title_type == FileSys::TitleType::Update) {
u32 version = 0;
auto ver_it = nsp_versions.find(title_id);
if (ver_it != nsp_versions.end()) {
version = ver_it->second;
}
std::string version_string;
auto str_it = nsp_version_strings.find(title_id);
if (str_it != nsp_version_strings.end()) {
version_string = str_it->second;
}
m_manual_provider->AddEntryWithVersion(
title_type, content_type, title_id, version, version_string,
nca->GetBaseFile());
LOG_DEBUG(Frontend, "Added NSP update entry - TitleID: {:016X}, Version: {}, VersionStr: {}",
title_id, version, version_string);
} else {
// Use regular AddEntry for non-updates
m_manual_provider->AddEntry(title_type, content_type, title_id,
nca->GetBaseFile());
LOG_DEBUG(Frontend, "Added NSP entry - TitleID: {:016X}, TitleType: {}, ContentType: {}",
title_id, static_cast<int>(title_type), static_cast<int>(content_type));
}
}
}
return;
}
}
// Handle XCI files
if (extension == "xci") {
FileSys::XCI xci{file};
if (xci.GetStatus() == Loader::ResultStatus::Success) {
const auto nsp = xci.GetSecurePartitionNSP();
if (nsp) {
for (const auto& title : nsp->GetNCAs()) {
for (const auto& entry : title.second) {
m_manual_provider->AddEntry(entry.first.first, entry.first.second, title.first,
entry.second->GetBaseFile());
}
}
}
return;
}
if (m_manual_provider->AddEntriesFromContainer(file)) {
return;
}
auto loader = Loader::GetLoader(m_system, file);
@@ -337,6 +240,13 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath)
}
}
void EmulationSession::ConfigureFilesystemProviderFromGameFolder(const std::string& filepath) {
if (!Settings::values.ext_content_from_game_dirs.GetValue()) {
return;
}
ConfigureFilesystemProvider(filepath);
}
void EmulationSession::InitializeSystem(bool reload) {
if (!reload) {
// Initialize logging system
@@ -780,9 +690,10 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject i
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject instance) {
ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
if (auto* native_window = EmulationSession::GetInstance().NativeWindow(); native_window) {
ANativeWindow_release(native_window);
}
EmulationSession::GetInstance().SetNativeWindow(nullptr);
EmulationSession::GetInstance().SurfaceChanged();
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance,
@@ -969,6 +880,40 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass claz
return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused());
}
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletCaptureBuffer(JNIEnv* env, jclass clazz) {
using namespace VideoCore::Capture;
if (!EmulationSession::GetInstance().IsRunning()) {
return env->NewByteArray(0);
}
const auto tiled = EmulationSession::GetInstance().System().GPU().GetAppletCaptureBuffer();
if (tiled.size() < TiledSize) {
return env->NewByteArray(0);
}
std::vector<u8> linear(LinearWidth * LinearHeight * BytesPerPixel);
Tegra::Texture::UnswizzleTexture(linear, tiled, BytesPerPixel, LinearWidth, LinearHeight,
LinearDepth, BlockHeight, BlockDepth);
auto buffer = env->NewByteArray(static_cast<jsize>(linear.size()));
if (!buffer) {
return env->NewByteArray(0);
}
env->SetByteArrayRegion(buffer, 0, static_cast<jsize>(linear.size()),
reinterpret_cast<const jbyte*>(linear.data()));
return buffer;
}
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletCaptureWidth(JNIEnv* env, jclass clazz) {
return static_cast<jint>(VideoCore::Capture::LinearWidth);
}
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletCaptureHeight(JNIEnv* env, jclass clazz) {
return static_cast<jint>(VideoCore::Capture::LinearHeight);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz,
jboolean reload) {
// Initialize the emulated system.
@@ -1572,6 +1517,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* e
Common::Android::GetJString(env, jpath));
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_addGameFolderFileToFilesystemProvider(
JNIEnv* env, jobject jobj, jstring jpath) {
EmulationSession::GetInstance().ConfigureFilesystemProviderFromGameFolder(
Common::Android::GetJString(env, jpath));
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, jobject jobj) {
EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries();
}
+4
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -46,6 +49,7 @@ public:
const Core::PerfStatsResults& PerfStats();
int ShadersBuilding();
void ConfigureFilesystemProvider(const std::string& filepath);
void ConfigureFilesystemProviderFromGameFolder(const std::string& filepath);
void InitializeSystem(bool reload);
void SetAppletId(int applet_id);
Core::SystemResultStatus InitializeEmulation(const std::string& filepath,
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="#E6FFFFFF" />
</shape>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/colorSurface" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="?attr/colorOutline" />
@@ -0,0 +1,248 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="16dp"
android:paddingHorizontal="16dp">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:gravity="start|center_vertical"
android:text="@string/multiplayer_room_browser"
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.card.MaterialCardView
android:id="@+id/search_background"
style="?attr/materialCardViewFilledStyle"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginEnd="16dp"
android:layout_weight="1"
app:cardBackgroundColor="?attr/colorSurfaceVariant"
app:cardCornerRadius="24dp">
<LinearLayout
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="16dp"
android:contentDescription="@string/home_search"
android:src="@drawable/ic_search"
app:tint="?attr/colorOnSurfaceVariant" />
<EditText
android:id="@+id/search_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:autofillHints=""
android:background="@android:color/transparent"
android:hint="@string/multiplayer_search_public_lobbies"
android:imeOptions="flagNoFullscreen"
android:inputType="text"
android:maxLines="1"
android:textColor="?attr/colorOnSurface" />
</LinearLayout>
<ImageView
android:id="@+id/clear_button"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:layout_marginEnd="48dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/clear"
android:src="@drawable/ic_clear"
android:visibility="invisible"
app:tint="?attr/colorOnSurfaceVariant"
tools:visibility="visible" />
<ImageView
android:id="@+id/btn_submit"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:layout_marginEnd="16dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/submit"
android:src="@drawable/ic_send"
app:tint="?attr/colorOnSurfaceVariant"
tools:visibility="visible" />
</com.google.android.material.card.MaterialCardView>
<FrameLayout
android:layout_width="48dp"
android:layout_height="48dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/refresh_button"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:text="@string/refresh"
app:icon="@drawable/ic_refresh" />
<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
<HorizontalScrollView
android:id="@+id/horizontalScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:clipToPadding="false"
android:fadingEdge="horizontal"
android:paddingHorizontal="16dp"
android:scrollbars="none">
<LinearLayout
android:id="@+id/chips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false">
<com.google.android.material.chip.Chip
android:id="@+id/chip_hide_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:checkable="true"
android:checked="false"
android:paddingStart="8dp"
android:paddingTop="6dp"
android:paddingEnd="8dp"
android:paddingBottom="6dp"
android:text="@string/multiplayer_hide_empty_rooms"
app:chipCornerRadius="16dp"
app:chipIconSize="18dp"
app:chipIconTint="?attr/colorOnSurface" />
<com.google.android.material.chip.Chip
android:id="@+id/chip_hide_full"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:checkable="true"
android:checked="false"
android:paddingStart="8dp"
android:paddingTop="6dp"
android:paddingEnd="8dp"
android:paddingBottom="6dp"
android:text="@string/multiplayer_hide_full_rooms"
app:chipCornerRadius="16dp"
app:chipIconSize="18dp"
app:chipIconTint="?attr/colorOnSurface" />
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/room_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:contentDescription="@string/room_list"
android:paddingBottom="16dp"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<LinearLayout
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:padding="32dp"
android:visibility="gone">
<ImageView
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_marginBottom="16dp"
android:alpha="0.5"
android:contentDescription="@string/refresh"
android:src="@drawable/ic_refresh"
app:tint="?attr/colorOnSurface" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/multiplayer_no_rooms_found"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
android:textColor="?attr/colorOnSurface" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/multiplayer_tap_refresh_to_check_again"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.button.MaterialButton
android:id="@+id/empty_refresh_button"
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/refresh"
app:icon="@drawable/ic_refresh" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/theme_dialog_background"
android:orientation="vertical">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:id="@+id/drag_handle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="20dp"
android:layout_weight="0.75">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:contentDescription="@string/multiplayer"
android:src="@drawable/ic_network"
app:tint="?attr/colorPrimary" />
</FrameLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.25"
android:orientation="vertical">
<TextView
android:id="@+id/text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:text="@string/multiplayer"
android:textAppearance="?attr/textAppearanceHeadline6"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_lobby_browser"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/multiplayer_public_room"
android:textColor="?attr/colorOnPrimary"
app:backgroundTint="?attr/colorPrimary"
app:cornerRadius="16dp"
app:icon="@drawable/ic_search"
app:iconPadding="12dp"
app:iconTint="?attr/colorOnPrimary" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_join"
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/multiplayer_join_room"
app:cornerRadius="16dp"
app:icon="@drawable/ic_install"
app:iconPadding="12dp" />
<Space
android:layout_width="16dp"
android:layout_height="match_parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_create"
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/multiplayer_create_room"
app:cornerRadius="16dp"
app:icon="@drawable/ic_add"
app:iconPadding="12dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
@@ -8,6 +8,29 @@
android:clipChildren="false"
>
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/background_scrim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/header"
android:layout_width="match_parent"
@@ -44,7 +67,12 @@
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@android:color/transparent"
app:cardCornerRadius="24dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="4dp"
>
@@ -103,7 +131,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -127,7 +160,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -151,7 +189,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -239,4 +282,4 @@
app:rippleColor="#99FFFFFF"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -12,70 +12,83 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingHorizontal="24dp"
android:paddingVertical="16dp">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="20dp"
android:layout_gravity="center_vertical"
app:tint="?attr/colorOnSurface"
tools:src="@drawable/ic_settings" />
<LinearLayout
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:orientation="vertical">
android:gravity="center_vertical"
android:orientation="horizontal">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/user_data"
android:textAlignment="viewStart" />
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="20dp"
android:layout_gravity="center_vertical"
app:tint="?attr/colorOnSurface"
tools:src="@drawable/ic_settings" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/user_data_description"
android:textAlignment="viewStart" />
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/user_data"
android:textAlignment="viewStart" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/user_data_description"
android:textAlignment="viewStart" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
app:icon="@drawable/ic_export"
tools:visibility="visible" />
android:layout_marginTop="10dp"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
app:icon="@drawable/ic_import"
tools:visibility="visible" />
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
app:icon="@drawable/ic_import"
tools:visibility="visible" />
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
app:icon="@drawable/ic_export"
tools:visibility="visible" />
</LinearLayout>
</LinearLayout>
@@ -5,8 +5,20 @@
android:id="@+id/coordinator_about"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
>
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_about"
android:layout_width="match_parent"
@@ -7,6 +7,16 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_info"
android:layout_width="match_parent"
@@ -7,6 +7,20 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.core.widget.NestedScrollView
android:id="@+id/list_all"
android:layout_width="0dp"
@@ -7,9 +7,13 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp"
android:background="?attr/selectableItemBackground"
android:background="@android:color/transparent"
android:clickable="true"
android:focusable="true">
android:focusable="true"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
@@ -2,11 +2,15 @@
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="?attr/materialCardViewOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
android:layout_marginVertical="12dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
@@ -27,10 +27,10 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="14dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:paddingBottom="6dp">
android:paddingTop="4dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingBottom="2dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/image_game_screen"
@@ -48,11 +48,14 @@
style="@style/SynthwaveText.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginTop="2dp"
android:gravity="center"
android:requiresFadingEdge="horizontal"
android:textAlignment="center"
android:textSize="14sp"
android:textStyle="bold"
android:maxLines="1"
android:ellipsize="end"
app:layout_constraintEnd_toEndOf="@+id/image_game_screen"
app:layout_constraintStart_toStartOf="@+id/image_game_screen"
app:layout_constraintTop_toBottomOf="@+id/image_game_screen"
@@ -27,10 +27,10 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="14dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:paddingBottom="6dp">
android:paddingTop="3dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingBottom="3dp">
<FrameLayout
android:id="@+id/image_container"
@@ -11,7 +11,7 @@
android:transitionName="card_game"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:cardBackgroundColor="@color/eden_card_background"
app:cardBackgroundColor="@android:color/transparent"
app:strokeWidth="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -27,6 +27,8 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium"
app:strokeColor="@color/eden_card_background"
app:strokeWidth="4dp"
tools:src="@drawable/default_icon" />
<com.google.android.material.textview.MaterialTextView
@@ -8,9 +8,14 @@
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginHorizontal="8dp"
android:background="@android:color/transparent"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="16dp">
app:cardCornerRadius="16dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:id="@+id/option_layout"
@@ -60,6 +65,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:textColor="?attr/colorPrimary"
android:textSize="14sp"
android:textStyle="bold"
android:singleLine="true"
@@ -2,11 +2,15 @@
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
android:layout_marginVertical="12dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
@@ -42,30 +46,37 @@
</LinearLayout>
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
app:icon="@drawable/ic_export"
tools:visibility="visible" />
android:gravity="center_horizontal"
android:orientation="vertical">
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
app:icon="@drawable/ic_import"
tools:visibility="visible" />
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
app:icon="@drawable/ic_export"
tools:visibility="visible" />
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
app:icon="@drawable/ic_import"
tools:visibility="visible" />
</LinearLayout>
</LinearLayout>
@@ -6,63 +6,75 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
android:layout_marginVertical="12dp"
android:background="@android:color/transparent"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingHorizontal="24dp"
android:paddingVertical="16dp">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="20dp"
android:layout_gravity="center_vertical"
app:tint="?attr/colorOnSurface"
tools:src="@drawable/ic_settings" />
<LinearLayout
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:orientation="vertical">
android:gravity="center_vertical"
android:orientation="horizontal">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/user_data"
android:textAlignment="viewStart" />
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="20dp"
android:layout_gravity="center_vertical"
app:tint="?attr/colorOnSurface"
tools:src="@drawable/ic_settings" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/user_data_description"
android:textAlignment="viewStart" />
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/user_data"
android:textAlignment="viewStart" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="@string/user_data_description"
android:textAlignment="viewStart" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_marginTop="10dp"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
@@ -71,11 +83,10 @@
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="8dp"
android:layout_marginStart="12dp"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
@@ -7,9 +7,13 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp"
android:background="?attr/selectableItemBackground"
android:background="@android:color/transparent"
android:clickable="true"
android:focusable="true">
android:focusable="true"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
@@ -81,14 +85,15 @@
android:visibility="gone"
tools:visibility="visible" />
<com.google.android.material.chip.ChipGroup
<LinearLayout
android:id="@+id/layoutSecondaryActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end|center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="24dp"
android:paddingVertical="8dp"
android:visibility="gone"
app:singleLine="false"
tools:visibility="visible" />
</LinearLayout>
@@ -6,18 +6,27 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
android:elevation="0dp">
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_scrollFlags="scroll|enterAlways|snap">
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
@@ -248,4 +257,4 @@
style="@style/Widget.Material3.Button.ElevatedButton" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
@@ -59,8 +59,11 @@
android:layout_marginBottom="16dp"
android:text="@string/multiplayer_public_room"
app:cornerRadius="16dp"
app:backgroundTint="?attr/colorPrimary"
app:icon="@drawable/ic_search"
app:iconPadding="12dp" />
app:iconPadding="12dp"
app:iconTint="?attr/colorOnPrimary"
android:textColor="?attr/colorOnPrimary" />
<Space
android:layout_width="20dp"
@@ -5,8 +5,20 @@
android:id="@+id/coordinator_about"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
>
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_about"
android:layout_width="match_parent"
@@ -51,12 +63,15 @@
android:src="@drawable/ic_yuzu" />
<com.google.android.material.card.MaterialCardView
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
app:cardCornerRadius="16dp">
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -84,14 +99,17 @@
<com.google.android.material.card.MaterialCardView
android:id="@+id/button_contributors"
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="12dp"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="16dp">
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -119,14 +137,17 @@
<com.google.android.material.card.MaterialCardView
android:id="@+id/button_licenses"
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="12dp"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="16dp">
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -161,7 +182,7 @@
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="16dp"
app:cardBackgroundColor="?attr/colorSurface"
app:cardBackgroundColor="@android:color/transparent"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
app:cardElevation="0dp">
@@ -6,8 +6,23 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_addons"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
@@ -18,6 +33,7 @@
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_addons"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
@@ -6,8 +6,20 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_applets"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
@@ -15,6 +27,7 @@
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_applets"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
@@ -7,19 +7,36 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_drivers"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:liftOnScrollTargetViewId="@id/list_drivers">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_drivers"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
@@ -6,6 +6,20 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
@@ -13,14 +27,15 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_drivers"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:liftOnScrollTargetViewId="@id/list_drivers">
android:touchscreenBlocksFocus="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_drivers"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
@@ -108,6 +108,22 @@
</FrameLayout>
<FrameLayout
android:id="@+id/paused_frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false">
<ImageView
android:id="@+id/paused_frame_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:scaleType="fitCenter"
android:visibility="gone" />
</FrameLayout>
<FrameLayout
android:id="@+id/input_container"
android:layout_width="match_parent"
@@ -142,6 +158,18 @@
android:layout_height="match_parent"
android:fitsSystemWindows="false">
<ImageView
android:id="@+id/paused_icon"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center"
android:background="@drawable/circle_white"
android:contentDescription="@string/emulation_unpause"
android:padding="14dp"
android:src="@drawable/ic_play"
android:visibility="gone"
app:tint="@android:color/black" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/show_stats_overlay_text"
style="@style/TextAppearance.Material3.BodySmall"
@@ -6,20 +6,35 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_folders"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:liftOnScrollTargetViewId="@id/list_folders">
android:touchscreenBlocksFocus="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_folders"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
@@ -6,37 +6,36 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_freedreno"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:elevation="0dp">
android:touchscreenBlocksFocus="false">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbar_freedreno_layout"
style="?attr/collapsingToolbarLayoutMediumStyle"
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_freedreno"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="?attr/colorSurface"
app:scrimVisibleHeightTrigger="100dp">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_freedreno"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_back"
app:title="@string/gpu_driver_settings" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
app:navigationIcon="@drawable/ic_back" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_freedreno"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
@@ -63,8 +62,12 @@
android:id="@+id/list_freedreno_presets"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingBottom="8dp"
android:scrollbars="horizontal"
android:scrollbarStyle="outsideInset"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<!-- Current Settings Section -->
@@ -135,22 +138,23 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="16dp"
android:spacing="8dp">
android:orientation="horizontal">
<Button
android:id="@+id/button_clear_all"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_weight="1"
android:text="@string/freedreno_clear_all"
style="?attr/materialButtonOutlinedStyle" />
style="?attr/materialButtonOutlinedStyle"
android:text="@string/freedreno_clear_all" />
<Button
android:id="@+id/button_save"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:text="@string/save" />
@@ -161,6 +165,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeWidth="1dp"
app:strokeColor="?attr/colorOutline">
@@ -7,6 +7,16 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_info"
android:layout_width="match_parent"
@@ -6,6 +6,20 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.core.widget.NestedScrollView
android:id="@+id/list_all"
android:layout_width="match_parent"
@@ -33,9 +47,12 @@
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@android:color/transparent"
app:icon="@drawable/ic_back"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -44,9 +61,12 @@
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@android:color/transparent"
app:icon="@drawable/ic_shortcut"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -8,6 +8,29 @@
android:clipChildren="false"
>
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/background_scrim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/header"
android:layout_width="match_parent"
@@ -37,7 +60,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -61,7 +89,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -85,7 +118,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@@ -117,7 +155,12 @@
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@android:color/transparent"
app:cardCornerRadius="24dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="4dp"
>
@@ -246,4 +289,4 @@
app:rippleColor="#99FFFFFF"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,38 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scroll_view_settings"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:fadeScrollbars="false"
android:clipToPadding="false"
android:background="?attr/colorSurface"
android:defaultFocusHighlightEnabled="false">
android:background="?attr/colorSurface">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/linear_layout_settings"
<ImageView
android:id="@+id/logo_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.12"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_home_settings"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="16dp">
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/logo_image"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginTop="48dp"
android:layout_marginBottom="24dp"
android:layout_gravity="center_horizontal"
android:src="@drawable/ic_yuzu" />
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_home_settings"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
app:navigationIcon="@drawable/ic_back"
app:title="@string/preferences_settings" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_settings_list"
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_view_settings"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
android:clipToPadding="false"
android:defaultFocusHighlightEnabled="false"
android:fadeScrollbars="false"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appbar_home_settings">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/linear_layout_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:nestedScrollingEnabled="false" />
android:orientation="vertical"
android:paddingHorizontal="16dp"
android:paddingTop="16dp">
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_settings_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:nestedScrollingEnabled="false" />
</androidx.core.widget.NestedScrollView>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -6,8 +6,20 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_installables"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
@@ -15,6 +27,7 @@
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_installables"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
@@ -8,14 +8,27 @@
android:background="?attr/colorSurface"
android:fitsSystemWindows="true">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_profiles"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/profile_manager"
@@ -6,32 +6,32 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<ImageView
android:id="@+id/background_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:alpha="0.1"
android:contentDescription="@null"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
android:src="@drawable/eden_background" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_settings"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:elevation="0dp">
android:touchscreenBlocksFocus="false">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbar_settings_layout"
style="?attr/collapsingToolbarLayoutMediumStyle"
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_settings"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="?attr/colorSurface"
app:scrimVisibleHeightTrigger="100dp">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_settings"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_back" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
app:navigationIcon="@drawable/ic_back" />
</com.google.android.material.appbar.AppBarLayout>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.button.MaterialButton xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp" />
@@ -11,8 +11,11 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
@@ -78,8 +81,11 @@
android:layout_width="48dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="10dp"
app:cardElevation="2dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
@@ -100,7 +106,7 @@
android:layout_gravity="center"
android:background="@null"
android:src="@drawable/ic_delete"
app:tint="@color/eden_border_gradient_end"
app:tint="?attr/colorPrimary"
android:contentDescription="@string/delete" />
</FrameLayout>
@@ -40,6 +40,10 @@
<action
android:id="@+id/action_global_settingsActivity"
app:destination="@id/settingsActivity" />
app:destination="@id/settingsActivity"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
</navigation>
@@ -101,7 +101,11 @@
<action
android:id="@+id/action_global_settingsActivity"
app:destination="@id/settingsActivity" />
app:destination="@id/settingsActivity"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<fragment
android:id="@+id/installableFragment"
android:name="org.yuzu.yuzu_emu.fragments.InstallableFragment"
@@ -383,6 +383,15 @@
<item>2</item>
</integer-array>
<string-array name="homeBackgroundEntries">
<item>@string/background_none</item>
<item>@string/background_eden_default</item>
</string-array>
<integer-array name="homeBackgroundValues">
<item>0</item>
<item>1</item>
</integer-array>
<string-array name="appLanguageNames">
<item>@string/app_language_system</item>
<item>@string/app_language_english</item>
@@ -1160,6 +1160,12 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">App Settings</string>
<string name="theme_and_color">Theme And Color</string>
<string name="home_background">Home background</string>
<string name="home_background_description">Show a decorative background across app screens.</string>
<string name="home_background_opacity">Background opacity</string>
<string name="home_background_opacity_description">Adjust the background visibility strength.</string>
<string name="background_none">None</string>
<string name="background_eden_default">Eden (default)</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Change theme mode</string>
@@ -1222,12 +1228,12 @@
<!-- Static Themes -->
<string name="static_theme_color">Theme Color</string>
<string name="eden_theme">Eden (Default)</string>
<string name="eden_theme">Eden</string>
<string name="violet">Violet</string>
<string name="blue">Blue</string>
<string name="cyan">Cyan</string>
<string name="red">Red</string>
<string name="green">Green</string>
<string name="green">Green (Default)</string>
<string name="yellow">Yellow</string>
<string name="orange">Orange</string>
<string name="pink">Pink</string>

Some files were not shown because too many files have changed in this diff Show More