Compare commits

...

203 Commits

Author SHA1 Message Date
ceef790cbb Android 207 2024-01-24 01:01:09 +00:00
910718dc91 Merge yuzu-emu#12749 2024-01-24 01:01:09 +00:00
4bb06f44fa Merge yuzu-emu#12499 2024-01-24 01:01:09 +00:00
a76f6a2775 Merge pull request #12763 from liamwhite/fix-hbl-again
loader: also register fs process for raw exefs partition
2024-01-23 13:31:41 -05:00
ba518f6899 Merge pull request #12768 from german77/wrong_conversion
service: properly convert buffers to strings
2024-01-23 13:31:27 -05:00
fc5d76e6e2 service: properly convert buffers to strings 2024-01-23 10:24:05 -06:00
5f9a45ada9 loader: also register fs process for raw exefs partition 2024-01-23 00:01:38 -05:00
8649a80071 Merge pull request #12753 from liamwhite/why
device_memory_manager: fix ScratchBuffer indexing
2024-01-22 14:55:07 -05:00
550cadbee4 device_memory_manager: fix ScratchBuffer indexing 2024-01-22 14:07:33 -05:00
8bd10473d6 Merge pull request #12579 from FernandoS27/smmu
Core: Implement Device Mapping & GPU SMMU
2024-01-22 10:55:39 -05:00
8d708b0c79 Merge pull request #12747 from t895/homescreen-widget
android: Add to launcher button
2024-01-22 10:55:25 -05:00
beaab10c8f android: Add to launcher button 2024-01-22 08:19:20 -05:00
889c5d2705 Merge pull request #12739 from t895/debug-keystore
android: Provide debug.keystore for debug and relWithDebInfo builds
2024-01-22 04:34:17 -05:00
17b0aac809 Merge pull request #12738 from t895/lock-drawer
android: Port "Lock drawer" feature from Citra
2024-01-22 04:34:08 -05:00
399220ddbc Merge pull request #12736 from t895/verify-contents
android: Add verify contents buttons
2024-01-22 04:33:56 -05:00
59080a3d1d android: Provide debug.keystore for debug and relWithDebInfo builds
Allows devs to share debug builds with testers without uninstalling the previous build
2024-01-21 22:08:07 -05:00
3a25a217e6 android: Port "Lock drawer" feature from Citra 2024-01-21 20:47:28 -05:00
961b5586a5 frontend_common: Remove default value for installer callbacks
We never used these without callbacks and these will break without them in their current state. I could write the default value to return false always but that's unnecessary for now.
2024-01-21 19:31:26 -05:00
57ff934f0d Merge pull request #12734 from german77/enable-applet
service: hid: Implement EnableAppletForInput
2024-01-21 19:15:53 -05:00
92ce9273ee Merge pull request #12735 from german77/disable-vibration
core: hid: Allow to disable vibration
2024-01-21 19:15:46 -05:00
dd36d43ea1 android: Add options to verify installed content 2024-01-21 19:15:11 -05:00
a7a7720752 core: hid: Allow to disable vibration 2024-01-21 16:44:31 -06:00
c725f3c86c frontend_common: Move integrity verification to content_manager 2024-01-21 16:36:37 -05:00
1b984738ab service: hid: Implement EnableAppletForInput 2024-01-21 14:05:18 -06:00
a3199401f4 Merge pull request #12733 from german77/settings_services
service: set: Don't allow invalid mii author id
2024-01-21 14:08:58 -05:00
a7620a29be service: set: Don't allow invalid mii author id 2024-01-21 12:18:18 -06:00
5ac1297fa5 Merge pull request #12728 from t895/sync-translations
android: Sync translations
2024-01-21 00:38:49 -05:00
fe69105f71 android: Sync translations 2024-01-20 23:26:47 -05:00
93a3342841 Merge pull request #12720 from t895/return-to-global
android: Change "Clear" to "Use global setting" for per-game settings
2024-01-20 13:56:31 -05:00
7b3e26acc9 android: Change "Clear" to "Use global setting" for per-game settings 2024-01-20 13:37:47 -05:00
444e86d191 Merge pull request #12688 from liamwhite/wl-present-fix
renderer_vulkan: recreate swapchain when frame size changes
2024-01-20 13:36:18 -05:00
61ce0088ae Merge pull request #12724 from merryhime/fs-u8str-overloads
fs/file: Explicitly convert std::u8string to std::filesystem::path
2024-01-20 13:35:41 -05:00
b3aa3633c7 Merge pull request #12721 from t895/card-elevation
android: Use elevated card style for home setting card
2024-01-20 13:35:30 -05:00
627ba271ad Merge pull request #12719 from t895/sort-search
android: Sort recently added/played games by time
2024-01-20 13:35:14 -05:00
2faa631676 Merge pull request #12715 from t895/remove-addons
android: Add uninstall addon button
2024-01-20 13:35:03 -05:00
5838779162 Merge pull request #12660 from german77/better-vibration
service: hid: Fully implement abstract vibration
2024-01-20 13:34:54 -05:00
23fd1041c1 Merge pull request #12701 from liamwhite/flinger-layer-issues
vi: check layer state before opening or closing
2024-01-20 13:34:32 -05:00
5c398ede6f fs/file: Explicitly convert std::u8string to std::filesystem::path 2024-01-20 17:46:30 +00:00
378e4752a6 android: Use elevated card style for home setting card 2024-01-20 03:55:48 -05:00
dad48f16b7 android: Sort recently added/played games by time 2024-01-20 03:18:48 -05:00
a363fa78ef frontend_common: Add documentation for content_mananger 2024-01-19 20:54:50 -05:00
03fa91ba3c android: Add addon delete button
Required some refactoring of retrieving patches in order for the frontend to pass the right information to ContentManager for deletion.
2024-01-19 20:54:50 -05:00
d79d4d5986 android: Use callback to update progress bar dialogs 2024-01-19 17:09:36 -05:00
ccd3dd842f frontend_common: Add content manager utility functions
Creates utility functions to remove/install DLC, updates, and base game content
2024-01-19 17:09:35 -05:00
b4a8e1ef8a Merge pull request #12713 from shinra-electric/mvk-127
macOS: Bump MoltenVK to v1.2.7
2024-01-19 13:07:14 -05:00
5ea8f05ec6 Bump MoltenVK to v1.2.7 2024-01-19 17:28:53 +01:00
10535e0016 Merge pull request #12687 from german77/amiibo-lock
core: hid: Disable special features before disconnecting the controllers
2024-01-19 09:33:31 -05:00
a8c552e261 Merge pull request #12695 from anpilley/user-arguments-v2
Allow -u to accept a username string in addition to index
2024-01-19 09:33:25 -05:00
932bd98824 Merge pull request #12709 from german77/npad-disc
service: hid: Clear controller status when aruid is no longer used
2024-01-19 09:33:16 -05:00
9f376cd901 service: hid: Clear controller status when aruid is no longer used 2024-01-19 00:09:49 -06:00
a560b9f5a2 Merge pull request #12678 from german77/settings_impl
service: set: Implement stubbed functions
2024-01-18 21:18:37 -05:00
4f04bd3697 Merge pull request #12683 from german77/amiibo-dump
service: nfc: Create backup when none exist
2024-01-18 21:18:27 -05:00
97c8b49444 Merge pull request #12644 from liamwhite/vkspec-image-offset
shader_recompiler: fix Offset operand usage for non-OpImage*Gather
2024-01-18 21:18:19 -05:00
748465f5a5 device_memory_manager: use unique_lock for update 2024-01-18 21:12:30 -05:00
04867e2456 nvhost_vic: use map erase by key 2024-01-18 21:12:30 -05:00
32f623e029 nvdrv: clean up preallocation 2024-01-18 21:12:30 -05:00
b6c6534c30 nvdrv: use correct names for interface factory 2024-01-18 21:12:30 -05:00
beb438bb0b nvdrv: use static typing for SessionId, smmu Asid types 2024-01-18 21:12:30 -05:00
4b963ca8a5 Core: Invert guest memory depandancy 2024-01-18 21:12:30 -05:00
648ed55fe6 Core: Make sure GPU Dirty Managers ae shared by all processes. 2024-01-18 21:12:30 -05:00
23430e6772 Core: Eliminate core/memory dependancies. 2024-01-18 21:12:30 -05:00
0672847330 SMMU: Fix Right Shift UB. 2024-01-18 21:12:30 -05:00
a874ab0133 SMMU: Fix 8Gb layout. 2024-01-18 21:12:30 -05:00
590d9b7e1d Core: Clang format and other small issues. 2024-01-18 21:12:30 -05:00
b0bca0f8b0 SMMU: Fix software rendering and cleanup 2024-01-18 21:12:30 -05:00
d8f1ce2f76 SMMU: Add continuity tracking optimization. 2024-01-18 21:12:30 -05:00
9b11b9dce5 SMMU: Simplify and remove old code. 2024-01-18 21:12:30 -05:00
303cd31162 SMMU: Add Android compatibility 2024-01-18 21:12:30 -05:00
0adc09e0af GPU-SMMU: Estimate game leak and preallocate device region. 2024-01-18 21:12:30 -05:00
96fd1348ae GPU SMMU: Expand to 34 bits 2024-01-18 21:12:30 -05:00
bad705f245 SMMU: Fix Unregister on MultiAddress 2024-01-18 21:12:30 -05:00
34a8d0cc8e SMMU: Implement physical memory mirroring 2024-01-18 21:12:30 -05:00
0a2536a0df SMMU: Initial adaptation to video_core. 2024-01-18 21:12:30 -05:00
c85d7ccd79 SMMU: Implement backing CPU page protect/unprotect 2024-01-18 21:12:30 -05:00
7a9d1ad2f8 NVDRV: Implement sessions and initial implementation of SMMU 2024-01-18 21:12:30 -05:00
2f0418c101 Core: Initial implementation of device memory mapping 2024-01-18 21:12:30 -05:00
3092855d5a Merge pull request #12702 from german77/android-input
input_common: Add android input engine
2024-01-18 09:16:58 -05:00
72f803c366 input_common: Add android input engine 2024-01-17 22:47:56 -06:00
c87b96435d Merge pull request #12699 from t895/overlay-saving
android: Save overlay data while using emulation fragment
2024-01-17 22:56:40 -05:00
e4bbb24dcf vi: check layer state before opening or closing 2024-01-17 22:03:40 -05:00
6536d29c61 Update based on feedback 2024-01-17 18:14:05 -08:00
116f76e4b6 android: Save overlay data while using emulation fragment
This should have been fully embraced before but the items within the popup menu and the adjust controls dialog fell through. This ensures that everything related to the overlay is saved during emulation and can't be lost during a crash.
2024-01-17 20:14:25 -05:00
ce89580749 nvnflinger: ensure display abandonment considers all layers and future layers 2024-01-17 18:45:39 -05:00
dff0a7c52a Allow -u to accept a username string in addition to index, and suppress the User selector even if settings requires it to be shown for one instance only. 2024-01-17 10:31:00 -08:00
915efa4236 Merge pull request #12689 from liamwhite/remove-format
ci: remove format dep from mainline step2
2024-01-17 00:36:07 -05:00
4548e5ae1d ci: remove format dep from mainline step2 2024-01-16 22:59:20 -05:00
46c2435235 Merge pull request #12380 from flodavid/save-profile
Save configuration profile name used by players
2024-01-16 21:27:25 -06:00
e9eb017aac renderer_vulkan: recreate swapchain when frame size changes 2024-01-16 16:09:39 -05:00
0b0e9ef18d core: hid: Disable special features before disconnecting the controllers 2024-01-16 14:44:54 -06:00
7f5adf8982 service: set: Implement stubbed functions 2024-01-15 23:17:03 -06:00
89d6856090 service: set: Refractor setting service 2024-01-15 23:16:36 -06:00
2cacb9d48c service: hid: Fully implement abstract vibration 2024-01-15 23:15:40 -06:00
2c29c2b8dd Merge pull request #12686 from szepeviktor/typos3
Fix more typos
2024-01-15 23:26:08 -05:00
16abda59be Fix typos in master 2024-01-16 00:09:25 +00:00
90ab89a0b0 Merge remote-tracking branch 'origin/master' into typos3 2024-01-16 00:09:00 +00:00
6531ad56a6 Fix typos in arrays.xml 2024-01-15 23:39:45 +00:00
e8671ed04e Fix one more typo 2024-01-15 23:34:11 +00:00
2044ae6b3a Fix more typos 2024-01-15 23:26:53 +00:00
c661b95864 service: nfc: Create backup when none exist 2024-01-15 14:07:54 -06:00
c683ec2bcb Merge pull request #12681 from t895/stick-toggles
android: Fix overlay toggle ordering
2024-01-15 13:52:53 -05:00
2e4e33156e Merge pull request #12680 from t895/format-mainline
ci: Remove format step from mainline builds
2024-01-15 13:52:48 -05:00
04f4eeaca2 Merge pull request #12677 from GPUCode/whyy-modders
core: Support multiple modules per patcher
2024-01-15 13:52:38 -05:00
2e4b32204c Merge pull request #12665 from german77/proof
service: acc: Only save profiles when profiles have changed
2024-01-15 13:52:33 -05:00
34db13486a Merge pull request #12659 from liamwhite/audio-memory
audio: fetch process object from handle table
2024-01-15 13:52:01 -05:00
c6c6bb4041 Merge pull request #12652 from liamwhite/huge-pile-of-spirv-spaghetti
shader_recompiler: emulate 8-bit and 16-bit storage writes with cas loop
2024-01-15 13:51:36 -05:00
a2ffb419c9 Merge pull request #12612 from liamwhite/fs-pid
fsp-srv: use program registry for SetCurrentProcess
2024-01-15 13:51:14 -05:00
0127cec371 Merge pull request #12611 from liamwhite/resource-management-is-hard
kernel: fix resource management issues
2024-01-15 13:50:58 -05:00
db3a6075f5 Merge pull request #12610 from liamwhite/reply-and-dont-receive
server_manager: respond to session close correctly
2024-01-15 13:50:43 -05:00
8876a15227 android: Fix overlay toggle ordering 2024-01-15 12:41:49 -05:00
954eb40237 ci: Remove format step from mainline builds 2024-01-15 10:30:57 -05:00
d4acdac168 core: Support multiple modules per patcher 2024-01-15 00:46:05 +02:00
817c7c445d Merge pull request #12667 from t895/version-info
android: Show version name instead of build hash in about fragment
2024-01-13 20:23:12 -05:00
da714a362b Merge pull request #12666 from t895/ktlint-yuzu-verify
android: Move ktlintCheck to yuzu-verify
2024-01-13 20:23:02 -05:00
7b3941e5d4 android: Show version name instead of git hash in the about fragment 2024-01-13 18:12:19 -05:00
15d8a40529 android: Clean up git commands in build.gradle 2024-01-13 18:06:33 -05:00
cdeaca73c4 android: Move ktlintCheck to yuzu-verify 2024-01-13 17:41:01 -05:00
bee22540a1 service: acc: Only save profiles when profiles have changed 2024-01-13 14:28:29 -06:00
76880b84f9 loader: fix homebrew nro registration 2024-01-13 13:48:56 -05:00
2f0b57ca13 kernel: optimize page free on shutdown 2024-01-12 19:19:07 -05:00
f90a022d3a kernel: fix debugger and process list lifetime 2024-01-12 18:31:33 -05:00
f2fed21c11 kernel: fix page leak on process termination 2024-01-12 18:31:33 -05:00
d940974789 audio: fetch process object from handle table 2024-01-12 10:03:16 -05:00
f7a3c135e2 Merge pull request #12605 from german77/abstract
service: hid: Create abstracted pad structure
2024-01-12 10:02:13 -05:00
fcb0dff67c Merge pull request #12642 from t895/adapter-refactor
android: Refactor list adapters
2024-01-12 10:01:54 -05:00
b5dac5f525 service: hid: Create abstracted pad structure 2024-01-11 19:35:04 -06:00
a4d90a9a64 Merge pull request #12653 from liamwhite/once-more
ci: fix file mode check in format script
2024-01-11 19:58:41 -05:00
84787a2ada ci: fix file mode check in format script 2024-01-11 18:57:07 -05:00
2a0d707ce1 shader_recompiler: emulate 8-bit and 16-bit storage writes with cas loop 2024-01-11 16:50:59 -05:00
aae9eea532 fsp-srv: use program registry for SetCurrentProcess 2024-01-11 11:28:52 -05:00
2044a289f8 shader_recompiler: fix Offset operand usage for non-OpImage*Gather 2024-01-11 00:56:37 -05:00
d3ba6b334b android: Fix added driver path
While this didn't break anything, the extra separator was unnecessary
2024-01-10 23:14:04 -05:00
dac8c4ce4d android: Add button to use global driver value 2024-01-10 23:14:04 -05:00
9e974d4c7e android: Reload driver data on importing user data 2024-01-10 23:14:04 -05:00
6bfc3c530c android: Rework driver fragment
Applies settings upon selection and uses a new Driver model to represent the information in-view. Also switches from an async diff list to a plain one.
2024-01-10 23:14:04 -05:00
93239f191a android: Refactor DriverAdapter to use AbstractSingleSelectionList 2024-01-10 23:14:04 -05:00
b17db2b462 android: Create generic single selection list adapter 2024-01-10 23:14:04 -05:00
9130366a58 android: Refactor recycler view adapters to use AbstractListAdapter 2024-01-10 23:14:04 -05:00
ad0066a6b6 android: Create generic list adapter for basic lists
Simplifies basic setup for lists
2024-01-10 23:14:04 -05:00
78c323c4eb android: Refactor async diff adapters to use AbstractDiffAdapter 2024-01-10 23:14:04 -05:00
51ad2d10de android: Create generic adapter and viewholder
Eliminates repeated code associated with every async differ list
2024-01-10 23:14:04 -05:00
6533dfd7ce Merge pull request #12639 from liamwhite/format-oops
ci: fix format task
2024-01-10 12:44:07 -05:00
e11a3414ae ci: fix format task 2024-01-10 11:52:58 -05:00
4fdc900581 Merge pull request #12634 from lat9nq/apple-intl-2
externals: Update txdb_to_nx
2024-01-09 18:42:57 -05:00
d99830b59c externals: Update txdb_to_nx
Includes a fix lat9nq/tzdb_to_nx@1e82342 that fixes a build issue on Mac OS.
2024-01-09 17:29:38 -05:00
23c11e50f9 Merge pull request #12609 from liamwhite/wrong-name-again
vi: minor cleanups
2024-01-09 11:15:56 -06:00
5fde5e62a8 Merge pull request #12622 from liamwhite/format
ci: make verify format workflow output more helpful
2024-01-09 07:31:34 -05:00
f124461674 Fix typos in src/core (#12625)
* Fix typos in src/core

* Fix typo correction

* Fix indentation of MemoryStateNames

* Fix indent
2024-01-08 13:31:48 -06:00
63b835f822 Save profile name used
- Save the profile name in global config
- Read the profile name when reading the global config
2024-01-08 18:43:56 +01:00
30743eff56 ci: make verify format workflow output more helpful 2024-01-08 09:52:25 -05:00
4f83b00f6f general: fix trailing whitespace 2024-01-08 09:34:32 -05:00
ea710e6523 vi: connect vsync event handle lifetime to application display service interface 2024-01-07 21:47:41 -05:00
200b371d13 server_manager: respond to session close correctly 2024-01-07 21:33:24 -05:00
ae88ea79b2 vi: fix name of nvnflinger 2024-01-07 21:31:03 -05:00
82b58668ed Merge pull request #12608 from szepeviktor/typos
Fix typos in video_core
2024-01-07 20:42:54 -05:00
bd80929ac1 Merge pull request #12606 from german77/npad_close
service: hid: Delete shared memory handle when unused
2024-01-07 20:41:11 -05:00
2a4ac7cfac Merge pull request #12600 from german77/npad-impl
service: hid: Hook interface implementations
2024-01-07 20:41:06 -05:00
ab513c378a Merge pull request #12599 from german77/settings
service: set: Use official names
2024-01-07 20:40:56 -05:00
a959fb011f Fix "Propietary" typo elsewhere 2024-01-07 23:15:38 +00:00
53085a45e0 Fix typos in video_core 2024-01-07 22:44:55 +00:00
bc2d1262d7 service: hid: Delete shared memory handle when unused 2024-01-07 12:55:24 -06:00
1220309323 Merge pull request #12560 from GayPotatoEmma/master
android: add basic support for google game dashboard
2024-01-07 10:43:53 -05:00
a972341b5d Merge pull request #12601 from german77/rocket
service: hid: Make sure there's an active aruid handle
2024-01-07 07:33:38 -05:00
87430acff1 Merge pull request #12576 from t895/total-save-manager
android: Re-add global save manager
2024-01-07 07:33:31 -05:00
0b4cc6e14c service: hid: Make sure there's an active aruid handle 2024-01-06 23:49:52 -06:00
5105b90017 service: hid: Implement GetLastActiveNpad 2024-01-06 23:30:43 -06:00
3516a2d0bf service: hid: Implement AssigningSingleOnSlSrPress 2024-01-06 23:30:42 -06:00
f224ef6185 service: hid: Implement SetNpadSystemExtStateEnabled 2024-01-06 23:30:41 -06:00
8e27a485d8 service: set: Rename files 2024-01-06 23:16:03 -06:00
a36f4d0a9f service: hid: Implement CaptureButtonAssignment 2024-01-06 21:18:44 -06:00
b71840bbd2 Merge pull request #12596 from german77/hid_qlaunch
service: hid: Add functions needed by QLaunch
2024-01-06 21:51:29 -05:00
71fbc87dbd Merge pull request #12593 from german77/pending-delete
service: hid: Handle pending delete
2024-01-06 21:51:22 -05:00
37b0870ee3 service: set: Use official names 2024-01-06 17:37:36 -06:00
3dbe998f9b service: hid: Add functions needed by Qlaunch 2024-01-06 16:10:37 -06:00
edfbf363de service: hid: Handle pending delete 2024-01-06 15:42:19 -06:00
12fd2ae86d Merge pull request #12582 from german77/hid-core
hid_core: Move hid to it's own subproject
2024-01-06 15:38:59 -06:00
ee847f8ff0 hid_core: Move hid to it's own subproject 2024-01-05 11:41:15 -06:00
92a331af76 Merge pull request #12437 from ameerj/gl-amd-fixes
OpenGL: Fixes and workaround updates for AMD
2024-01-04 15:53:44 -05:00
a8f62bff43 Merge pull request #12575 from t895/inconsistent-settings-application
frontend_common: config: Only write setting related to opened config file
2024-01-04 15:51:24 -05:00
519904e8a8 Merge pull request #12571 from t895/apply-orientation-on-start
android: Expose more orientation options
2024-01-04 15:51:08 -05:00
8d3463dbdd Merge pull request #12570 from t895/generic-config-pain
frontend_common: config: Move WriteIntegerSetting definition to header
2024-01-04 15:51:00 -05:00
b125cb97a2 Merge pull request #12568 from t895/actions-button
actions: android: Allow for manually triggering Android builds
2024-01-04 15:50:54 -05:00
d7e7a69e00 Merge pull request #12558 from t895/zip-storage-method
android: Disable compression for zip exports
2024-01-04 15:50:47 -05:00
246cffb624 Merge pull request #12557 from merryhime/termination-ipi
KThread: Send termination interrupt to all cores a thread has affinity to
2024-01-04 15:50:40 -05:00
0e93cad4f0 Merge pull request #12549 from german77/npadresource
service: hid: Implement NpadResource and NpadData
2024-01-04 15:50:33 -05:00
53d4dbacf0 android: Re-add global save manager
Reworked to correctly collect and import/export saves that could exist in either /nand/user/save/000...000/<user id> or /nand/user/save/account/<user id raw string>
2024-01-04 00:56:40 -05:00
39d28a5131 android: Save global config synchronously in onCloseGameFoldersFragment
Could cause multiple global saves at once that went untracked previously
2024-01-03 22:50:21 -05:00
fa04dea7c4 frontend_common: config: Only write setting related to opened config file
If we tried to write a switchable setting to config that was not using global in the global config instance, we could write the per-game setting accidentally. This ensures that we always use the global setting for global config and the currently applied setting for custom config.
2024-01-03 22:49:41 -05:00
1c278974a8 android: Don't save settings on config destruction
Android doesn't have a proper way of destroying its config object so it's best to stick to the built-in methods to control saving config
2024-01-03 22:12:15 -05:00
2b838b6d06 android: Update orientation on emulation fragment start 2024-01-03 21:35:45 -05:00
82ea082997 android: Expose all orientation locking options 2024-01-03 21:35:45 -05:00
5562322290 service: hid: Remove data races when handling shared memory 2024-01-03 20:21:16 -06:00
6a244465ce service: hid: Implement NpadResource and NpadData 2024-01-03 20:21:14 -06:00
e5de3d5a77 android: add basic support for google game dashboard 2024-01-04 01:07:43 +01:00
bdf87ba0f8 frontend_common: config: Move WriteIntegerSetting definition to header
Fixes a compiler error where the compiler could not see the definition of the method in qt_config and others.
2024-01-03 17:57:20 -05:00
3b314a68a1 actions: android: Prevent resolving tag commit to PR link 2024-01-03 17:01:31 -05:00
06c68fb196 actions: android: Resolve PR commits to link 2024-01-03 17:00:49 -05:00
9a31122c82 actions: android: Move trigger logic to be yuzu-android specific 2024-01-03 03:15:07 -05:00
dace726d08 android: Add internal option to disable compression for zip exports
Disables compression for user data and save exports
2024-01-02 18:11:22 -05:00
0f7fc94111 KThread: Send termination interrupt to all cores a thread has affinity to
KThread::RequestTerminate may run from a thread which is not the CurrentCore, and thus
masking this out is erroneous.
2024-01-02 21:34:34 +00:00
139b4cc9ea Settings: Indicate AMD's compatibility with SPIR-V on OGL 2023-12-21 22:00:49 -05:00
d5d0d2cb0e spirv_emit_context: Fix BaseInstance for OGL spirv 2023-12-21 21:53:24 -05:00
a5b2b8b91b emit_glsl_image: Use inlined texelFetch offsets 2023-12-20 19:24:11 -05:00
b4b301d22e gl_device: Remove AMD blacklists that are no longer applicable 2023-12-20 18:19:15 -05:00
683 changed files with 26602 additions and 11313 deletions

View File

@ -3,38 +3,35 @@
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop \
dist/*.svg dist/*.xml; then
shopt -s nullglob globstar
if git grep -nrI '\s$' src **/*.yml **/*.txt **/*.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop dist/*.svg dist/*.xml; then
echo Trailing whitespace found, aborting
exit 1
fi
# Default clang-format points to default 3.5 version one
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-15}
$CLANG_FORMAT --version
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
# Get list of every file modified in this pull request
files_to_lint="$(git diff --name-only --diff-filter=ACMRTUXB $TRAVIS_COMMIT_RANGE | grep '^src/[^.]*[.]\(cpp\|h\)$' || true)"
else
# Check everything for branch pushes
files_to_lint="$(find src/ -name '*.cpp' -or -name '*.h')"
fi
CLANG_FORMAT="${CLANG_FORMAT:-clang-format-15}"
"$CLANG_FORMAT" --version
# Turn off tracing for this because it's too verbose
set +x
for f in $files_to_lint; do
d=$(diff -u "$f" <($CLANG_FORMAT "$f") || true)
if ! [ -z "$d" ]; then
echo "!!! $f not compliant to coding style, here is the fix:"
echo "$d"
fail=1
fi
# Check everything for branch pushes
FILES_TO_LINT="$(find src/ -name '*.cpp' -or -name '*.h')"
for f in $FILES_TO_LINT; do
echo "$f"
"$CLANG_FORMAT" -i "$f"
done
set -x
DIFF=$(git -c core.fileMode=false diff)
if [ "$fail" = 1 ]; then
if [ ! -z "$DIFF" ]; then
echo "!!! Not compliant to coding style, here is the fix:"
echo "$DIFF"
exit 1
fi
cd src/android
./gradlew ktlintCheck

View File

@ -9,7 +9,7 @@ chmod a+x ./.ci/scripts/linux/docker.sh
sudo chown -R 1027 ./
# The environment variables listed below:
# AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION
# AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION
# are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps
docker run -e AZURECIREPO -e TITLEBARFORMATIDLE -e TITLEBARFORMATRUNNING -e DISPLAYVERSION -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh "$1"

View File

@ -8,17 +8,7 @@ variables:
DisplayVersion: $[counter(variables['DisplayPrefix'], 1)]
stages:
- stage: format
displayName: 'format'
jobs:
- job: format
displayName: 'clang'
pool:
vmImage: ubuntu-latest
steps:
- template: ./templates/format-check.yml
- stage: build
dependsOn: format
displayName: 'build'
jobs:
- job: build
@ -43,7 +33,6 @@ stages:
cache: 'true'
version: $(DisplayVersion)
- stage: build_win
dependsOn: format
displayName: 'build-windows'
jobs:
- job: build

View File

@ -10,7 +10,7 @@ const CHANGE_LABEL = 'android-merge';
// how far back in time should we consider the changes are "recent"? (default: 24 hours)
const DETECTION_TIME_FRAME = (parseInt(process.env.DETECTION_TIME_FRAME)) || (24 * 3600 * 1000);
async function checkBaseChanges(github, context) {
async function checkBaseChanges(github) {
// query the commit date of the latest commit on this branch
const query = `query($owner:String!, $name:String!, $ref:String!) {
repository(name:$name, owner:$owner) {
@ -22,8 +22,8 @@ async function checkBaseChanges(github, context) {
}
}`;
const variables = {
owner: context.repo.owner,
name: context.repo.repo,
owner: 'yuzu-emu',
name: 'yuzu',
ref: 'refs/heads/master',
};
const result = await github.graphql(query, variables);
@ -38,8 +38,8 @@ async function checkBaseChanges(github, context) {
return false;
}
async function checkAndroidChanges(github, context) {
if (checkBaseChanges(github, context)) return true;
async function checkAndroidChanges(github) {
if (checkBaseChanges(github)) return true;
const query = `query($owner:String!, $name:String!, $label:String!) {
repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) {
@ -48,8 +48,8 @@ async function checkAndroidChanges(github, context) {
}
}`;
const variables = {
owner: context.repo.owner,
name: context.repo.repo,
owner: 'yuzu-emu',
name: 'yuzu',
label: CHANGE_LABEL,
};
const result = await github.graphql(query, variables);
@ -90,8 +90,8 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
console.log(`New tag: ${newTag}`);
if (commit) {
let channelName = channel[0].toUpperCase() + channel.slice(1);
console.info(`Committing pending commit as ${channelName} #${tagNumber + 1}`);
await execa("git", ['commit', '-m', `${channelName} #${tagNumber + 1}`]);
console.info(`Committing pending commit as ${channelName} ${tagNumber + 1}`);
await execa("git", ['commit', '-m', `${channelName} ${tagNumber + 1}`]);
}
console.info('Pushing tags to GitHub ...');
await execa("git", ['tag', newTag]);
@ -157,7 +157,7 @@ async function mergePullRequests(pulls, execa) {
process1.stdout.pipe(process.stdout);
await process1;
const process2 = execa("git", ["commit", "-m", `Merge PR ${pr}`]);
const process2 = execa("git", ["commit", "-m", `Merge yuzu-emu#${pr}`]);
process2.stdout.pipe(process.stdout);
await process2;
@ -182,7 +182,30 @@ async function mergePullRequests(pulls, execa) {
return mergeResults;
}
async function resetBranch(execa) {
console.log("::group::Reset master branch");
let hasFailed = false;
try {
await execa("git", ["remote", "add", "source", "https://github.com/yuzu-emu/yuzu.git"]);
await execa("git", ["fetch", "source"]);
const process1 = await execa("git", ["rev-parse", "source/master"]);
const headCommit = process1.stdout;
await execa("git", ["reset", "--hard", headCommit]);
} catch (err) {
console.log(`::error title=Failed to reset master branch`);
hasFailed = true;
}
console.log("::endgroup::");
if (hasFailed) {
throw 'Failed to reset the master branch. Aborting!';
}
}
async function mergebot(github, context, execa) {
// Reset our local copy of master to what appears on yuzu-emu/yuzu - master
await resetBranch(execa);
const query = `query ($owner:String!, $name:String!, $label:String!) {
repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) {
@ -193,8 +216,8 @@ async function mergebot(github, context, execa) {
}
}`;
const variables = {
owner: context.repo.owner,
name: context.repo.repo,
owner: 'yuzu-emu',
name: 'yuzu',
label: CHANGE_LABEL,
};
const result = await github.graphql(query, variables);
@ -209,7 +232,7 @@ async function mergebot(github, context, execa) {
await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa);
const mergeResults = await mergePullRequests(pulls, execa);
await generateReadme(pulls, context, mergeResults, execa);
await tagAndPush(github, context.repo.owner, `${context.repo.repo}-android`, execa, true);
await tagAndPush(github, 'yuzu-emu', `yuzu-android`, execa, true);
}
module.exports.mergebot = mergebot;

View File

@ -16,7 +16,7 @@ on:
jobs:
android:
runs-on: ubuntu-latest
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu' }}
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu-android' }}
steps:
# this checkout is required to make sure the GitHub Actions scripts are available
- uses: actions/checkout@v3
@ -33,7 +33,7 @@ jobs:
script: |
if (context.payload.inputs && context.payload.inputs.android === 'true') return true;
const checkAndroidChanges = require('./.github/workflows/android-merge.js').checkAndroidChanges;
return checkAndroidChanges(github, context);
return checkAndroidChanges(github);
- run: npm install execa@5
if: ${{ steps.check-changes.outputs.result == 'true' }}
- uses: actions/checkout@v3

View File

@ -13,13 +13,15 @@ jobs:
format:
name: 'verify format'
runs-on: ubuntu-latest
container:
image: yuzuemu/build-environments:linux-clang-format
options: -u 1001
steps:
- uses: actions/checkout@v3
with:
submodules: false
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: 'Verify Formatting'
run: bash -ex ./.ci/scripts/format/script.sh
build:

View File

@ -155,3 +155,7 @@ License: MIT
Files: externals/gamemode/*
Copyright: Copyright 2017-2019 Feral Interactive
License: BSD-3-Clause
Files: src/android/app/debug.keystore
Copyright: 2023 yuzu Emulator Project
License: GPL-3.0-or-later

View File

@ -1,4 +1,4 @@
Copyright (c) <year> <owner>
Copyright (c) <year> <owner>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View File

@ -1,4 +1,4 @@
Copyright (c) <year> <owner>.
Copyright (c) <year> <owner>.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

View File

@ -35,7 +35,7 @@ Mozilla Public License Version 2.0
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"

View File

@ -1,3 +1,13 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12499](https://github.com/yuzu-emu/yuzu-android//pull/12499) | [`fc30a84fc`](https://github.com/yuzu-emu/yuzu-android//pull/12499/files) | Rework time services | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu-android//pull/12749) | [`e3171486d`](https://github.com/yuzu-emu/yuzu-android//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.
-----
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -178,6 +178,9 @@ if (NOT TARGET stb::headers)
add_library(stb::headers ALIAS stb)
endif()
add_library(tz tz/tz/tz.cpp)
target_include_directories(tz PUBLIC ./tz)
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
target_include_directories(bc_decoder PUBLIC ./bc_decoder)

View File

@ -138,7 +138,7 @@ if (NOT WIN32 AND NOT ANDROID)
--cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
--sysroot=${SYSROOT}
--target-os=android
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="-nostdlib"
)
endif()

1636
externals/tz/tz/tz.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

81
externals/tz/tz/tz.h vendored Normal file
View File

@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: 1996 Arthur David Olson
// SPDX-License-Identifier: BSD-2-Clause
#pragma once
#include <cstdint>
#include <limits>
#include <span>
#include <array>
#include <time.h>
namespace Tz {
using u8 = uint8_t;
using s8 = int8_t;
using u16 = uint16_t;
using s16 = int16_t;
using u32 = uint32_t;
using s32 = int32_t;
using u64 = uint64_t;
using s64 = int64_t;
constexpr size_t TZ_MAX_TIMES = 1000;
constexpr size_t TZ_MAX_TYPES = 128;
constexpr size_t TZ_MAX_CHARS = 50;
constexpr size_t MY_TZNAME_MAX = 255;
constexpr size_t TZNAME_MAXIMUM = 255;
constexpr size_t TZ_MAX_LEAPS = 50;
constexpr s64 TIME_T_MAX = std::numeric_limits<s64>::max();
constexpr s64 TIME_T_MIN = std::numeric_limits<s64>::min();
constexpr size_t CHARS_EXTRA = 3;
constexpr size_t MAX_ZONE_CHARS = std::max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof("UTC"));
constexpr size_t MAX_TZNAME_CHARS = 2 * (MY_TZNAME_MAX + 1);
struct ttinfo {
s32 tt_utoff;
bool tt_isdst;
s32 tt_desigidx;
bool tt_ttisstd;
bool tt_ttisut;
};
static_assert(sizeof(ttinfo) == 0x10, "ttinfo has the wrong size!");
struct Rule {
s32 timecnt;
s32 typecnt;
s32 charcnt;
bool goback;
bool goahead;
std::array <u8, 0x2> padding0;
std::array<s64, TZ_MAX_TIMES> ats;
std::array<u8, TZ_MAX_TIMES> types;
std::array<ttinfo, TZ_MAX_TYPES> ttis;
std::array<char, std::max(MAX_ZONE_CHARS, MAX_TZNAME_CHARS)> chars;
s32 defaulttype;
std::array <u8, 0x12C4> padding1;
};
static_assert(sizeof(Rule) == 0x4000, "Rule has the wrong size!");
struct CalendarTimeInternal {
s32 tm_sec;
s32 tm_min;
s32 tm_hour;
s32 tm_mday;
s32 tm_mon;
s32 tm_year;
s32 tm_wday;
s32 tm_yday;
s32 tm_isdst;
std::array<char, 16> tm_zone;
s32 tm_utoff;
s32 time_index;
};
static_assert(sizeof(CalendarTimeInternal) == 0x3C, "CalendarTimeInternal has the wrong size!");
s32 ParseTimeZoneBinary(Rule& out_rule, std::span<const u8> binary);
bool localtime_rz(CalendarTimeInternal* tmp, Rule* sp, time_t* timep);
u32 mktime_tzname(time_t* out_time, Rule* sp, CalendarTimeInternal* tmp);
} // namespace Tz

View File

@ -185,6 +185,7 @@ add_subdirectory(common)
add_subdirectory(core)
add_subdirectory(audio_core)
add_subdirectory(video_core)
add_subdirectory(hid_core)
add_subdirectory(network)
add_subdirectory(input_common)
add_subdirectory(frontend_common)

View File

@ -82,8 +82,8 @@ android {
}
val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")
if (keystoreFile != null) {
signingConfigs {
signingConfigs {
if (keystoreFile != null) {
create("release") {
storeFile = file(keystoreFile)
storePassword = System.getenv("ANDROID_KEYSTORE_PASS")
@ -91,6 +91,12 @@ android {
keyPassword = System.getenv("ANDROID_KEYSTORE_PASS")
}
}
create("default") {
storeFile = file("$projectDir/debug.keystore")
storePassword = "android"
keyAlias = "androiddebugkey"
keyPassword = "android"
}
}
// Define build types, which are orthogonal to product flavors.
@ -101,7 +107,7 @@ android {
signingConfig = if (keystoreFile != null) {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
signingConfigs.getByName("default")
}
resValue("string", "app_name_suffixed", "yuzu")
@ -118,7 +124,7 @@ android {
register("relWithDebInfo") {
isDefault = true
resValue("string", "app_name_suffixed", "yuzu Debug Release")
signingConfig = signingConfigs.getByName("debug")
signingConfig = signingConfigs.getByName("default")
isMinifyEnabled = true
isDebuggable = true
proguardFiles(
@ -133,6 +139,7 @@ android {
// Signed by debug key disallowing distribution on Play Store.
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
debug {
signingConfig = signingConfigs.getByName("default")
resValue("string", "app_name_suffixed", "yuzu Debug")
isDebuggable = true
isJniDebuggable = true
@ -188,8 +195,15 @@ tasks.create<Delete>("ktlintReset") {
delete(File(buildDir.path + File.separator + "intermediates/ktLint"))
}
val showFormatHelp = {
logger.lifecycle(
"If this check fails, please try running \"gradlew ktlintFormat\" for automatic " +
"codestyle fixes"
)
}
tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() }
tasks.getByPath("ktlintMainSourceSetCheck").doFirst { showFormatHelp.invoke() }
tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset")
tasks.getByPath("preBuild").dependsOn("ktlintCheck")
ktlint {
version.set("0.47.1")
@ -228,71 +242,33 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
}
fun getGitVersion(): String {
var versionName = "0.0"
try {
versionName = ProcessBuilder("git", "describe", "--always", "--long")
fun runGitCommand(command: List<String>): String {
return try {
ProcessBuilder(command)
.directory(project.rootDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start().inputStream.bufferedReader().use { it.readText() }
.trim()
} catch (e: Exception) {
logger.error("Cannot find git")
""
}
}
fun getGitVersion(): String {
val versionName = if (System.getenv("GITHUB_ACTIONS") != null) {
val gitTag = System.getenv("GIT_TAG_NAME") ?: ""
gitTag
} else {
runGitCommand(listOf("git", "describe", "--always", "--long"))
.replace(Regex("(-0)?-[^-]+$"), "")
} catch (e: Exception) {
logger.error("Cannot find git, defaulting to dummy version number")
}
if (System.getenv("GITHUB_ACTIONS") != null) {
val gitTag = System.getenv("GIT_TAG_NAME")
versionName = gitTag ?: versionName
}
return versionName
return versionName.ifEmpty { "0.0" }
}
fun getGitHash(): String {
try {
val processBuilder = ProcessBuilder("git", "rev-parse", "--short", "HEAD")
processBuilder.directory(project.rootDir)
val process = processBuilder.start()
val inputStream = process.inputStream
val errorStream = process.errorStream
process.waitFor()
fun getGitHash(): String =
runGitCommand(listOf("git", "rev-parse", "--short", "HEAD")).ifEmpty { "dummy-hash" }
return if (process.exitValue() == 0) {
inputStream.bufferedReader()
.use { it.readText().trim() } // return the value of gitHash
} else {
val errorMessage = errorStream.bufferedReader().use { it.readText().trim() }
logger.error("Error running git command: $errorMessage")
"dummy-hash" // return a dummy hash value in case of an error
}
} catch (e: Exception) {
logger.error("$e: Cannot find git, defaulting to dummy build hash")
return "dummy-hash" // return a dummy hash value in case of an error
}
}
fun getBranch(): String {
try {
val processBuilder = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
processBuilder.directory(project.rootDir)
val process = processBuilder.start()
val inputStream = process.inputStream
val errorStream = process.errorStream
process.waitFor()
return if (process.exitValue() == 0) {
inputStream.bufferedReader()
.use { it.readText().trim() } // return the value of gitHash
} else {
val errorMessage = errorStream.bufferedReader().use { it.readText().trim() }
logger.error("Error running git command: $errorMessage")
"dummy-hash" // return a dummy hash value in case of an error
}
} catch (e: Exception) {
logger.error("$e: Cannot find git, defaulting to dummy build hash")
return "dummy-hash" // return a dummy hash value in case of an error
}
}
fun getBranch(): String =
runGitCommand(listOf("git", "rev-parse", "--abbrev-ref", "HEAD")).ifEmpty { "dummy-hash" }

Binary file not shown.

View File

@ -31,6 +31,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:dataExtractionRules="@xml/data_extraction_rules_api_31"
android:enableOnBackInvokedCallback="true">
<meta-data android:name="android.game_mode_config"
android:resource="@xml/game_mode_config" />
<activity
android:name="org.yuzu.yuzu_emu.ui.main.MainActivity"
android:exported="true"

View File

@ -21,6 +21,9 @@ import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.Patch
import org.yuzu.yuzu_emu.model.GameVerificationResult
/**
* Class which contains methods that interact
@ -235,9 +238,12 @@ object NativeLibrary {
/**
* Installs a nsp or xci file to nand
* @param filename String representation of file uri
* @param extension Lowercase string representation of file extension without "."
* @return int representation of [InstallResult]
*/
external fun installFileToNand(filename: String, extension: String): Int
external fun installFileToNand(
filename: String,
callback: (max: Long, progress: Long) -> Boolean
): Int
external fun doesUpdateMatchProgram(programId: String, updatePath: String): Boolean
@ -535,9 +541,49 @@ object NativeLibrary {
*
* @param path Path to game file. Can be a [Uri].
* @param programId String representation of a game's program ID
* @return Array of pairs where the first value is the name of an addon and the second is the version
* @return Array of available patches
*/
external fun getAddonsForFile(path: String, programId: String): Array<Pair<String, String>>?
external fun getPatchesForFile(path: String, programId: String): Array<Patch>?
/**
* Removes an update for a given [programId]
* @param programId String representation of a game's program ID
*/
external fun removeUpdate(programId: String)
/**
* Removes all DLC for a [programId]
* @param programId String representation of a game's program ID
*/
external fun removeDLC(programId: String)
/**
* Removes a mod installed for a given [programId]
* @param programId String representation of a game's program ID
* @param name The name of a mod as given by [getPatchesForFile]. This corresponds with the name
* of the mod's directory in a game's load folder.
*/
external fun removeMod(programId: String, name: String)
/**
* Verifies all installed content
* @param callback UI callback for verification progress. Return true in the callback to cancel.
* @return Array of content that failed verification. Successful if empty.
*/
external fun verifyInstalledContents(
callback: (max: Long, progress: Long) -> Boolean
): Array<String>
/**
* Verifies the contents of a game
* @param path String path to a game
* @param callback UI callback for verification progress. Return true in the callback to cancel.
* @return Int that is meant to be converted to a [GameVerificationResult]
*/
external fun verifyGameContents(
path: String,
callback: (max: Long, progress: Long) -> Boolean
): Int
/**
* Gets the save location for a specific game
@ -547,6 +593,15 @@ object NativeLibrary {
*/
external fun getSavePath(programId: String): String
/**
* Gets the root save directory for the default profile as either
* /user/save/account/<user id raw string> or /user/save/000...000/<user id>
*
* @param future If true, returns the /user/save/account/... directory
* @return Save data path that may not exist yet
*/
external fun getDefaultProfileSaveDataRoot(future: Boolean): String
/**
* Adds a file to the manual filesystem provider in our EmulationSession instance
* @param path Path to the file we're adding. Can be a string representation of a [Uri] or
@ -600,15 +655,4 @@ object NativeLibrary {
const val RELEASED = 0
const val PRESSED = 1
}
/**
* Result from installFileToNand
*/
object InstallFileToNandResult {
const val Success = 0
const val SuccessFileOverwritten = 1
const val Error = 2
const val ErrorBaseGame = 3
const val ErrorFilenameExtension = 4
}
}

View File

@ -49,7 +49,6 @@ import org.yuzu.yuzu_emu.utils.ForegroundService
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.NfcReader
import org.yuzu.yuzu_emu.utils.ThemeHelper
import java.text.NumberFormat
@ -171,11 +170,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
stopMotionSensorListener()
}
override fun onStop() {
super.onStop()
NativeConfig.saveGlobalConfig()
}
override fun onUserLeaveHint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) {

View File

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.adapters
import android.annotation.SuppressLint
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
import androidx.recyclerview.widget.RecyclerView
/**
* Generic adapter that implements an [AsyncDifferConfig] and covers some of the basic boilerplate
* code used in every [RecyclerView].
* Type assigned to [Model] must inherit from [Object] in order to be compared properly.
*/
abstract class AbstractDiffAdapter<Model : Any, Holder : AbstractViewHolder<Model>> :
ListAdapter<Model, Holder>(AsyncDifferConfig.Builder(DiffCallback<Model>()).build()) {
override fun onBindViewHolder(holder: Holder, position: Int) =
holder.bind(currentList[position])
private class DiffCallback<Model> : DiffUtil.ItemCallback<Model>() {
override fun areItemsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean {
return oldItem === newItem
}
@SuppressLint("DiffUtilEquals")
override fun areContentsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean {
return oldItem == newItem
}
}
}

View File

@ -0,0 +1,98 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.adapters
import android.annotation.SuppressLint
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
/**
* Generic list class meant to take care of basic lists
* @param currentList The list to show initially
*/
abstract class AbstractListAdapter<Model : Any, Holder : AbstractViewHolder<Model>>(
open var currentList: List<Model>
) : RecyclerView.Adapter<Holder>() {
override fun onBindViewHolder(holder: Holder, position: Int) =
holder.bind(currentList[position])
override fun getItemCount(): Int = currentList.size
/**
* Adds an item to [currentList] and notifies the underlying adapter of the change. If no parameter
* is passed in for position, [item] is added to the end of the list. Invokes [callback] last.
* @param item The item to add to the list
* @param position Index where [item] will be added
* @param callback Lambda that's called at the end of the list changes and has the added list
* position passed in as a parameter
*/
open fun addItem(item: Model, position: Int = -1, callback: ((position: Int) -> Unit)? = null) {
val newList = currentList.toMutableList()
val positionToUpdate: Int
if (position == -1) {
newList.add(item)
currentList = newList
positionToUpdate = currentList.size - 1
} else {
newList.add(position, item)
currentList = newList
positionToUpdate = position
}
onItemAdded(positionToUpdate, callback)
}
protected fun onItemAdded(position: Int, callback: ((Int) -> Unit)? = null) {
notifyItemInserted(position)
callback?.invoke(position)
}
/**
* Replaces the [item] at [position] in the [currentList] and notifies the underlying adapter
* of the change. Invokes [callback] last.
* @param item New list item
* @param position Index where [item] will replace the existing list item
* @param callback Lambda that's called at the end of the list changes and has the changed list
* position passed in as a parameter
*/
fun changeItem(item: Model, position: Int, callback: ((position: Int) -> Unit)? = null) {
val newList = currentList.toMutableList()
newList[position] = item
currentList = newList
onItemChanged(position, callback)
}
protected fun onItemChanged(position: Int, callback: ((Int) -> Unit)? = null) {
notifyItemChanged(position)
callback?.invoke(position)
}
/**
* Removes the list item at [position] in [currentList] and notifies the underlying adapter
* of the change. Invokes [callback] last.
* @param position Index where the list item will be removed
* @param callback Lambda that's called at the end of the list changes and has the removed list
* position passed in as a parameter
*/
fun removeItem(position: Int, callback: ((position: Int) -> Unit)? = null) {
val newList = currentList.toMutableList()
newList.removeAt(position)
currentList = newList
onItemRemoved(position, callback)
}
protected fun onItemRemoved(position: Int, callback: ((Int) -> Unit)? = null) {
notifyItemRemoved(position)
callback?.invoke(position)
}
/**
* Replaces [currentList] with [newList] and notifies the underlying adapter of the change.
* @param newList The new list to replace [currentList]
*/
@SuppressLint("NotifyDataSetChanged")
open fun replaceList(newList: List<Model>) {
currentList = newList
notifyDataSetChanged()
}
}

View File

@ -0,0 +1,105 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.adapters
import org.yuzu.yuzu_emu.model.SelectableItem
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
/**
* Generic list class meant to take care of single selection UI updates
* @param currentList The list to show initially
* @param defaultSelection The default selection to use if no list items are selected by
* [SelectableItem.selected] or if the currently selected item is removed from the list
*/
abstract class AbstractSingleSelectionList<
Model : SelectableItem,
Holder : AbstractViewHolder<Model>
>(
final override var currentList: List<Model>,
private val defaultSelection: DefaultSelection = DefaultSelection.Start
) : AbstractListAdapter<Model, Holder>(currentList) {
var selectedItem = getDefaultSelection()
init {
findSelectedItem()
}
/**
* Changes the selection state of the [SelectableItem] that was selected and the previously selected
* item and notifies the underlying adapter of the change for those items. Invokes [callback] last.
* Does nothing if [position] is the same as the currently selected item.
* @param position Index of the item that was selected
* @param callback Lambda that's called at the end of the list changes and has the selected list
* position passed in as a parameter
*/
fun selectItem(position: Int, callback: ((position: Int) -> Unit)? = null) {
if (position == selectedItem) {
return
}
val previouslySelectedItem = selectedItem
selectedItem = position
if (currentList.indices.contains(selectedItem)) {
currentList[selectedItem].onSelectionStateChanged(true)
}
if (currentList.indices.contains(previouslySelectedItem)) {
currentList[previouslySelectedItem].onSelectionStateChanged(false)
}
onItemChanged(previouslySelectedItem)
onItemChanged(selectedItem)
callback?.invoke(position)
}
/**
* Removes a given item from the list and notifies the underlying adapter of the change. If the
* currently selected item was the item that was removed, the item at the position provided
* by [defaultSelection] will be made the new selection. Invokes [callback] last.
* @param position Index of the item that was removed
* @param callback Lambda that's called at the end of the list changes and has the removed and
* selected list positions passed in as parameters
*/
fun removeSelectableItem(
position: Int,
callback: ((removedPosition: Int, selectedPosition: Int) -> Unit)?
) {
removeItem(position)
if (position == selectedItem) {
selectedItem = getDefaultSelection()
currentList[selectedItem].onSelectionStateChanged(true)
onItemChanged(selectedItem)
} else if (position < selectedItem) {
selectedItem--
}
callback?.invoke(position, selectedItem)
}
override fun addItem(item: Model, position: Int, callback: ((Int) -> Unit)?) {
super.addItem(item, position, callback)
if (position <= selectedItem && position != -1) {
selectedItem++
}
}
override fun replaceList(newList: List<Model>) {
super.replaceList(newList)
findSelectedItem()
}
private fun findSelectedItem() {
for (i in currentList.indices) {
if (currentList[i].selected) {
selectedItem = i
break
}
}
}
private fun getDefaultSelection(): Int =
when (defaultSelection) {
DefaultSelection.Start -> currentList.indices.first
DefaultSelection.End -> currentList.indices.last
}
enum class DefaultSelection { Start, End }
}

View File

@ -5,48 +5,33 @@ package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding
import org.yuzu.yuzu_emu.model.Addon
import org.yuzu.yuzu_emu.model.Patch
import org.yuzu.yuzu_emu.model.AddonViewModel
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class AddonAdapter : ListAdapter<Addon, AddonAdapter.AddonViewHolder>(
AsyncDifferConfig.Builder(DiffCallback()).build()
) {
class AddonAdapter(val addonViewModel: AddonViewModel) :
AbstractDiffAdapter<Patch, AddonAdapter.AddonViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder {
ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return AddonViewHolder(it) }
}
override fun getItemCount(): Int = currentList.size
override fun onBindViewHolder(holder: AddonViewHolder, position: Int) =
holder.bind(currentList[position])
inner class AddonViewHolder(val binding: ListItemAddonBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(addon: Addon) {
AbstractViewHolder<Patch>(binding) {
override fun bind(model: Patch) {
binding.root.setOnClickListener {
binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked
binding.addonCheckbox.isChecked = !binding.addonCheckbox.isChecked
}
binding.title.text = addon.title
binding.version.text = addon.version
binding.addonSwitch.setOnCheckedChangeListener { _, checked ->
addon.enabled = checked
binding.title.text = model.name
binding.version.text = model.version
binding.addonCheckbox.setOnCheckedChangeListener { _, checked ->
model.enabled = checked
}
binding.addonCheckbox.isChecked = model.enabled
binding.buttonDelete.setOnClickListener {
addonViewModel.setAddonToDelete(model)
}
binding.addonSwitch.isChecked = addon.enabled
}
}
private class DiffCallback : DiffUtil.ItemCallback<Addon>() {
override fun areItemsTheSame(oldItem: Addon, newItem: Addon): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Addon, newItem: Addon): Boolean {
return oldItem == newItem
}
}
}

View File

@ -4,13 +4,11 @@
package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
@ -19,72 +17,58 @@ import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.Applet
import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) :
RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(),
View.OnClickListener {
class AppletAdapter(val activity: FragmentActivity, applets: List<Applet>) :
AbstractListAdapter<Applet, AppletAdapter.AppletViewHolder>(applets) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): AppletAdapter.AppletViewHolder {
CardSimpleOutlinedBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.apply { root.setOnClickListener(this@AppletAdapter) }
.also { return AppletViewHolder(it) }
}
override fun onBindViewHolder(holder: AppletViewHolder, position: Int) =
holder.bind(applets[position])
override fun getItemCount(): Int = applets.size
override fun onClick(view: View) {
val applet = (view.tag as AppletViewHolder).applet
val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId)
if (appletPath.isEmpty()) {
Toast.makeText(
YuzuApplication.appContext,
R.string.applets_error_applet,
Toast.LENGTH_SHORT
).show()
return
}
if (applet.appletInfo == AppletInfo.Cabinet) {
view.findNavController()
.navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment)
return
}
NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId)
val appletGame = Game(
title = YuzuApplication.appContext.getString(applet.titleId),
path = appletPath
)
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
view.findNavController().navigate(action)
}
inner class AppletViewHolder(val binding: CardSimpleOutlinedBinding) :
RecyclerView.ViewHolder(binding.root) {
lateinit var applet: Applet
init {
itemView.tag = this
}
fun bind(applet: Applet) {
this.applet = applet
binding.title.setText(applet.titleId)
binding.description.setText(applet.descriptionId)
AbstractViewHolder<Applet>(binding) {
override fun bind(model: Applet) {
binding.title.setText(model.titleId)
binding.description.setText(model.descriptionId)
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.context.resources,
applet.iconId,
model.iconId,
binding.icon.context.theme
)
)
binding.root.setOnClickListener { onClick(model) }
}
fun onClick(applet: Applet) {
val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId)
if (appletPath.isEmpty()) {
Toast.makeText(
binding.root.context,
R.string.applets_error_applet,
Toast.LENGTH_SHORT
).show()
return
}
if (applet.appletInfo == AppletInfo.Cabinet) {
binding.root.findNavController()
.navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment)
return
}
NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId)
val appletGame = Game(
title = YuzuApplication.appContext.getString(applet.titleId),
path = appletPath
)
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
binding.root.findNavController().navigate(action)
}
}
}

View File

@ -4,12 +4,10 @@
package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
@ -19,54 +17,43 @@ import org.yuzu.yuzu_emu.model.CabinetMode
import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder
import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class CabinetLauncherDialogAdapter(val fragment: Fragment) :
RecyclerView.Adapter<CabinetModeViewHolder>(),
View.OnClickListener {
private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size)
AbstractListAdapter<CabinetMode, CabinetModeViewHolder>(
CabinetMode.values().copyOfRange(1, CabinetMode.entries.size).toList()
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder {
DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.apply { root.setOnClickListener(this@CabinetLauncherDialogAdapter) }
.also { return CabinetModeViewHolder(it) }
}
override fun getItemCount(): Int = cabinetModes.size
override fun onBindViewHolder(holder: CabinetModeViewHolder, position: Int) =
holder.bind(cabinetModes[position])
override fun onClick(view: View) {
val mode = (view.tag as CabinetModeViewHolder).cabinetMode
val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId)
NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId)
NativeLibrary.setCabinetMode(mode.id)
val appletGame = Game(
title = YuzuApplication.appContext.getString(R.string.cabinet_applet),
path = appletPath
)
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
fragment.findNavController().navigate(action)
}
inner class CabinetModeViewHolder(val binding: DialogListItemBinding) :
RecyclerView.ViewHolder(binding.root) {
lateinit var cabinetMode: CabinetMode
init {
itemView.tag = this
}
fun bind(cabinetMode: CabinetMode) {
this.cabinetMode = cabinetMode
AbstractViewHolder<CabinetMode>(binding) {
override fun bind(model: CabinetMode) {
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.context.resources,
cabinetMode.iconId,
model.iconId,
binding.icon.context.theme
)
)
binding.title.setText(cabinetMode.titleId)
binding.title.setText(model.titleId)
binding.root.setOnClickListener { onClick(model) }
}
private fun onClick(mode: CabinetMode) {
val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId)
NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId)
NativeLibrary.setCabinetMode(mode.id)
val appletGame = Game(
title = YuzuApplication.appContext.getString(R.string.cabinet_applet),
path = appletPath
)
val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
fragment.findNavController().navigate(action)
}
}
}

View File

@ -7,65 +7,39 @@ import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.model.Driver
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class DriverAdapter(private val driverViewModel: DriverViewModel) :
ListAdapter<Pair<String, GpuDriverMetadata>, DriverAdapter.DriverViewHolder>(
AsyncDifferConfig.Builder(DiffCallback()).build()
AbstractSingleSelectionList<Driver, DriverAdapter.DriverViewHolder>(
driverViewModel.driverList.value
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder {
val binding =
CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return DriverViewHolder(binding)
}
override fun getItemCount(): Int = currentList.size
override fun onBindViewHolder(holder: DriverViewHolder, position: Int) =
holder.bind(currentList[position])
private fun onSelectDriver(position: Int) {
driverViewModel.setSelectedDriverIndex(position)
notifyItemChanged(driverViewModel.previouslySelectedDriver)
notifyItemChanged(driverViewModel.selectedDriver)
}
private fun onDeleteDriver(driverData: Pair<String, GpuDriverMetadata>, position: Int) {
if (driverViewModel.selectedDriver > position) {
driverViewModel.setSelectedDriverIndex(driverViewModel.selectedDriver - 1)
}
if (GpuDriverHelper.customDriverSettingData == driverData.second) {
driverViewModel.setSelectedDriverIndex(0)
}
driverViewModel.driversToDelete.add(driverData.first)
driverViewModel.removeDriver(driverData)
notifyItemRemoved(position)
notifyItemChanged(driverViewModel.selectedDriver)
CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return DriverViewHolder(it) }
}
inner class DriverViewHolder(val binding: CardDriverOptionBinding) :
RecyclerView.ViewHolder(binding.root) {
private lateinit var driverData: Pair<String, GpuDriverMetadata>
fun bind(driverData: Pair<String, GpuDriverMetadata>) {
this.driverData = driverData
val driver = driverData.second
AbstractViewHolder<Driver>(binding) {
override fun bind(model: Driver) {
binding.apply {
radioButton.isChecked = driverViewModel.selectedDriver == bindingAdapterPosition
radioButton.isChecked = model.selected
root.setOnClickListener {
onSelectDriver(bindingAdapterPosition)
selectItem(bindingAdapterPosition) {
driverViewModel.onDriverSelected(it)
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
}
}
buttonDelete.setOnClickListener {
onDeleteDriver(driverData, bindingAdapterPosition)
removeSelectableItem(
bindingAdapterPosition
) { removedPosition: Int, selectedPosition: Int ->
driverViewModel.onDriverRemoved(removedPosition, selectedPosition)
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
}
}
// Delay marquee by 3s
@ -80,38 +54,19 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
},
3000
)
if (driver.name == null) {
title.setText(R.string.system_gpu_driver)
description.text = ""
version.text = ""
version.visibility = View.GONE
description.visibility = View.GONE
buttonDelete.visibility = View.GONE
} else {
title.text = driver.name
version.text = driver.version
description.text = driver.description
title.text = model.title
version.text = model.version
description.text = model.description
if (model.description.isNotEmpty()) {
version.visibility = View.VISIBLE
description.visibility = View.VISIBLE
buttonDelete.visibility = View.VISIBLE
} else {
version.visibility = View.GONE
description.visibility = View.GONE
buttonDelete.visibility = View.GONE
}
}
}
}
private class DiffCallback : DiffUtil.ItemCallback<Pair<String, GpuDriverMetadata>>() {
override fun areItemsTheSame(
oldItem: Pair<String, GpuDriverMetadata>,
newItem: Pair<String, GpuDriverMetadata>
): Boolean {
return oldItem.first == newItem.first
}
override fun areContentsTheSame(
oldItem: Pair<String, GpuDriverMetadata>,
newItem: Pair<String, GpuDriverMetadata>
): Boolean {
return oldItem.second == newItem.second
}
}
}

View File

@ -8,19 +8,14 @@ import android.text.TextUtils
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.databinding.CardFolderBinding
import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment
import org.yuzu.yuzu_emu.model.GameDir
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) :
ListAdapter<GameDir, FolderAdapter.FolderViewHolder>(
AsyncDifferConfig.Builder(DiffCallback()).build()
) {
AbstractDiffAdapter<GameDir, FolderAdapter.FolderViewHolder>() {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
@ -29,18 +24,11 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
.also { return FolderViewHolder(it) }
}
override fun onBindViewHolder(holder: FolderAdapter.FolderViewHolder, position: Int) =
holder.bind(currentList[position])
inner class FolderViewHolder(val binding: CardFolderBinding) :
RecyclerView.ViewHolder(binding.root) {
private lateinit var gameDir: GameDir
fun bind(gameDir: GameDir) {
this.gameDir = gameDir
AbstractViewHolder<GameDir>(binding) {
override fun bind(model: GameDir) {
binding.apply {
path.text = Uri.parse(gameDir.uriString).path
path.text = Uri.parse(model.uriString).path
path.postDelayed(
{
path.isSelected = true
@ -50,7 +38,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
)
buttonEdit.setOnClickListener {
GameFolderPropertiesDialogFragment.newInstance(this@FolderViewHolder.gameDir)
GameFolderPropertiesDialogFragment.newInstance(model)
.show(
activity.supportFragmentManager,
GameFolderPropertiesDialogFragment.TAG
@ -58,19 +46,9 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
}
buttonDelete.setOnClickListener {
gamesViewModel.removeFolder(this@FolderViewHolder.gameDir)
gamesViewModel.removeFolder(model)
}
}
}
}
private class DiffCallback : DiffUtil.ItemCallback<GameDir>() {
override fun areItemsTheSame(oldItem: GameDir, newItem: GameDir): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: GameDir, newItem: GameDir): Boolean {
return oldItem == newItem
}
}
}

View File

@ -3,155 +3,46 @@
package org.yuzu.yuzu_emu.adapters
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.LayerDrawable
import android.net.Uri
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.IconCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder
import org.yuzu.yuzu_emu.databinding.CardGameBinding
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class GameAdapter(private val activity: AppCompatActivity) :
ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()),
View.OnClickListener,
View.OnLongClickListener {
AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
// Create a new view.
val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
binding.cardGame.setOnClickListener(this)
binding.cardGame.setOnLongClickListener(this)
// Use that view to create a ViewHolder.
return GameViewHolder(binding)
}
override fun onBindViewHolder(holder: GameViewHolder, position: Int) =
holder.bind(currentList[position])
override fun getItemCount(): Int = currentList.size
/**
* Launches the game that was clicked on.
*
* @param view The card representing the game the user wants to play.
*/
override fun onClick(view: View) {
val holder = view.tag as GameViewHolder
val gameExists = DocumentFile.fromSingleUri(
YuzuApplication.appContext,
Uri.parse(holder.game.path)
)?.exists() == true
if (!gameExists) {
Toast.makeText(
YuzuApplication.appContext,
R.string.loader_error_file_not_found,
Toast.LENGTH_LONG
).show()
ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true)
return
}
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
preferences.edit()
.putLong(
holder.game.keyLastPlayedTime,
System.currentTimeMillis()
)
.apply()
val openIntent = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
action = Intent.ACTION_VIEW
data = Uri.parse(holder.game.path)
}
activity.lifecycleScope.launch {
withContext(Dispatchers.IO) {
val layerDrawable = ResourcesCompat.getDrawable(
YuzuApplication.appContext.resources,
R.drawable.shortcut,
null
) as LayerDrawable
layerDrawable.setDrawableByLayerId(
R.id.shortcut_foreground,
GameIconUtils.getGameIcon(activity, holder.game)
.toDrawable(YuzuApplication.appContext.resources)
)
val inset = YuzuApplication.appContext.resources
.getDimensionPixelSize(R.dimen.icon_inset)
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
val shortcut =
ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
.setShortLabel(holder.game.title)
.setIcon(
IconCompat.createWithAdaptiveBitmap(
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
)
)
.setIntent(openIntent)
.build()
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
}
}
val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game, true)
view.findNavController().navigate(action)
}
override fun onLongClick(view: View): Boolean {
val holder = view.tag as GameViewHolder
val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(holder.game)
view.findNavController().navigate(action)
return true
CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return GameViewHolder(it) }
}
inner class GameViewHolder(val binding: CardGameBinding) :
RecyclerView.ViewHolder(binding.root) {
lateinit var game: Game
init {
binding.cardGame.tag = this
}
fun bind(game: Game) {
this.game = game
AbstractViewHolder<Game>(binding) {
override fun bind(model: Game) {
binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
GameIconUtils.loadGameIcon(game, binding.imageGameScreen)
GameIconUtils.loadGameIcon(model, binding.imageGameScreen)
binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ")
binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ")
binding.textGameTitle.postDelayed(
{
@ -160,16 +51,56 @@ class GameAdapter(private val activity: AppCompatActivity) :
},
3000
)
}
}
private class DiffCallback : DiffUtil.ItemCallback<Game>() {
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
return oldItem == newItem
binding.cardGame.setOnClickListener { onClick(model) }
binding.cardGame.setOnLongClickListener { onLongClick(model) }
}
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
return oldItem == newItem
fun onClick(game: Game) {
val gameExists = DocumentFile.fromSingleUri(
YuzuApplication.appContext,
Uri.parse(game.path)
)?.exists() == true
if (!gameExists) {
Toast.makeText(
YuzuApplication.appContext,
R.string.loader_error_file_not_found,
Toast.LENGTH_LONG
).show()
ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true)
return
}
val preferences =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
preferences.edit()
.putLong(
game.keyLastPlayedTime,
System.currentTimeMillis()
)
.apply()
activity.lifecycleScope.launch {
withContext(Dispatchers.IO) {
val shortcut =
ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path)
.setShortLabel(game.title)
.setIcon(GameIconUtils.getShortcutIcon(activity, game))
.setIntent(game.launchIntent)
.build()
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
}
}
val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true)
binding.root.findNavController().navigate(action)
}
fun onLongClick(game: Game): Boolean {
val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game)
binding.root.findNavController().navigate(action)
return true
}
}
}

View File

@ -12,23 +12,22 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.GameProperty
import org.yuzu.yuzu_emu.model.InstallableProperty
import org.yuzu.yuzu_emu.model.SubmenuProperty
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class GamePropertiesAdapter(
private val viewLifecycle: LifecycleOwner,
private var properties: List<GameProperty>
) :
RecyclerView.Adapter<GamePropertiesAdapter.GamePropertyViewHolder>() {
) : AbstractListAdapter<GameProperty, AbstractViewHolder<GameProperty>>(properties) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): GamePropertyViewHolder {
): AbstractViewHolder<GameProperty> {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
PropertyType.Submenu.ordinal -> {
@ -51,11 +50,6 @@ class GamePropertiesAdapter(
}
}
override fun getItemCount(): Int = properties.size
override fun onBindViewHolder(holder: GamePropertyViewHolder, position: Int) =
holder.bind(properties[position])
override fun getItemViewType(position: Int): Int {
return when (properties[position]) {
is SubmenuProperty -> PropertyType.Submenu.ordinal
@ -63,14 +57,10 @@ class GamePropertiesAdapter(
}
}
sealed class GamePropertyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(property: GameProperty)
}
inner class SubmenuPropertyViewHolder(val binding: CardSimpleOutlinedBinding) :
GamePropertyViewHolder(binding.root) {
override fun bind(property: GameProperty) {
val submenuProperty = property as SubmenuProperty
AbstractViewHolder<GameProperty>(binding) {
override fun bind(model: GameProperty) {
val submenuProperty = model as SubmenuProperty
binding.root.setOnClickListener {
submenuProperty.action.invoke()
@ -108,9 +98,9 @@ class GamePropertiesAdapter(
}
inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) :
GamePropertyViewHolder(binding.root) {
override fun bind(property: GameProperty) {
val installableProperty = property as InstallableProperty
AbstractViewHolder<GameProperty>(binding) {
override fun bind(model: GameProperty) {
val installableProperty = model as InstallableProperty
binding.title.setText(installableProperty.titleId)
binding.description.setText(installableProperty.descriptionId)

View File

@ -14,69 +14,37 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class HomeSettingAdapter(
private val activity: AppCompatActivity,
private val viewLifecycle: LifecycleOwner,
var options: List<HomeSetting>
) :
RecyclerView.Adapter<HomeSettingAdapter.HomeOptionViewHolder>(),
View.OnClickListener {
options: List<HomeSetting>
) : AbstractListAdapter<HomeSetting, HomeSettingAdapter.HomeOptionViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder {
val binding =
CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
binding.root.setOnClickListener(this)
return HomeOptionViewHolder(binding)
}
override fun getItemCount(): Int {
return options.size
}
override fun onBindViewHolder(holder: HomeOptionViewHolder, position: Int) {
holder.bind(options[position])
}
override fun onClick(view: View) {
val holder = view.tag as HomeOptionViewHolder
if (holder.option.isEnabled.invoke()) {
holder.option.onClick.invoke()
} else {
MessageDialogFragment.newInstance(
activity,
titleId = holder.option.disabledTitleId,
descriptionId = holder.option.disabledMessageId
).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
}
CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return HomeOptionViewHolder(it) }
}
inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) :
RecyclerView.ViewHolder(binding.root) {
lateinit var option: HomeSetting
init {
itemView.tag = this
}
fun bind(option: HomeSetting) {
this.option = option
binding.optionTitle.text = activity.resources.getString(option.titleId)
binding.optionDescription.text = activity.resources.getString(option.descriptionId)
AbstractViewHolder<HomeSetting>(binding) {
override fun bind(model: HomeSetting) {
binding.optionTitle.text = activity.resources.getString(model.titleId)
binding.optionDescription.text = activity.resources.getString(model.descriptionId)
binding.optionIcon.setImageDrawable(
ResourcesCompat.getDrawable(
activity.resources,
option.iconId,
model.iconId,
activity.theme
)
)
when (option.titleId) {
when (model.titleId) {
R.string.get_early_access ->
binding.optionLayout.background =
ContextCompat.getDrawable(
@ -85,7 +53,7 @@ class HomeSettingAdapter(
)
}
if (!option.isEnabled.invoke()) {
if (!model.isEnabled.invoke()) {
binding.optionTitle.alpha = 0.5f
binding.optionDescription.alpha = 0.5f
binding.optionIcon.alpha = 0.5f
@ -93,7 +61,7 @@ class HomeSettingAdapter(
viewLifecycle.lifecycleScope.launch {
viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
option.details.collect { updateOptionDetails(it) }
model.details.collect { updateOptionDetails(it) }
}
}
binding.optionDetail.postDelayed(
@ -103,6 +71,20 @@ class HomeSettingAdapter(
},
3000
)
binding.root.setOnClickListener { onClick(model) }
}
private fun onClick(model: HomeSetting) {
if (model.isEnabled.invoke()) {
model.onClick.invoke()
} else {
MessageDialogFragment.newInstance(
activity,
titleId = model.disabledTitleId,
descriptionId = model.disabledMessageId
).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
}
}
private fun updateOptionDetails(detailString: String) {

View File

@ -6,43 +6,33 @@ package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
import org.yuzu.yuzu_emu.model.Installable
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class InstallableAdapter(private val installables: List<Installable>) :
RecyclerView.Adapter<InstallableAdapter.InstallableViewHolder>() {
class InstallableAdapter(installables: List<Installable>) :
AbstractListAdapter<Installable, InstallableAdapter.InstallableViewHolder>(installables) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): InstallableAdapter.InstallableViewHolder {
val binding =
CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return InstallableViewHolder(binding)
CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return InstallableViewHolder(it) }
}
override fun getItemCount(): Int = installables.size
override fun onBindViewHolder(holder: InstallableAdapter.InstallableViewHolder, position: Int) =
holder.bind(installables[position])
inner class InstallableViewHolder(val binding: CardInstallableBinding) :
RecyclerView.ViewHolder(binding.root) {
lateinit var installable: Installable
AbstractViewHolder<Installable>(binding) {
override fun bind(model: Installable) {
binding.title.setText(model.titleId)
binding.description.setText(model.descriptionId)
fun bind(installable: Installable) {
this.installable = installable
binding.title.setText(installable.titleId)
binding.description.setText(installable.descriptionId)
if (installable.install != null) {
if (model.install != null) {
binding.buttonInstall.visibility = View.VISIBLE
binding.buttonInstall.setOnClickListener { installable.install.invoke() }
binding.buttonInstall.setOnClickListener { model.install.invoke() }
}
if (installable.export != null) {
if (model.export != null) {
binding.buttonExport.visibility = View.VISIBLE
binding.buttonExport.setOnClickListener { installable.export.invoke() }
binding.buttonExport.setOnClickListener { model.export.invoke() }
}
}
}

View File

@ -7,49 +7,33 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
import org.yuzu.yuzu_emu.model.License
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) :
RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(),
View.OnClickListener {
class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) :
AbstractListAdapter<License, LicenseAdapter.LicenseViewHolder>(licenses) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder {
val binding =
ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
binding.root.setOnClickListener(this)
return LicenseViewHolder(binding)
ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return LicenseViewHolder(it) }
}
override fun getItemCount(): Int = licenses.size
inner class LicenseViewHolder(val binding: ListItemSettingBinding) :
AbstractViewHolder<License>(binding) {
override fun bind(model: License) {
binding.apply {
textSettingName.text = root.context.getString(model.titleId)
textSettingDescription.text = root.context.getString(model.descriptionId)
textSettingValue.visibility = View.GONE
override fun onBindViewHolder(holder: LicenseViewHolder, position: Int) {
holder.bind(licenses[position])
}
override fun onClick(view: View) {
val license = (view.tag as LicenseViewHolder).license
LicenseBottomSheetDialogFragment.newInstance(license)
.show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG)
}
inner class LicenseViewHolder(val binding: ListItemSettingBinding) : ViewHolder(binding.root) {
lateinit var license: License
init {
itemView.tag = this
root.setOnClickListener { onClick(model) }
}
}
fun bind(license: License) {
this.license = license
val context = YuzuApplication.appContext
binding.textSettingName.text = context.getString(license.titleId)
binding.textSettingDescription.text = context.getString(license.descriptionId)
binding.textSettingValue.visibility = View.GONE
private fun onClick(license: License) {
LicenseBottomSheetDialogFragment.newInstance(license)
.show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG)
}
}
}

View File

@ -10,7 +10,6 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.button.MaterialButton
import org.yuzu.yuzu_emu.databinding.PageSetupBinding
import org.yuzu.yuzu_emu.model.HomeViewModel
@ -18,31 +17,19 @@ import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage
import org.yuzu.yuzu_emu.model.StepState
import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) :
RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() {
class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
AbstractListAdapter<SetupPage, SetupAdapter.SetupPageViewHolder>(pages) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder {
val binding = PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return SetupPageViewHolder(binding)
PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return SetupPageViewHolder(it) }
}
override fun getItemCount(): Int = pages.size
override fun onBindViewHolder(holder: SetupPageViewHolder, position: Int) =
holder.bind(pages[position])
inner class SetupPageViewHolder(val binding: PageSetupBinding) :
RecyclerView.ViewHolder(binding.root), SetupCallback {
lateinit var page: SetupPage
init {
itemView.tag = this
}
fun bind(page: SetupPage) {
this.page = page
if (page.stepCompleted.invoke() == StepState.COMPLETE) {
AbstractViewHolder<SetupPage>(binding), SetupCallback {
override fun bind(model: SetupPage) {
if (model.stepCompleted.invoke() == StepState.COMPLETE) {
binding.buttonAction.visibility = View.INVISIBLE
binding.textConfirmation.visibility = View.VISIBLE
}
@ -50,31 +37,31 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
activity.resources,
page.iconId,
model.iconId,
activity.theme
)
)
binding.textTitle.text = activity.resources.getString(page.titleId)
binding.textTitle.text = activity.resources.getString(model.titleId)
binding.textDescription.text =
Html.fromHtml(activity.resources.getString(page.descriptionId), 0)
Html.fromHtml(activity.resources.getString(model.descriptionId), 0)
binding.buttonAction.apply {
text = activity.resources.getString(page.buttonTextId)
if (page.buttonIconId != 0) {
text = activity.resources.getString(model.buttonTextId)
if (model.buttonIconId != 0) {
icon = ResourcesCompat.getDrawable(
activity.resources,
page.buttonIconId,
model.buttonIconId,
activity.theme
)
}
iconGravity =
if (page.leftAlignedIcon) {
if (model.leftAlignedIcon) {
MaterialButton.ICON_GRAVITY_START
} else {
MaterialButton.ICON_GRAVITY_END
}
setOnClickListener {
page.buttonAction.invoke(this@SetupPageViewHolder)
model.buttonAction.invoke(this@SetupPageViewHolder)
}
}
}

View File

@ -23,7 +23,8 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
THEME("theme"),
THEME_MODE("theme_mode"),
OVERLAY_SCALE("control_scale"),
OVERLAY_OPACITY("control_opacity");
OVERLAY_OPACITY("control_opacity"),
LOCK_DRAWER("lock_drawer");
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)

View File

@ -79,7 +79,18 @@ object Settings {
const val PREF_THEME_MODE = "ThemeMode"
const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds"
const val LayoutOption_Unspecified = 0
const val LayoutOption_MobilePortrait = 4
const val LayoutOption_MobileLandscape = 5
enum class EmulationOrientation(val int: Int) {
Unspecified(0),
SensorLandscape(5),
Landscape(1),
ReverseLandscape(2),
SensorPortrait(6),
Portrait(4),
ReversePortrait(3);
companion object {
fun from(int: Int): EmulationOrientation =
entries.firstOrNull { it.int == int } ?: Unspecified
}
}
}

View File

@ -76,8 +76,8 @@ class AboutFragment : Fragment() {
binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment)
}
binding.textBuildHash.text = BuildConfig.GIT_HASH
binding.buttonBuildHash.setOnClickListener {
binding.textVersionName.text = BuildConfig.VERSION_NAME
binding.textVersionName.setOnClickListener {
val clipBoard =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH)

View File

@ -74,7 +74,7 @@ class AddonsFragment : Fragment() {
binding.listAddons.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = AddonAdapter()
adapter = AddonAdapter(addonViewModel)
}
viewLifecycleOwner.lifecycleScope.apply {
@ -110,6 +110,21 @@ class AddonsFragment : Fragment() {
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.addonToDelete.collect {
if (it != null) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.confirm_uninstall,
descriptionId = R.string.confirm_uninstall_description,
positiveAction = { addonViewModel.onDeleteAddon(it) }
).show(parentFragmentManager, MessageDialogFragment.TAG)
addonViewModel.setAddonToDelete(null)
}
}
}
}
}
binding.buttonInstall.setOnClickListener {
@ -156,22 +171,22 @@ class AddonsFragment : Fragment() {
descriptionId = R.string.invalid_directory_description
)
if (isValid) {
IndeterminateProgressDialogFragment.newInstance(
ProgressDialogFragment.newInstance(
requireActivity(),
R.string.installing_game_content,
false
) {
) { progressCallback, _ ->
val parentDirectoryName = externalAddonDirectory.name
val internalAddonDirectory =
File(args.game.addonDir + parentDirectoryName)
try {
externalAddonDirectory.copyFilesTo(internalAddonDirectory)
externalAddonDirectory.copyFilesTo(internalAddonDirectory, progressCallback)
} catch (_: Exception) {
return@newInstance errorMessage
}
addonViewModel.refreshAddons()
return@newInstance getString(R.string.addon_installed_successfully)
}.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
} else {
errorMessage.show(parentFragmentManager, MessageDialogFragment.TAG)
}

View File

@ -3,6 +3,7 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -13,20 +14,26 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.DriverAdapter
import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
import org.yuzu.yuzu_emu.model.DriverViewModel
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 java.io.File
import java.io.IOException
@ -55,12 +62,43 @@ class DriverManagerFragment : Fragment() {
return binding.root
}
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true)
homeViewModel.setStatusBarShadeVisibility(visible = false)
driverViewModel.onOpenDriverManager(args.game)
if (NativeConfig.isPerGameConfigLoaded()) {
binding.toolbarDrivers.inflateMenu(R.menu.menu_driver_manager)
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
binding.toolbarDrivers.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_driver_use_global -> {
StringSetting.DRIVER_PATH.global = true
driverViewModel.updateDriverList()
(binding.listDrivers.adapter as DriverAdapter)
.replaceList(driverViewModel.driverList.value)
driverViewModel.showClearButton(false)
true
}
else -> false
}
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
driverViewModel.showClearButton.collect {
binding.toolbarDrivers.menu
.findItem(R.id.menu_driver_use_global).isVisible = it
}
}
}
}
}
if (!driverViewModel.isInteractionAllowed.value) {
DriversLoadingDialogFragment().show(
@ -85,25 +123,6 @@ class DriverManagerFragment : Fragment() {
adapter = DriverAdapter(driverViewModel)
}
viewLifecycleOwner.lifecycleScope.apply {
launch {
driverViewModel.driverList.collectLatest {
(binding.listDrivers.adapter as DriverAdapter).submitList(it)
}
}
launch {
driverViewModel.newDriverInstalled.collect {
if (_binding != null && it) {
(binding.listDrivers.adapter as DriverAdapter).apply {
notifyItemChanged(driverViewModel.previouslySelectedDriver)
notifyItemChanged(driverViewModel.selectedDriver)
driverViewModel.setNewDriverInstalled(false)
}
}
}
}
}
setInsets()
}
@ -154,13 +173,13 @@ class DriverManagerFragment : Fragment() {
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
ProgressDialogFragment.newInstance(
requireActivity(),
R.string.installing_driver,
false
) {
) { _, _ ->
val driverPath =
"${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}"
"${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(result)}"
val driverFile = File(driverPath)
// Ignore file exceptions when a user selects an invalid zip
@ -177,14 +196,23 @@ class DriverManagerFragment : Fragment() {
val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
val driverInList =
driverViewModel.driverList.value.firstOrNull { it.second == driverData }
driverViewModel.driverData.firstOrNull { it.second == driverData }
if (driverInList != null) {
return@newInstance getString(R.string.driver_already_installed)
} else {
driverViewModel.addDriver(Pair(driverPath, driverData))
driverViewModel.setNewDriverInstalled(true)
driverViewModel.onDriverAdded(Pair(driverPath, driverData))
withContext(Dispatchers.Main) {
if (_binding != null) {
val adapter = binding.listDrivers.adapter as DriverAdapter
adapter.addItem(driverData.toDriver())
adapter.selectItem(adapter.currentList.indices.last)
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
binding.listDrivers
.smoothScrollToPosition(adapter.currentList.indices.last)
}
}
}
return@newInstance Any()
}.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(childFragmentManager, ProgressDialogFragment.TAG)
}
}

View File

@ -50,6 +50,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationOrientation
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.Game
@ -99,6 +100,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
updateOrientation()
val intentUri: Uri? = requireActivity().intent.data
var intentGame: Game? = null
@ -180,11 +182,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
override fun onDrawerOpened(drawerView: View) {
// No op
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
}
override fun onDrawerClosed(drawerView: View) {
// No op
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
}
override fun onDrawerStateChanged(newState: Int) {
@ -194,6 +196,28 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
game.title
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) {
R.string.unlock_drawer
} else {
R.string.lock_drawer
}
val iconId = if (lockMode == DrawerLayout.LOCK_MODE_UNLOCKED) {
R.drawable.ic_unlock
} else {
R.drawable.ic_lock
}
title = getString(titleId)
icon = ResourcesCompat.getDrawable(
resources,
iconId,
requireContext().theme
)
}
binding.inGameMenu.setNavigationItemSelectedListener {
when (it.itemId) {
R.id.menu_pause_emulation -> {
@ -240,6 +264,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
true
}
R.id.menu_lock_drawer -> {
when (IntSetting.LOCK_DRAWER.getInt()) {
DrawerLayout.LOCK_MODE_UNLOCKED -> {
IntSetting.LOCK_DRAWER.setInt(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
it.title = resources.getString(R.string.unlock_drawer)
it.icon = ResourcesCompat.getDrawable(
resources,
R.drawable.ic_lock,
requireContext().theme
)
}
DrawerLayout.LOCK_MODE_LOCKED_CLOSED -> {
IntSetting.LOCK_DRAWER.setInt(DrawerLayout.LOCK_MODE_UNLOCKED)
it.title = resources.getString(R.string.lock_drawer)
it.icon = ResourcesCompat.getDrawable(
resources,
R.drawable.ic_unlock,
requireContext().theme
)
}
}
NativeConfig.saveGlobalConfig()
true
}
R.id.menu_exit -> {
emulationState.stop()
emulationViewModel.setIsEmulationStopping(true)
@ -324,7 +374,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.emulationStarted.collectLatest {
if (it) {
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
ViewUtils.showView(binding.surfaceInputOverlay)
ViewUtils.hideView(binding.loadingIndicator)
@ -458,13 +508,23 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@SuppressLint("SourceLockedOrientationActivity")
private fun updateOrientation() {
emulationActivity?.let {
it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.getInt()) {
Settings.LayoutOption_MobileLandscape ->
val orientationSetting =
EmulationOrientation.from(IntSetting.RENDERER_SCREEN_LAYOUT.getInt())
it.requestedOrientation = when (orientationSetting) {
EmulationOrientation.Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
EmulationOrientation.SensorLandscape ->
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
Settings.LayoutOption_MobilePortrait ->
ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
Settings.LayoutOption_Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
else -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
EmulationOrientation.Landscape -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
EmulationOrientation.ReverseLandscape ->
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
EmulationOrientation.SensorPortrait ->
ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
EmulationOrientation.Portrait -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
EmulationOrientation.ReversePortrait ->
ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
}
}
}
@ -542,6 +602,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean()
}
popup.setOnDismissListener { NativeConfig.saveGlobalConfig() }
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_toggle_fps -> {
@ -651,7 +712,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@SuppressLint("SourceLockedOrientationActivity")
private fun startConfiguringControls() {
// Lock the current orientation to prevent editing inconsistencies
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) {
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) {
emulationActivity?.let {
it.requestedOrientation =
if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
@ -669,7 +730,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.doneControlConfig.visibility = View.GONE
binding.surfaceInputOverlay.setIsInEditMode(false)
// Unlock the orientation if it was locked for editing
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == Settings.LayoutOption_Unspecified) {
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) {
emulationActivity?.let {
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
}
@ -708,7 +769,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.emulation_control_adjust)
.setView(adjustBinding.root)
.setPositiveButton(android.R.string.ok, null)
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
NativeConfig.saveGlobalConfig()
}
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
setControlScale(50)
setControlOpacity(100)

View File

@ -21,8 +21,10 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import com.google.android.material.transition.MaterialSharedAxis
import org.yuzu.yuzu_emu.NativeLibrary
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.GameMetadata
@ -101,6 +103,38 @@ class GameInfoFragment : Fragment() {
""".trimIndent()
copyToClipboard(args.game.title, details)
}
buttonVerifyIntegrity.setOnClickListener {
ProgressDialogFragment.newInstance(
requireActivity(),
R.string.verifying,
true
) { progressCallback, _ ->
val result = GameVerificationResult.from(
NativeLibrary.verifyGameContents(
args.game.path,
progressCallback
)
)
return@newInstance when (result) {
GameVerificationResult.Success ->
MessageDialogFragment.newInstance(
titleId = R.string.verify_success,
descriptionId = R.string.operation_completed_successfully
)
GameVerificationResult.Failed ->
MessageDialogFragment.newInstance(
titleId = R.string.verify_failure,
descriptionId = R.string.verify_failure_description
)
GameVerificationResult.NotImplemented ->
MessageDialogFragment.newInstance(
titleId = R.string.verify_no_result,
descriptionId = R.string.verify_no_result_description
)
}
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
}
setInsets()

View File

@ -4,6 +4,8 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
@ -44,7 +46,6 @@ 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 java.io.BufferedInputStream
import java.io.BufferedOutputStream
import java.io.File
@ -85,6 +86,24 @@ class GamePropertiesFragment : Fragment() {
view.findNavController().popBackStack()
}
val shortcutManager = requireActivity().getSystemService(ShortcutManager::class.java)
binding.buttonShortcut.isEnabled = shortcutManager.isRequestPinShortcutSupported
binding.buttonShortcut.setOnClickListener {
viewLifecycleOwner.lifecycleScope.launch {
withContext(Dispatchers.IO) {
val shortcut = ShortcutInfo.Builder(requireContext(), args.game.title)
.setShortLabel(args.game.title)
.setIcon(
GameIconUtils.getShortcutIcon(requireActivity(), args.game)
.toIcon(requireContext())
)
.setIntent(args.game.launchIntent)
.build()
shortcutManager.requestPinShortcut(shortcut, null)
}
}
}
GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen)
binding.title.text = args.game.title
binding.title.postDelayed(
@ -357,27 +376,17 @@ class GamePropertiesFragment : Fragment() {
return@registerForActivityResult
}
val inputZip = requireContext().contentResolver.openInputStream(result)
val savesFolder = File(args.game.saveDir)
val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/")
cacheSaveDir.mkdir()
if (inputZip == null) {
Toast.makeText(
YuzuApplication.appContext,
getString(R.string.fatal_error),
Toast.LENGTH_LONG
).show()
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
ProgressDialogFragment.newInstance(
requireActivity(),
R.string.save_files_importing,
false
) {
) { _, _ ->
try {
FileUtil.unzipToInternalStorage(BufferedInputStream(inputZip), cacheSaveDir)
FileUtil.unzipToInternalStorage(result.toString(), cacheSaveDir)
val files = cacheSaveDir.listFiles()
var savesFolderFile: File? = null
if (files != null) {
@ -422,7 +431,7 @@ class GamePropertiesFragment : Fragment() {
Toast.LENGTH_LONG
).show()
}
}.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
/**
@ -436,21 +445,22 @@ class GamePropertiesFragment : Fragment() {
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
ProgressDialogFragment.newInstance(
requireActivity(),
R.string.save_files_exporting,
false
) {
) { _, _ ->
val saveLocation = args.game.saveDir
val zipResult = FileUtil.zipFromInternalStorage(
File(saveLocation),
saveLocation.replaceAfterLast("/", ""),
BufferedOutputStream(requireContext().contentResolver.openOutputStream(result))
BufferedOutputStream(requireContext().contentResolver.openOutputStream(result)),
compression = false
)
return@newInstance when (zipResult) {
TaskState.Completed -> getString(R.string.export_success)
TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
}
}.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
}

View File

@ -32,6 +32,7 @@ import org.yuzu.yuzu_emu.BuildConfig
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter
import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
import org.yuzu.yuzu_emu.features.DocumentProvider
@ -140,6 +141,38 @@ class HomeSettingsFragment : Fragment() {
}
)
)
add(
HomeSetting(
R.string.verify_installed_content,
R.string.verify_installed_content_description,
R.drawable.ic_check_circle,
{
ProgressDialogFragment.newInstance(
requireActivity(),
titleId = R.string.verifying,
cancellable = true
) { progressCallback, _ ->
val result = NativeLibrary.verifyInstalledContents(progressCallback)
return@newInstance if (result.isEmpty()) {
MessageDialogFragment.newInstance(
titleId = R.string.verify_success,
descriptionId = R.string.operation_completed_successfully
)
} else {
val failedNames = result.joinToString("\n")
val errorMessage = YuzuApplication.appContext.getString(
R.string.verification_failed_for,
failedNames
)
MessageDialogFragment.newInstance(
titleId = R.string.verify_failure,
descriptionString = errorMessage
)
}
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
)
)
add(
HomeSetting(
R.string.share_log,

View File

@ -7,20 +7,38 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.InstallableAdapter
import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.Installable
import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil
import java.io.BufferedOutputStream
import java.io.File
import java.math.BigInteger
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
class InstallableFragment : Fragment() {
private var _binding: FragmentInstallablesBinding? = null
@ -56,6 +74,17 @@ class InstallableFragment : Fragment() {
binding.root.findNavController().popBackStack()
}
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.openImportSaves.collect {
if (it) {
importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false)
}
}
}
}
val installables = listOf(
Installable(
R.string.user_data,
@ -63,6 +92,43 @@ class InstallableFragment : Fragment() {
install = { mainActivity.importUserData.launch(arrayOf("application/zip")) },
export = { mainActivity.exportUserData.launch("export.zip") }
),
Installable(
R.string.manage_save_data,
R.string.manage_save_data_description,
install = {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.import_save_warning,
descriptionId = R.string.import_save_warning_description,
positiveAction = { homeViewModel.setOpenImportSaves(true) }
).show(parentFragmentManager, MessageDialogFragment.TAG)
},
export = {
val oldSaveDataFolder = File(
"${DirectoryInitialization.userDirectory}/nand" +
NativeLibrary.getDefaultProfileSaveDataRoot(false)
)
val futureSaveDataFolder = File(
"${DirectoryInitialization.userDirectory}/nand" +
NativeLibrary.getDefaultProfileSaveDataRoot(true)
)
if (!oldSaveDataFolder.exists() && !futureSaveDataFolder.exists()) {
Toast.makeText(
YuzuApplication.appContext,
R.string.no_save_data_found,
Toast.LENGTH_SHORT
).show()
return@Installable
} else {
exportSaves.launch(
"${getString(R.string.save_data)} " +
LocalDateTime.now().format(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
)
)
}
}
),
Installable(
R.string.install_game_content,
R.string.install_game_content_description,
@ -121,4 +187,150 @@ class InstallableFragment : Fragment() {
windowInsets
}
private val importSaves =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result == null) {
return@registerForActivityResult
}
val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/")
cacheSaveDir.mkdir()
ProgressDialogFragment.newInstance(
requireActivity(),
R.string.save_files_importing,
false
) { progressCallback, _ ->
try {
FileUtil.unzipToInternalStorage(
result.toString(),
cacheSaveDir,
progressCallback
)
val files = cacheSaveDir.listFiles()
var successfulImports = 0
var failedImports = 0
if (files != null) {
for (file in files) {
if (file.isDirectory) {
val baseSaveDir =
NativeLibrary.getSavePath(BigInteger(file.name, 16).toString())
if (baseSaveDir.isEmpty()) {
failedImports++
continue
}
val internalSaveFolder = File(
"${DirectoryInitialization.userDirectory}/nand$baseSaveDir"
)
internalSaveFolder.deleteRecursively()
internalSaveFolder.mkdir()
file.copyRecursively(target = internalSaveFolder, overwrite = true)
successfulImports++
}
}
}
withContext(Dispatchers.Main) {
if (successfulImports == 0) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.save_file_invalid_zip_structure,
descriptionId = R.string.save_file_invalid_zip_structure_description
).show(parentFragmentManager, MessageDialogFragment.TAG)
return@withContext
}
val successString = if (failedImports > 0) {
"""
${
requireContext().resources.getQuantityString(
R.plurals.saves_import_success,
successfulImports,
successfulImports
)
}
${
requireContext().resources.getQuantityString(
R.plurals.saves_import_failed,
failedImports,
failedImports
)
}
"""
} else {
requireContext().resources.getQuantityString(
R.plurals.saves_import_success,
successfulImports,
successfulImports
)
}
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.import_complete,
descriptionString = successString
).show(parentFragmentManager, MessageDialogFragment.TAG)
}
cacheSaveDir.deleteRecursively()
} catch (e: Exception) {
Toast.makeText(
YuzuApplication.appContext,
getString(R.string.fatal_error),
Toast.LENGTH_LONG
).show()
}
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
private val exportSaves = registerForActivityResult(
ActivityResultContracts.CreateDocument("application/zip")
) { result ->
if (result == null) {
return@registerForActivityResult
}
ProgressDialogFragment.newInstance(
requireActivity(),
R.string.save_files_exporting,
false
) { _, _ ->
val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/")
cacheSaveDir.mkdir()
val oldSaveDataFolder = File(
"${DirectoryInitialization.userDirectory}/nand" +
NativeLibrary.getDefaultProfileSaveDataRoot(false)
)
if (oldSaveDataFolder.exists()) {
oldSaveDataFolder.copyRecursively(cacheSaveDir)
}
val futureSaveDataFolder = File(
"${DirectoryInitialization.userDirectory}/nand" +
NativeLibrary.getDefaultProfileSaveDataRoot(true)
)
if (futureSaveDataFolder.exists()) {
futureSaveDataFolder.copyRecursively(cacheSaveDir)
}
val saveFilesTotal = cacheSaveDir.listFiles()?.size ?: 0
if (saveFilesTotal == 0) {
cacheSaveDir.deleteRecursively()
return@newInstance getString(R.string.no_save_data_found)
}
val zipResult = FileUtil.zipFromInternalStorage(
cacheSaveDir,
cacheSaveDir.path,
BufferedOutputStream(requireContext().contentResolver.openOutputStream(result))
)
cacheSaveDir.deleteRecursively()
return@newInstance when (zipResult) {
TaskState.Completed -> getString(R.string.export_success)
TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
}
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
}

View File

@ -69,7 +69,7 @@ class MessageDialogFragment : DialogFragment() {
private const val HELP_LINK = "Link"
fun newInstance(
activity: FragmentActivity,
activity: FragmentActivity? = null,
titleId: Int = 0,
titleString: String = "",
descriptionId: Int = 0,
@ -86,9 +86,11 @@ class MessageDialogFragment : DialogFragment() {
putString(DESCRIPTION_STRING, descriptionString)
putInt(HELP_LINK, helpLinkId)
}
ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
clear()
this.positiveAction = positiveAction
if (activity != null) {
ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
clear()
this.positiveAction = positiveAction
}
}
dialog.arguments = bundle
return dialog

View File

@ -23,11 +23,13 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.TaskViewModel
class IndeterminateProgressDialogFragment : DialogFragment() {
class ProgressDialogFragment : DialogFragment() {
private val taskViewModel: TaskViewModel by activityViewModels()
private lateinit var binding: DialogProgressBarBinding
private val PROGRESS_BAR_RESOLUTION = 1000
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val titleId = requireArguments().getInt(TITLE)
val cancellable = requireArguments().getBoolean(CANCELLABLE)
@ -61,6 +63,7 @@ class IndeterminateProgressDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.message.isSelected = true
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
@ -97,6 +100,35 @@ class IndeterminateProgressDialogFragment : DialogFragment() {
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.progress.collect {
if (it != 0.0) {
binding.progressBar.apply {
isIndeterminate = false
progress = (
(it / taskViewModel.maxProgress.value) *
PROGRESS_BAR_RESOLUTION
).toInt()
min = 0
max = PROGRESS_BAR_RESOLUTION
}
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.message.collect {
if (it.isEmpty()) {
binding.message.visibility = View.GONE
} else {
binding.message.visibility = View.VISIBLE
binding.message.text = it
}
}
}
}
}
}
@ -108,6 +140,7 @@ class IndeterminateProgressDialogFragment : DialogFragment() {
val negativeButton = alertDialog.getButton(Dialog.BUTTON_NEGATIVE)
negativeButton.setOnClickListener {
alertDialog.setTitle(getString(R.string.cancelling))
binding.progressBar.isIndeterminate = true
taskViewModel.setCancelled(true)
}
}
@ -122,9 +155,12 @@ class IndeterminateProgressDialogFragment : DialogFragment() {
activity: FragmentActivity,
titleId: Int,
cancellable: Boolean = false,
task: suspend () -> Any
): IndeterminateProgressDialogFragment {
val dialog = IndeterminateProgressDialogFragment()
task: suspend (
progressCallback: (max: Long, progress: Long) -> Boolean,
messageCallback: (message: String) -> Unit
) -> Any
): ProgressDialogFragment {
val dialog = ProgressDialogFragment()
val args = Bundle()
ViewModelProvider(activity)[TaskViewModel::class.java].task = task
args.putInt(TITLE, titleId)

View File

@ -136,14 +136,14 @@ class SearchFragment : Fragment() {
baseList.filter {
val lastPlayedTime = preferences.getLong(it.keyLastPlayedTime, 0L)
lastPlayedTime > (System.currentTimeMillis() - 24 * 60 * 60 * 1000)
}
}.sortedByDescending { preferences.getLong(it.keyLastPlayedTime, 0L) }
}
R.id.chip_recently_added -> {
baseList.filter {
val addedTime = preferences.getLong(it.keyAddedToLibraryTime, 0L)
addedTime > (System.currentTimeMillis() - 24 * 60 * 60 * 1000)
}
}.sortedByDescending { preferences.getLong(it.keyAddedToLibraryTime, 0L) }
}
R.id.chip_homebrew -> baseList.filter { it.isHomebrew }

View File

@ -1,10 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
data class Addon(
var enabled: Boolean,
val title: String,
val version: String
)

View File

@ -15,8 +15,8 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
import java.util.concurrent.atomic.AtomicBoolean
class AddonViewModel : ViewModel() {
private val _addonList = MutableStateFlow(mutableListOf<Addon>())
val addonList get() = _addonList.asStateFlow()
private val _patchList = MutableStateFlow(mutableListOf<Patch>())
val addonList get() = _patchList.asStateFlow()
private val _showModInstallPicker = MutableStateFlow(false)
val showModInstallPicker get() = _showModInstallPicker.asStateFlow()
@ -24,6 +24,9 @@ class AddonViewModel : ViewModel() {
private val _showModNoticeDialog = MutableStateFlow(false)
val showModNoticeDialog get() = _showModNoticeDialog.asStateFlow()
private val _addonToDelete = MutableStateFlow<Patch?>(null)
val addonToDelete = _addonToDelete.asStateFlow()
var game: Game? = null
private val isRefreshing = AtomicBoolean(false)
@ -40,36 +43,47 @@ class AddonViewModel : ViewModel() {
isRefreshing.set(true)
viewModelScope.launch {
withContext(Dispatchers.IO) {
val addonList = mutableListOf<Addon>()
val disabledAddons = NativeConfig.getDisabledAddons(game!!.programId)
NativeLibrary.getAddonsForFile(game!!.path, game!!.programId)?.forEach {
val name = it.first.replace("[D] ", "")
addonList.add(Addon(!disabledAddons.contains(name), name, it.second))
}
addonList.sortBy { it.title }
_addonList.value = addonList
val patchList = (
NativeLibrary.getPatchesForFile(game!!.path, game!!.programId)
?: emptyArray()
).toMutableList()
patchList.sortBy { it.name }
_patchList.value = patchList
isRefreshing.set(false)
}
}
}
fun setAddonToDelete(patch: Patch?) {
_addonToDelete.value = patch
}
fun onDeleteAddon(patch: Patch) {
when (PatchType.from(patch.type)) {
PatchType.Update -> NativeLibrary.removeUpdate(patch.programId)
PatchType.DLC -> NativeLibrary.removeDLC(patch.programId)
PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name)
}
refreshAddons()
}
fun onCloseAddons() {
if (_addonList.value.isEmpty()) {
if (_patchList.value.isEmpty()) {
return
}
NativeConfig.setDisabledAddons(
game!!.programId,
_addonList.value.mapNotNull {
_patchList.value.mapNotNull {
if (it.enabled) {
null
} else {
it.title
it.name
}
}.toTypedArray()
)
NativeConfig.saveGlobalConfig()
_addonList.value.clear()
_patchList.value.clear()
game = null
}

View File

@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
data class Driver(
override var selected: Boolean,
val title: String,
val version: String = "",
val description: String = ""
) : SelectableItem {
override fun onSelectionStateChanged(selected: Boolean) {
this.selected = selected
}
companion object {
fun GpuDriverMetadata.toDriver(selected: Boolean = false): Driver =
Driver(
selected,
this.name ?: "",
this.version ?: "",
this.description ?: ""
)
}
}

View File

@ -9,6 +9,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@ -17,11 +18,10 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
import org.yuzu.yuzu_emu.utils.NativeConfig
import java.io.BufferedOutputStream
import java.io.File
class DriverViewModel : ViewModel() {
@ -38,97 +38,81 @@ class DriverViewModel : ViewModel() {
!loading && ready && !deleting
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false)
private val _driverList = MutableStateFlow(GpuDriverHelper.getDrivers())
val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList
var driverData = GpuDriverHelper.getDrivers()
var previouslySelectedDriver = 0
var selectedDriver = -1
private val _driverList = MutableStateFlow(emptyList<Driver>())
val driverList: StateFlow<List<Driver>> get() = _driverList
// Used for showing which driver is currently installed within the driver manager card
private val _selectedDriverTitle = MutableStateFlow("")
val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle
private val _newDriverInstalled = MutableStateFlow(false)
val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled
private val _showClearButton = MutableStateFlow(false)
val showClearButton = _showClearButton.asStateFlow()
val driversToDelete = mutableListOf<String>()
private val driversToDelete = mutableListOf<String>()
init {
val currentDriverMetadata = GpuDriverHelper.installedCustomDriverData
findSelectedDriver(currentDriverMetadata)
// If a user had installed a driver before the manager was implemented, this zips
// the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can
// be indexed and exported as expected.
if (selectedDriver == -1) {
val driverToSave =
File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip")
driverToSave.createNewFile()
FileUtil.zipFromInternalStorage(
File(GpuDriverHelper.driverInstallationPath!!),
GpuDriverHelper.driverInstallationPath!!,
BufferedOutputStream(driverToSave.outputStream())
)
_driverList.value.add(Pair(driverToSave.path, currentDriverMetadata))
setSelectedDriverIndex(_driverList.value.size - 1)
}
// If a user had installed a driver before the config was reworked to be multiplatform,
// we have save the path of the previously selected driver to the new setting.
if (StringSetting.DRIVER_PATH.getString(true).isEmpty() && selectedDriver > 0 &&
StringSetting.DRIVER_PATH.global
) {
StringSetting.DRIVER_PATH.setString(_driverList.value[selectedDriver].first)
NativeConfig.saveGlobalConfig()
} else {
findSelectedDriver(GpuDriverHelper.customDriverSettingData)
}
updateDriverList()
updateDriverNameForGame(null)
}
fun setSelectedDriverIndex(value: Int) {
if (selectedDriver != -1) {
previouslySelectedDriver = selectedDriver
fun reloadDriverData() {
_areDriversLoading.value = true
driverData = GpuDriverHelper.getDrivers()
updateDriverList()
_areDriversLoading.value = false
}
fun updateDriverList() {
val selectedDriver = GpuDriverHelper.customDriverSettingData
val newDriverList = mutableListOf(
Driver(
selectedDriver == GpuDriverMetadata(),
YuzuApplication.appContext.getString(R.string.system_gpu_driver)
)
)
driverData.forEach {
newDriverList.add(it.second.toDriver(it.second == selectedDriver))
}
selectedDriver = value
}
fun setNewDriverInstalled(value: Boolean) {
_newDriverInstalled.value = value
}
fun addDriver(driverData: Pair<String, GpuDriverMetadata>) {
val driverIndex = _driverList.value.indexOfFirst { it == driverData }
if (driverIndex == -1) {
_driverList.value.add(driverData)
setSelectedDriverIndex(_driverList.value.size - 1)
_selectedDriverTitle.value = driverData.second.name
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
} else {
setSelectedDriverIndex(driverIndex)
}
}
fun removeDriver(driverData: Pair<String, GpuDriverMetadata>) {
_driverList.value.remove(driverData)
_driverList.value = newDriverList
}
fun onOpenDriverManager(game: Game?) {
if (game != null) {
SettingsFile.loadCustomConfig(game)
}
updateDriverList()
}
val driverPath = StringSetting.DRIVER_PATH.getString()
if (driverPath.isEmpty()) {
setSelectedDriverIndex(0)
fun showClearButton(value: Boolean) {
_showClearButton.value = value
}
fun onDriverSelected(position: Int) {
if (position == 0) {
StringSetting.DRIVER_PATH.setString("")
} else {
findSelectedDriver(GpuDriverHelper.getMetadataFromZip(File(driverPath)))
StringSetting.DRIVER_PATH.setString(driverData[position - 1].first)
}
}
fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) {
driversToDelete.add(driverData[removedPosition - 1].first)
driverData.removeAt(removedPosition - 1)
onDriverSelected(selectedPosition)
}
fun onDriverAdded(driver: Pair<String, GpuDriverMetadata>) {
if (driversToDelete.contains(driver.first)) {
driversToDelete.remove(driver.first)
}
driverData.add(driver)
onDriverSelected(driverData.size)
}
fun onCloseDriverManager(game: Game?) {
_isDeletingDrivers.value = true
StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first)
updateDriverNameForGame(game)
if (game == null) {
NativeConfig.saveGlobalConfig()
@ -181,20 +165,6 @@ class DriverViewModel : ViewModel() {
}
}
private fun findSelectedDriver(currentDriverMetadata: GpuDriverMetadata) {
if (driverList.value.size == 1) {
setSelectedDriverIndex(0)
return
}
driverList.value.forEachIndexed { i: Int, driver: Pair<String, GpuDriverMetadata> ->
if (driver.second == currentDriverMetadata) {
setSelectedDriverIndex(i)
return
}
}
}
fun updateDriverNameForGame(game: Game?) {
if (!GpuDriverHelper.supportsCustomDriverLoading()) {
return
@ -217,7 +187,6 @@ class DriverViewModel : ViewModel() {
private fun setDriverReady() {
_isDriverReady.value = true
_selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
updateName()
}
}

View File

@ -3,6 +3,7 @@
package org.yuzu.yuzu_emu.model
import android.content.Intent
import android.net.Uri
import android.os.Parcelable
import java.util.HashSet
@ -11,6 +12,7 @@ import kotlinx.serialization.Serializable
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil
import java.time.LocalDateTime
@ -61,6 +63,12 @@ class Game(
val addonDir: String
get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
val launchIntent: Intent
get() = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
action = Intent.ACTION_VIEW
data = Uri.parse(path)
}
override fun equals(other: Any?): Boolean {
if (other !is Game) {
return false

View File

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
enum class GameVerificationResult(val int: Int) {
Success(0),
Failed(1),
NotImplemented(2);
companion object {
fun from(int: Int): GameVerificationResult =
entries.firstOrNull { it.int == int } ?: Success
}
}

View File

@ -167,13 +167,14 @@ class GamesViewModel : ViewModel() {
}
}
fun onCloseGameFoldersFragment() =
fun onCloseGameFoldersFragment() {
NativeConfig.saveGlobalConfig()
viewModelScope.launch {
withContext(Dispatchers.IO) {
NativeConfig.saveGlobalConfig()
getGameDirs(true)
}
}
}
private fun getGameDirs(reloadList: Boolean = false) {
val gameDirs = NativeConfig.getGameDirs()

View File

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
enum class InstallResult(val int: Int) {
Success(0),
Overwrite(1),
Failure(2),
BaseInstallAttempted(3);
companion object {
fun from(int: Int): InstallResult = entries.firstOrNull { it.int == int } ?: Success
}
}

View File

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
import androidx.annotation.Keep
@Keep
data class Patch(
var enabled: Boolean,
val name: String,
val version: String,
val type: Int,
val programId: String,
val titleId: String
)

View File

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
enum class PatchType(val int: Int) {
Update(0),
DLC(1),
Mod(2);
companion object {
fun from(int: Int): PatchType = entries.firstOrNull { it.int == int } ?: Update
}
}

View File

@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.model
interface SelectableItem {
var selected: Boolean
fun onSelectionStateChanged(selected: Boolean)
}

View File

@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
class TaskViewModel : ViewModel() {
@ -23,13 +24,28 @@ class TaskViewModel : ViewModel() {
val cancelled: StateFlow<Boolean> get() = _cancelled
private val _cancelled = MutableStateFlow(false)
lateinit var task: suspend () -> Any
private val _progress = MutableStateFlow(0.0)
val progress = _progress.asStateFlow()
private val _maxProgress = MutableStateFlow(0.0)
val maxProgress = _maxProgress.asStateFlow()
private val _message = MutableStateFlow("")
val message = _message.asStateFlow()
lateinit var task: suspend (
progressCallback: (max: Long, progress: Long) -> Boolean,
messageCallback: (message: String) -> Unit
) -> Any
fun clear() {
_result.value = Any()
_isComplete.value = false
_isRunning.value = false
_cancelled.value = false
_progress.value = 0.0
_maxProgress.value = 0.0
_message.value = ""
}
fun setCancelled(value: Boolean) {
@ -43,7 +59,16 @@ class TaskViewModel : ViewModel() {
_isRunning.value = true
viewModelScope.launch(Dispatchers.IO) {
val res = task()
val res = task(
{ max, progress ->
_maxProgress.value = max.toDouble()
_progress.value = progress.toDouble()
return@task cancelled.value
},
{ message ->
_message.value = message
}
)
_result.value = res
_isComplete.value = true
_isRunning.value = false

View File

@ -38,11 +38,13 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
import org.yuzu.yuzu_emu.fragments.ProgressDialogFragment
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.model.AddonViewModel
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.model.TaskViewModel
import org.yuzu.yuzu_emu.utils.*
@ -58,6 +60,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private val gamesViewModel: GamesViewModel by viewModels()
private val taskViewModel: TaskViewModel by viewModels()
private val addonViewModel: AddonViewModel by viewModels()
private val driverViewModel: DriverViewModel by viewModels()
override var themeId: Int = 0
@ -367,26 +370,23 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
val inputZip = contentResolver.openInputStream(result)
if (inputZip == null) {
Toast.makeText(
applicationContext,
getString(R.string.fatal_error),
Toast.LENGTH_LONG
).show()
return@registerForActivityResult
}
val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") }
val firmwarePath =
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
val cacheFirmwareDir = File("${cacheDir.path}/registered/")
val task: () -> Any = {
ProgressDialogFragment.newInstance(
this,
R.string.firmware_installing
) { progressCallback, _ ->
var messageToShow: Any
try {
FileUtil.unzipToInternalStorage(BufferedInputStream(inputZip), cacheFirmwareDir)
FileUtil.unzipToInternalStorage(
result.toString(),
cacheFirmwareDir,
progressCallback
)
val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1
val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2
messageToShow = if (unfilteredNumOfFiles != filteredNumOfFiles) {
@ -402,18 +402,13 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
getString(R.string.save_file_imported_success)
}
} catch (e: Exception) {
Log.error("[MainActivity] Firmware install failed - ${e.message}")
messageToShow = getString(R.string.fatal_error)
} finally {
cacheFirmwareDir.deleteRecursively()
}
messageToShow
}
IndeterminateProgressDialogFragment.newInstance(
this,
R.string.firmware_installing,
task = task
).show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}
val getAmiiboKey =
@ -472,11 +467,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
ProgressDialogFragment.newInstance(
this@MainActivity,
R.string.verifying_content,
false
) {
) { _, _ ->
var updatesMatchProgram = true
for (document in documents) {
val valid = NativeLibrary.doesUpdateMatchProgram(
@ -499,44 +494,42 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
positiveAction = { homeViewModel.setContentToInstall(documents) }
)
}
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}
private fun installContent(documents: List<Uri>) {
IndeterminateProgressDialogFragment.newInstance(
ProgressDialogFragment.newInstance(
this@MainActivity,
R.string.installing_game_content
) {
) { progressCallback, messageCallback ->
var installSuccess = 0
var installOverwrite = 0
var errorBaseGame = 0
var errorExtension = 0
var errorOther = 0
var error = 0
documents.forEach {
messageCallback.invoke(FileUtil.getFilename(it))
when (
NativeLibrary.installFileToNand(
it.toString(),
FileUtil.getExtension(it)
InstallResult.from(
NativeLibrary.installFileToNand(
it.toString(),
progressCallback
)
)
) {
NativeLibrary.InstallFileToNandResult.Success -> {
InstallResult.Success -> {
installSuccess += 1
}
NativeLibrary.InstallFileToNandResult.SuccessFileOverwritten -> {
InstallResult.Overwrite -> {
installOverwrite += 1
}
NativeLibrary.InstallFileToNandResult.ErrorBaseGame -> {
InstallResult.BaseInstallAttempted -> {
errorBaseGame += 1
}
NativeLibrary.InstallFileToNandResult.ErrorFilenameExtension -> {
errorExtension += 1
}
else -> {
errorOther += 1
InstallResult.Failure -> {
error += 1
}
}
}
@ -563,7 +556,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
)
installResult.append(separator)
}
val errorTotal: Int = errorBaseGame + errorExtension + errorOther
val errorTotal: Int = errorBaseGame + error
if (errorTotal > 0) {
installResult.append(separator)
installResult.append(
@ -580,14 +573,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
)
installResult.append(separator)
}
if (errorExtension > 0) {
installResult.append(separator)
installResult.append(
getString(R.string.install_game_content_failure_file_extension)
)
installResult.append(separator)
}
if (errorOther > 0) {
if (error > 0) {
installResult.append(
getString(R.string.install_game_content_failure_description)
)
@ -606,7 +592,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
descriptionString = installResult.toString().trim()
)
}
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}
val exportUserData = registerForActivityResult(
@ -616,23 +602,24 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
ProgressDialogFragment.newInstance(
this,
R.string.exporting_user_data,
true
) {
) { progressCallback, _ ->
val zipResult = FileUtil.zipFromInternalStorage(
File(DirectoryInitialization.userDirectory!!),
DirectoryInitialization.userDirectory!!,
BufferedOutputStream(contentResolver.openOutputStream(result)),
taskViewModel.cancelled
progressCallback,
compression = false
)
return@newInstance when (zipResult) {
TaskState.Completed -> getString(R.string.user_data_export_success)
TaskState.Failed -> R.string.export_failed
TaskState.Cancelled -> R.string.user_data_export_cancelled
}
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}
val importUserData =
@ -641,10 +628,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
IndeterminateProgressDialogFragment.newInstance(
ProgressDialogFragment.newInstance(
this,
R.string.importing_user_data
) {
) { progressCallback, _ ->
val checkStream =
ZipInputStream(BufferedInputStream(contentResolver.openInputStream(result)))
var isYuzuBackup = false
@ -673,8 +660,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
// Copy archive to internal storage
try {
FileUtil.unzipToInternalStorage(
BufferedInputStream(contentResolver.openInputStream(result)),
File(DirectoryInitialization.userDirectory!!)
result.toString(),
File(DirectoryInitialization.userDirectory!!),
progressCallback
)
} catch (e: Exception) {
return@newInstance MessageDialogFragment.newInstance(
@ -688,8 +676,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
NativeLibrary.initializeSystem(true)
NativeConfig.initializeGlobalConfig()
gamesViewModel.reloadGames(false)
driverViewModel.reloadDriverData()
return@newInstance getString(R.string.user_data_import_success)
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}
}

View File

@ -7,7 +7,6 @@ import android.database.Cursor
import android.net.Uri
import android.provider.DocumentsContract
import androidx.documentfile.provider.DocumentFile
import kotlinx.coroutines.flow.StateFlow
import java.io.BufferedInputStream
import java.io.File
import java.io.IOException
@ -19,8 +18,10 @@ import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
import org.yuzu.yuzu_emu.model.TaskState
import java.io.BufferedOutputStream
import java.io.OutputStream
import java.lang.NullPointerException
import java.nio.charset.StandardCharsets
import java.util.zip.Deflater
import java.util.zip.ZipOutputStream
import kotlin.IllegalStateException
@ -103,7 +104,7 @@ object FileUtil {
/**
* Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow
* This function will be faster than DoucmentFile.listFiles
* This function will be faster than DocumentFile.listFiles
* @param uri Directory uri.
* @return CheapDocument lists.
*/
@ -282,12 +283,34 @@ object FileUtil {
/**
* Extracts the given zip file into the given directory.
* @param path String representation of a [Uri] or a typical path delimited by '/'
* @param destDir Location to unzip the contents of [path] into
* @param progressCallback Lambda that is called with the total number of files and the current
* progress through the process. Stops execution as soon as possible if this returns true.
*/
@Throws(SecurityException::class)
fun unzipToInternalStorage(zipStream: BufferedInputStream, destDir: File) {
ZipInputStream(zipStream).use { zis ->
fun unzipToInternalStorage(
path: String,
destDir: File,
progressCallback: (max: Long, progress: Long) -> Boolean = { _, _ -> false }
) {
var totalEntries = 0L
ZipInputStream(getInputStream(path)).use { zis ->
var tempEntry = zis.nextEntry
while (tempEntry != null) {
tempEntry = zis.nextEntry
totalEntries++
}
}
var progress = 0L
ZipInputStream(getInputStream(path)).use { zis ->
var entry: ZipEntry? = zis.nextEntry
while (entry != null) {
if (progressCallback.invoke(totalEntries, progress)) {
return@use
}
val newFile = File(destDir, entry.name)
val destinationDirectory = if (entry.isDirectory) newFile else newFile.parentFile
@ -303,6 +326,7 @@ object FileUtil {
newFile.outputStream().use { fos -> zis.copyTo(fos) }
}
entry = zis.nextEntry
progress++
}
}
}
@ -312,17 +336,28 @@ object FileUtil {
* @param inputFile File representation of the item that will be zipped
* @param rootDir Directory containing the inputFile
* @param outputStream Stream where the zip file will be output
* @param progressCallback Lambda that is called with the total number of files and the current
* progress through the process. Stops execution as soon as possible if this returns true.
* @param compression Disables compression if true
*/
fun zipFromInternalStorage(
inputFile: File,
rootDir: String,
outputStream: BufferedOutputStream,
cancelled: StateFlow<Boolean>? = null
progressCallback: (max: Long, progress: Long) -> Boolean = { _, _ -> false },
compression: Boolean = true
): TaskState {
try {
ZipOutputStream(outputStream).use { zos ->
if (!compression) {
zos.setMethod(ZipOutputStream.DEFLATED)
zos.setLevel(Deflater.NO_COMPRESSION)
}
var count = 0L
val totalFiles = inputFile.walkTopDown().count().toLong()
inputFile.walkTopDown().forEach { file ->
if (cancelled?.value == true) {
if (progressCallback.invoke(totalFiles, count)) {
return TaskState.Cancelled
}
@ -334,10 +369,12 @@ object FileUtil {
if (file.isFile) {
file.inputStream().use { fis -> fis.copyTo(zos) }
}
count++
}
}
}
} catch (e: Exception) {
Log.error("[FileUtil] Failed creating zip file - ${e.message}")
return TaskState.Failed
}
return TaskState.Completed
@ -346,9 +383,14 @@ object FileUtil {
/**
* Helper function that copies the contents of a DocumentFile folder into a [File]
* @param file [File] representation of the folder to copy into
* @param progressCallback Lambda that is called with the total number of files and the current
* progress through the process. Stops execution as soon as possible if this returns true.
* @throws IllegalStateException Fails when trying to copy a folder into a file and vice versa
*/
fun DocumentFile.copyFilesTo(file: File) {
fun DocumentFile.copyFilesTo(
file: File,
progressCallback: (max: Long, progress: Long) -> Boolean = { _, _ -> false }
) {
file.mkdirs()
if (!this.isDirectory || !file.isDirectory) {
throw IllegalStateException(
@ -356,7 +398,13 @@ object FileUtil {
)
}
var count = 0L
val totalFiles = this.listFiles().size.toLong()
this.listFiles().forEach {
if (progressCallback.invoke(totalFiles, count)) {
return
}
val newFile = File(file, it.name!!)
if (it.isDirectory) {
newFile.mkdirs()
@ -371,6 +419,7 @@ object FileUtil {
newFile.outputStream().use { os -> bos.copyTo(os) }
}
}
count++
}
}
@ -417,6 +466,18 @@ object FileUtil {
}
}
fun getInputStream(path: String) = if (path.contains("content://")) {
Uri.parse(path).inputStream()
} else {
File(path).inputStream()
}
fun getOutputStream(path: String) = if (path.contains("content://")) {
Uri.parse(path).outputStream()
} else {
File(path).outputStream()
}
@Throws(IOException::class)
fun getStringFromFile(file: File): String =
String(file.readBytes(), StandardCharsets.UTF_8)
@ -424,4 +485,19 @@ object FileUtil {
@Throws(IOException::class)
fun getStringFromInputStream(stream: InputStream): String =
String(stream.readBytes(), StandardCharsets.UTF_8)
fun DocumentFile.inputStream(): InputStream =
YuzuApplication.appContext.contentResolver.openInputStream(uri)!!
fun DocumentFile.outputStream(): OutputStream =
YuzuApplication.appContext.contentResolver.openOutputStream(uri)!!
fun Uri.inputStream(): InputStream =
YuzuApplication.appContext.contentResolver.openInputStream(this)!!
fun Uri.outputStream(): OutputStream =
YuzuApplication.appContext.contentResolver.openOutputStream(this)!!
fun Uri.asDocumentFile(): DocumentFile? =
DocumentFile.fromSingleUri(YuzuApplication.appContext, this)
}

View File

@ -5,7 +5,10 @@ package org.yuzu.yuzu_emu.utils
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.LayerDrawable
import android.widget.ImageView
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.IconCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable
import androidx.lifecycle.LifecycleOwner
@ -85,4 +88,22 @@ object GameIconUtils {
return imageLoader.execute(request)
.drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888)
}
suspend fun getShortcutIcon(lifecycleOwner: LifecycleOwner, game: Game): IconCompat {
val layerDrawable = ResourcesCompat.getDrawable(
YuzuApplication.appContext.resources,
R.drawable.shortcut,
null
) as LayerDrawable
layerDrawable.setDrawableByLayerId(
R.id.shortcut_foreground,
getGameIcon(lifecycleOwner, game).toDrawable(YuzuApplication.appContext.resources)
)
val inset = YuzuApplication.appContext.resources
.getDimensionPixelSize(R.dimen.icon_inset)
layerDrawable.setLayerInset(1, inset, inset, inset, inset)
return IconCompat.createWithAdaptiveBitmap(
layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
)
}
}

View File

@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.utils
import android.net.Uri
import android.os.Build
import java.io.BufferedInputStream
import java.io.File
import java.io.IOException
import org.yuzu.yuzu_emu.NativeLibrary
@ -62,9 +61,6 @@ object GpuDriverHelper {
?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name }
?.distinct()
?.toMutableList() ?: mutableListOf()
// TODO: Get system driver information
drivers.add(0, Pair("", GpuDriverMetadata()))
return drivers
}
@ -126,7 +122,7 @@ object GpuDriverHelper {
// Unzip the driver.
try {
FileUtil.unzipToInternalStorage(
BufferedInputStream(copiedFile.inputStream()),
copiedFile.path,
File(driverInstallationPath!!)
)
} catch (e: SecurityException) {
@ -159,7 +155,7 @@ object GpuDriverHelper {
// Unzip the driver to the private installation directory
try {
FileUtil.unzipToInternalStorage(
BufferedInputStream(driver.inputStream()),
driver.path,
File(driverInstallationPath!!)
)
} catch (e: SecurityException) {

View File

@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.viewholder
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import org.yuzu.yuzu_emu.adapters.AbstractDiffAdapter
import org.yuzu.yuzu_emu.adapters.AbstractListAdapter
/**
* [RecyclerView.ViewHolder] meant to work together with a [AbstractDiffAdapter] or a
* [AbstractListAdapter] so we can run [bind] on each list item without needing a manual hookup.
*/
abstract class AbstractViewHolder<Model>(binding: ViewBinding) :
RecyclerView.ViewHolder(binding.root) {
abstract fun bind(model: Model)
}

View File

@ -42,3 +42,19 @@ double GetJDouble(JNIEnv* env, jobject jdouble) {
jobject ToJDouble(JNIEnv* env, double value) {
return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value);
}
s32 GetJInteger(JNIEnv* env, jobject jinteger) {
return env->GetIntField(jinteger, IDCache::GetIntegerValueField());
}
jobject ToJInteger(JNIEnv* env, s32 value) {
return env->NewObject(IDCache::GetIntegerClass(), IDCache::GetIntegerConstructor(), value);
}
bool GetJBoolean(JNIEnv* env, jobject jboolean) {
return env->GetBooleanField(jboolean, IDCache::GetBooleanValueField());
}
jobject ToJBoolean(JNIEnv* env, bool value) {
return env->NewObject(IDCache::GetBooleanClass(), IDCache::GetBooleanConstructor(), value);
}

View File

@ -6,6 +6,7 @@
#include <string>
#include <jni.h>
#include "common/common_types.h"
std::string GetJString(JNIEnv* env, jstring jstr);
jstring ToJString(JNIEnv* env, std::string_view str);
@ -13,3 +14,9 @@ jstring ToJString(JNIEnv* env, std::u16string_view str);
double GetJDouble(JNIEnv* env, jobject jdouble);
jobject ToJDouble(JNIEnv* env, double value);
s32 GetJInteger(JNIEnv* env, jobject jinteger);
jobject ToJInteger(JNIEnv* env, s32 value);
bool GetJBoolean(JNIEnv* env, jobject jboolean);
jobject ToJBoolean(JNIEnv* env, bool value);

View File

@ -14,12 +14,6 @@ AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_t
}
}
AndroidConfig::~AndroidConfig() {
if (global) {
AndroidConfig::SaveAllValues();
}
}
void AndroidConfig::ReloadAllValues() {
Reload();
ReadAndroidValues();
@ -27,7 +21,7 @@ void AndroidConfig::ReloadAllValues() {
}
void AndroidConfig::SaveAllValues() {
Save();
SaveValues();
SaveAndroidValues();
}

View File

@ -9,7 +9,6 @@ class AndroidConfig final : public Config {
public:
explicit AndroidConfig(const std::string& config_name = "config",
ConfigType config_type = ConfigType::GlobalConfig);
~AndroidConfig() override;
void ReloadAllValues() override;
void SaveAllValues() override;

View File

@ -63,6 +63,7 @@ struct Values {
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
Settings::Category::Overlay};
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
Settings::Setting<s32> lock_drawer{linkage, false, "lock_drawer", Settings::Category::Overlay};
};
extern Values values;

View File

@ -43,10 +43,27 @@ static jfieldID s_overlay_control_data_landscape_position_field;
static jfieldID s_overlay_control_data_portrait_position_field;
static jfieldID s_overlay_control_data_foldable_position_field;
static jclass s_patch_class;
static jmethodID s_patch_constructor;
static jfieldID s_patch_enabled_field;
static jfieldID s_patch_name_field;
static jfieldID s_patch_version_field;
static jfieldID s_patch_type_field;
static jfieldID s_patch_program_id_field;
static jfieldID s_patch_title_id_field;
static jclass s_double_class;
static jmethodID s_double_constructor;
static jfieldID s_double_value_field;
static jclass s_integer_class;
static jmethodID s_integer_constructor;
static jfieldID s_integer_value_field;
static jclass s_boolean_class;
static jmethodID s_boolean_constructor;
static jfieldID s_boolean_value_field;
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
namespace IDCache {
@ -186,6 +203,38 @@ jfieldID GetOverlayControlDataFoldablePositionField() {
return s_overlay_control_data_foldable_position_field;
}
jclass GetPatchClass() {
return s_patch_class;
}
jmethodID GetPatchConstructor() {
return s_patch_constructor;
}
jfieldID GetPatchEnabledField() {
return s_patch_enabled_field;
}
jfieldID GetPatchNameField() {
return s_patch_name_field;
}
jfieldID GetPatchVersionField() {
return s_patch_version_field;
}
jfieldID GetPatchTypeField() {
return s_patch_type_field;
}
jfieldID GetPatchProgramIdField() {
return s_patch_program_id_field;
}
jfieldID GetPatchTitleIdField() {
return s_patch_title_id_field;
}
jclass GetDoubleClass() {
return s_double_class;
}
@ -198,6 +247,30 @@ jfieldID GetDoubleValueField() {
return s_double_value_field;
}
jclass GetIntegerClass() {
return s_integer_class;
}
jmethodID GetIntegerConstructor() {
return s_integer_constructor;
}
jfieldID GetIntegerValueField() {
return s_integer_value_field;
}
jclass GetBooleanClass() {
return s_boolean_class;
}
jmethodID GetBooleanConstructor() {
return s_boolean_constructor;
}
jfieldID GetBooleanValueField() {
return s_boolean_value_field;
}
} // namespace IDCache
#ifdef __cplusplus
@ -278,12 +351,37 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
env->DeleteLocalRef(overlay_control_data_class);
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
s_patch_constructor = env->GetMethodID(
patch_class, "<init>",
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V");
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
env->DeleteLocalRef(patch_class);
const jclass double_class = env->FindClass("java/lang/Double");
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
s_double_value_field = env->GetFieldID(double_class, "value", "D");
env->DeleteLocalRef(double_class);
const jclass int_class = env->FindClass("java/lang/Integer");
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
s_integer_value_field = env->GetFieldID(int_class, "value", "I");
env->DeleteLocalRef(int_class);
const jclass boolean_class = env->FindClass("java/lang/Boolean");
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z");
env->DeleteLocalRef(boolean_class);
// Initialize Android Storage
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
@ -309,7 +407,10 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
env->DeleteGlobalRef(s_string_class);
env->DeleteGlobalRef(s_pair_class);
env->DeleteGlobalRef(s_overlay_control_data_class);
env->DeleteGlobalRef(s_patch_class);
env->DeleteGlobalRef(s_double_class);
env->DeleteGlobalRef(s_integer_class);
env->DeleteGlobalRef(s_boolean_class);
// UnInitialize applets
SoftwareKeyboard::CleanupJNI(env);

View File

@ -43,8 +43,25 @@ jfieldID GetOverlayControlDataLandscapePositionField();
jfieldID GetOverlayControlDataPortraitPositionField();
jfieldID GetOverlayControlDataFoldablePositionField();
jclass GetPatchClass();
jmethodID GetPatchConstructor();
jfieldID GetPatchEnabledField();
jfieldID GetPatchNameField();
jfieldID GetPatchVersionField();
jfieldID GetPatchTypeField();
jfieldID GetPatchProgramIdField();
jfieldID GetPatchTitleIdField();
jclass GetDoubleClass();
jmethodID GetDoubleConstructor();
jfieldID GetDoubleValueField();
jclass GetIntegerClass();
jmethodID GetIntegerConstructor();
jfieldID GetIntegerValueField();
jclass GetBooleanClass();
jmethodID GetBooleanConstructor();
jfieldID GetBooleanValueField();
} // namespace IDCache

View File

@ -17,6 +17,7 @@
#include <core/file_sys/patch_manager.h>
#include <core/file_sys/savedata_factory.h>
#include <core/loader/nro.h>
#include <frontend_common/content_manager.h>
#include <jni.h>
#include "common/detached_tasks.h"
@ -45,15 +46,15 @@
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "frontend_common/config.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
#include "jni/android_common/android_common.h"
#include "jni/id_cache.h"
#include "jni/native.h"
@ -100,67 +101,6 @@ void EmulationSession::SetNativeWindow(ANativeWindow* native_window) {
m_native_window = native_window;
}
int EmulationSession::InstallFileToNand(std::string filename, std::string file_extension) {
jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
std::size_t block_size) {
if (src == nullptr || dest == nullptr) {
return false;
}
if (!dest->Resize(src->GetSize())) {
return false;
}
using namespace Common::Literals;
[[maybe_unused]] std::vector<u8> buffer(1_MiB);
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
jconst read = src->Read(buffer.data(), buffer.size(), i);
dest->Write(buffer.data(), read, i);
}
return true;
};
enum InstallResult {
Success = 0,
SuccessFileOverwritten = 1,
InstallError = 2,
ErrorBaseGame = 3,
ErrorFilenameExtension = 4,
};
[[maybe_unused]] std::shared_ptr<FileSys::NSP> nsp;
if (file_extension == "nsp") {
nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
if (nsp->IsExtractedType()) {
return InstallError;
}
} else {
return ErrorFilenameExtension;
}
if (!nsp) {
return InstallError;
}
if (nsp->GetStatus() != Loader::ResultStatus::Success) {
return InstallError;
}
jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true,
copy_func);
switch (res) {
case FileSys::InstallResult::Success:
return Success;
case FileSys::InstallResult::OverwriteExisting:
return SuccessFileOverwritten;
case FileSys::InstallResult::ErrorBaseInstall:
return ErrorBaseGame;
default:
return InstallError;
}
}
void EmulationSession::InitializeGpuDriver(const std::string& hook_lib_dir,
const std::string& custom_driver_dir,
const std::string& custom_driver_name,
@ -410,8 +350,8 @@ void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) {
jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
handheld->Disconnect();
}
}
@ -512,10 +452,20 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject
}
int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance,
jstring j_file,
jstring j_file_extension) {
return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file),
GetJString(env, j_file_extension));
jstring j_file, jobject jcallback) {
auto jlambdaClass = env->GetObjectClass(jcallback);
auto jlambdaInvokeMethod = env->GetMethodID(
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
ToJDouble(env, max), ToJDouble(env, progress));
return GetJBoolean(env, jwasCancelled);
};
return static_cast<int>(
ContentManager::InstallNSP(&EmulationSession::GetInstance().System(),
EmulationSession::GetInstance().System().GetFilesystem().get(),
GetJString(env, j_file), callback));
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
@ -770,8 +720,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
EmulationSession::GetInstance().System(), vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser,
FileSys::SaveDataType::SaveData, 1, user_id->AsU128(), 0);
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1,
user_id->AsU128(), 0);
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
if (!Common::FS::CreateParentDirs(full_path)) {
@ -824,9 +774,9 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env,
return true;
}
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env, jobject jobj,
jstring jpath,
jstring jprogramId) {
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj,
jstring jpath,
jstring jprogramId) {
const auto path = GetJString(env, jpath);
const auto vFile =
Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path);
@ -843,25 +793,85 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env,
FileSys::VirtualFile update_raw;
loader->ReadUpdateRaw(update_raw);
auto addons = pm.GetPatchVersionNames(update_raw);
auto jemptyString = ToJString(env, "");
auto jemptyStringPair = env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
jemptyString, jemptyString);
jobjectArray jaddonsArray =
env->NewObjectArray(addons.size(), IDCache::GetPairClass(), jemptyStringPair);
auto patches = pm.GetPatches(update_raw);
jobjectArray jpatchArray =
env->NewObjectArray(patches.size(), IDCache::GetPatchClass(), nullptr);
int i = 0;
for (const auto& addon : addons) {
jobject jaddon = env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(),
ToJString(env, addon.first), ToJString(env, addon.second));
env->SetObjectArrayElement(jaddonsArray, i, jaddon);
for (const auto& patch : patches) {
jobject jpatch = env->NewObject(
IDCache::GetPatchClass(), IDCache::GetPatchConstructor(), patch.enabled,
ToJString(env, patch.name), ToJString(env, patch.version),
static_cast<jint>(patch.type), ToJString(env, std::to_string(patch.program_id)),
ToJString(env, std::to_string(patch.title_id)));
env->SetObjectArrayElement(jpatchArray, i, jpatch);
++i;
}
return jaddonsArray;
return jpatchArray;
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject jobj,
jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveUpdate(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj,
jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveAllDLC(&EmulationSession::GetInstance().System(), program_id);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId,
jstring jname) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id, GetJString(env, jname));
}
jobject Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env, jobject jobj,
jobject jcallback) {
auto jlambdaClass = env->GetObjectClass(jcallback);
auto jlambdaInvokeMethod = env->GetMethodID(
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
ToJDouble(env, max), ToJDouble(env, progress));
return GetJBoolean(env, jwasCancelled);
};
auto& session = EmulationSession::GetInstance();
std::vector<std::string> result = ContentManager::VerifyInstalledContents(
&session.System(), session.GetContentProvider(), callback);
jobjectArray jresult =
env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, ""));
for (size_t i = 0; i < result.size(); ++i) {
env->SetObjectArrayElement(jresult, i, ToJString(env, result[i]));
}
return jresult;
}
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobject jobj,
jstring jpath, jobject jcallback) {
auto jlambdaClass = env->GetObjectClass(jcallback);
auto jlambdaInvokeMethod = env->GetMethodID(
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
ToJDouble(env, max), ToJDouble(env, progress));
return GetJBoolean(env, jwasCancelled);
};
auto& session = EmulationSession::GetInstance();
return static_cast<jint>(
ContentManager::VerifyGameContents(&session.System(), GetJString(env, jpath), callback));
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
if (program_id == 0) {
return ToJString(env, "");
}
auto& system = EmulationSession::GetInstance().System();
@ -875,11 +885,24 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
FileSys::Mode::Read);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
system, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
program_id, user_id->AsU128(), 0);
return ToJString(env, user_save_data_path);
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIEnv* env,
jobject jobj,
jboolean jfuture) {
Service::Account::ProfileManager manager;
// TODO: Pass in a selected user once we get the relevant UI working
const auto user_id = manager.GetUser(static_cast<std::size_t>(0));
ASSERT(user_id);
const auto user_save_data_root =
FileSys::SaveDataFactory::GetUserGameSaveDataRoot(user_id->AsU128(), jfuture);
return ToJString(env, user_save_data_root);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj,
jstring jpath) {
EmulationSession::GetInstance().ConfigureFilesystemProvider(GetJString(env, jpath));

View File

@ -7,6 +7,7 @@
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/perf_stats.h"
#include "frontend_common/content_manager.h"
#include "jni/applets/software_keyboard.h"
#include "jni/emu_window/emu_window.h"
#include "video_core/rasterizer_interface.h"
@ -29,7 +30,6 @@ public:
void SetNativeWindow(ANativeWindow* native_window);
void SurfaceChanged();
int InstallFileToNand(std::string filename, std::string file_extension);
void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
const std::string& custom_driver_name,
const std::string& file_redirect_dir);

View File

@ -205,7 +205,7 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEn
jstring jkey) {
auto setting = getSetting<std::string>(env, jkey);
if (setting != nullptr) {
return setting->RuntimeModfiable();
return setting->RuntimeModifiable();
}
return true;
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M280,920q-33,0 -56.5,-23.5T200,840v-720q0,-33 23.5,-56.5T280,40h400q33,0 56.5,23.5T760,120v160h-80v-40L280,240v480h400v-40h80v160q0,33 -23.5,56.5T680,920L280,920ZM686,520L480,520v120h-80v-120q0,-33 23.5,-56.5T480,440h206l-62,-64 56,-56 160,160 -160,160 -56,-56 62,-64Z" />
</vector>

View File

@ -147,7 +147,7 @@
android:layout_marginHorizontal="20dp" />
<LinearLayout
android:id="@+id/button_build_hash"
android:id="@+id/button_version_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
@ -164,7 +164,7 @@
android:textAlignment="viewStart" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_build_hash"
android:id="@+id/text_version_name"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -43,16 +43,35 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="@+id/button_back"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_margin="8dp"
app:icon="@drawable/ic_back"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface" />
android:orientation="horizontal">
<Button
android:id="@+id/button_back"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_back"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_shortcut"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_shortcut"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewElevatedStyle"

View File

@ -2,16 +2,16 @@
<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/materialCardViewFilledStyle"
style="?attr/materialCardViewElevatedStyle"
android:id="@+id/option_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:layout_marginHorizontal="12dp"
android:background="?attr/selectableItemBackground"
android:backgroundTint="?attr/colorSurfaceVariant"
android:clickable="true"
android:focusable="true">
android:focusable="true"
app:cardElevation="4dp">
<LinearLayout
android:id="@+id/option_layout"

View File

@ -1,8 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.progressindicator.LinearProgressIndicator xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp"
app:trackCornerRadius="4dp" />
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/message"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="6dp"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart"
android:visibility="gone" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp"
app:trackCornerRadius="4dp" />
</LinearLayout>

View File

@ -148,7 +148,7 @@
android:layout_marginHorizontal="20dp" />
<LinearLayout
android:id="@+id/button_build_hash"
android:id="@+id/button_version_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="16dp"
@ -165,7 +165,7 @@
android:text="@string/build" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_build_hash"
android:id="@+id/text_version_name"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -118,6 +118,14 @@
android:layout_marginTop="16dp"
android:text="@string/copy_details" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_verify_integrity"
style="@style/Widget.Material3.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/verify_integrity" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout 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"
@ -22,16 +21,35 @@
android:orientation="vertical"
android:gravity="center_horizontal">
<Button
android:id="@+id/button_back"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_gravity="start"
app:icon="@drawable/ic_back"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface" />
android:orientation="horizontal">
<Button
android:id="@+id/button_back"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_back"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_shortcut"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_shortcut"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewElevatedStyle"
@ -45,7 +63,7 @@
android:id="@+id/image_game_screen"
android:layout_width="175dp"
android:layout_height="175dp"
tools:src="@drawable/default_icon"/>
tools:src="@drawable/default_icon" />
</com.google.android.material.card.MaterialCardView>

View File

@ -14,12 +14,11 @@
android:id="@+id/text_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="@+id/addon_switch"
app:layout_constraintEnd_toStartOf="@+id/addon_switch"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toStartOf="@+id/addon_checkbox"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/addon_switch">
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/title"
@ -42,16 +41,29 @@
</LinearLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/addon_switch"
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/addon_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:gravity="center"
android:nextFocusLeft="@id/addon_container"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="@+id/text_container"
app:layout_constraintBottom_toBottomOf="@+id/text_container"
app:layout_constraintEnd_toStartOf="@+id/button_delete" />
<Button
android:id="@+id/button_delete"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/delete"
android:tooltipText="@string/delete"
app:icon="@drawable/ic_delete"
app:iconTint="?attr/colorControlNormal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/text_container"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="@+id/addon_checkbox"
app:layout_constraintBottom_toBottomOf="@+id/addon_checkbox" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -69,7 +69,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:visibility="gone"
android:text="@string/clear"
android:text="@string/use_global_setting"
tools:visibility="visible" />
</LinearLayout>

View File

@ -63,7 +63,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/clear"
android:text="@string/use_global_setting"
android:visibility="gone"
tools:visibility="visible" />

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_driver_use_global"
android:title="@string/use_global_setting" />
</menu>

View File

@ -21,6 +21,11 @@
android:icon="@drawable/ic_controller"
android:title="@string/emulation_input_overlay" />
<item
android:id="@+id/menu_lock_drawer"
android:icon="@drawable/ic_unlock"
android:title="@string/emulation_input_overlay" />
<item
android:id="@+id/menu_exit"
android:icon="@drawable/ic_exit"

View File

@ -3,38 +3,39 @@
<string name="emulation_notification_channel_name">المحاكي نشط</string>
<string name="emulation_notification_channel_description">اظهار اشعار دائم عندما يكون المحاكي نشطاً</string>
<string name="emulation_notification_running">يوزو يعمل</string>
<string name="emulation_notification_running">يوزو قيد التشغيل</string>
<string name="notice_notification_channel_name">الإشعارات والأخطاء</string>
<string name="notice_notification_channel_description">اظهار اشعار عند حصول اي مشكلة.</string>
<string name="notification_permission_not_granted">لم يتم منح إذن الإشعار</string>
<!-- Setup strings -->
<string name="welcome">مرحبًا</string>
<string name="welcome_description">والانتقال إلى المحاكاة <b>يوزو</b> تعرف على كيفية إعداد.</string>
<string name="welcome">مرحبا</string>
<string name="welcome_description">تعرف على كيفية إعداد <b>يوزو</b> والانتقال إلى المحاكاة</string>
<string name="get_started">لنبدأ</string>
<string name="keys">المفاتيح</string>
<string name="keys_description">اختر ملف &lt;b>prod.keys&lt;/b> من الزر ادناه</string>
<string name="select_keys">إختيار المفاتيح</string>
<string name="games">الألعاب</string>
<string name="games_description">اختر مجلد &lt;b>العابك&lt;/b> من الزر ادناه.</string>
<string name="games_description">حدد مجلد &lt;b>العابك&lt;/b> من الزر ادناه.</string>
<string name="done">إنهاء</string>
<string name="done_description">كل شيء جاهز./n استمتع بألعابك!</string>
<string name="done_description">أنت جاهز تمامًا. استمتع بألعابك!</string>
<string name="text_continue">استمر</string>
<string name="next">التالي</string>
<string name="back">عودة</string>
<string name="add_games">إضافة ألعاب</string>
<string name="add_games_description">إختار مجلد ألعابك</string>
<string name="add_games_description">حدد مجلد الألعاب الخاص بك</string>
<string name="step_complete">مكتمل</string>
<!-- Home strings -->
<string name="home_games">الألعاب</string>
<string name="home_search">البحث</string>
<string name="home_settings">الإعدادات</string>
<string name="empty_gamelist">لم يتم العثور على ملفات او لم يتم تحديد مسار العاب.</string>
<string name="search_and_filter_games">بحث وتصفية الألعاب</string>
<string name="select_games_folder">تحديد مجلد الألعاب</string>
<string name="empty_gamelist">لم يتم العثور على ملفات أو لم يتم تحديد مجلد الألعاب حتى الآن.</string>
<string name="search_and_filter_games">البحث وتصفية الألعاب</string>
<string name="select_games_folder">حدد مجلد الألعاب</string>
<string name="manage_game_folders">إدارة مجلدات اللعبة</string>
<string name="select_games_folder_description">يسمح لـ يوزو بملء قائمة الألعاب</string>
<string name="add_games_warning">تخطُ اختيار مجلد الالعاب؟</string>
<string name="add_games_warning">تخطي تحديد مجلد الألعاب؟</string>
<string name="add_games_warning_description">لن يتم عرض الألعاب في قائمة الألعاب إذا لم يتم تحديد مجلد</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
<string name="home_search_games">البحث عن ألعاب</string>
@ -45,7 +46,7 @@
<string name="install_prod_keys_warning">تخطي إضافة المفاتيح؟</string>
<string name="install_prod_keys_warning_description">مطلوب مفاتيح صالحة لمحاكاة ألعاب البيع بالتجزئة. ستعمل تطبيقات البيرة المنزلية فقط إذا تابعت</string>
<string name="install_prod_keys_warning_help">https://yuzu-emu.org/help/quickstart/#guide-introduction</string>
<string name="notifications">التنبيهات</string>
<string name="notifications">الإشعارات</string>
<string name="notifications_description">امنح إذن الإشعار باستخدام الزر أدناه</string>
<string name="give_permission">منح الإذن</string>
<string name="notification_warning">تخطي منح إذن الإشعارات؟</string>
@ -62,9 +63,12 @@
<string name="invalid_keys_file">تم تحديد ملف مفاتيح غير صالح</string>
<string name="install_keys_success">تم تثبيت المفاتيح بنجاح</string>
<string name="reading_keys_failure">خطأ في قراءة مفاتيح التشفير</string>
<string name="install_prod_keys_failure_extension_description">وحاول مرة أخر keys تحقق من أن ملف المفاتيح له امتداد</string>
<string name="install_amiibo_keys_failure_extension_description">وحاول مرة أخر bin تحقق من أن ملف المفاتيح له امتداد</string>
<string name="invalid_keys_error">مفاتيح التشفير غير صالحة</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">الملف المحدد غير صحيح أو تالف. يرجى إعادة المفاتيح الخاصة بك</string>
<string name="gpu_driver_manager">GPU مدير برنامج تشغيل</string>
<string name="install_gpu_driver">GPU تثبيت برنامج تشغيل</string>
<string name="install_gpu_driver_description">قم بتثبيت برامج تشغيل بديلة للحصول على أداء أو دقة أفضل</string>
<string name="advanced_settings">إعدادات متقدمة</string>
@ -82,22 +86,27 @@
<string name="notification_no_directory_link_description">الرجاء تحديد موقع مجلد المستخدم باستخدام اللوحة الجانبية لمدير الملفات يدويًا</string>
<string name="manage_save_data">إدارة حفظ البيانات</string>
<string name="manage_save_data_description">حفظ البيانات التي تم العثور عليها. يرجى اختيار أحد الخيارات التالية</string>
<string name="import_save_warning">استيراد حفظ البيانات</string>
<string name="import_save_warning_description">سيؤدي هذا إلى استبدال جميع بيانات الحفظ الموجودة بالملف المقدم. هل أنت متأكد أنك تريد الاستمرار؟</string>
<string name="import_export_saves_description">استيراد أو تصدير ملفات الحفظ</string>
<string name="save_files_importing">جاري استيراد ملفات الحفظ</string>
<string name="save_files_exporting">جاري تصدير ملفات الحفظ</string>
<string name="save_file_imported_success">تم الاستيراد بنجاح</string>
<string name="save_file_invalid_zip_structure">بنية مجلد الحفظ غير صالحة</string>
<string name="save_file_invalid_zip_structure_description">يجب أن يكون اسم المجلد الفرعي الأول هو معرف عنوان اللعبة.</string>
<string name="import_saves">استيراد</string>
<string name="export_saves">تصدير</string>
<string name="install_firmware">تثبيت البرامج الثابتة</string>
<string name="firmware_installing">تثبيت البرامج الثابتة</string>
<string name="firmware_installed_success">تم تثبيت البرامج الثابتة بنجاح</string>
<string name="firmware_installed_failure">فشل تثبيت البرامج الثابتة</string>
<string name="install_firmware">تثبيت فيرموير</string>
<string name="install_firmware_description">يجب أن يكون فيرموير في أرشيف مضغوط وهو ضروري لتشغيل بعض الألعاب</string>
<string name="firmware_installing">تثبيت فيرموير</string>
<string name="firmware_installed_success">تم تثبيت فيرموير بنجاح</string>
<string name="firmware_installed_failure">فشل تثبيت فيرموير</string>
<string name="share_log">مشاركة سجلات التصحيح</string>
<string name="share_log_description">مشاركة ملف سجل يوزو لتصحيح المشكلات</string>
<string name="share_log_missing">لم يتم العثور على ملف السجل</string>
<string name="install_game_content">تثبيت محتوى اللعبة</string>
<string name="install_game_content_description">DLC قم بتثبيت تحديثات اللعبة أو</string>
<string name="installing_game_content">جارٍ تثبيت المحتوى</string>
<string name="installing_game_content">جاري تثبيت المحتوى</string>
<string name="install_game_content_failure_base">لا يُسمح بتثبيت الألعاب الأساسية لتجنب التعارضات المحتملة.</string>
<string name="install_game_content_success_install">%1$d تم التثبيت بنجاح</string>
<string name="install_game_content_success_overwrite">%1$d تمت الكتابة فوقه بنجاح</string>
@ -105,19 +114,39 @@
<string name="custom_driver_not_supported">برامج التشغيل المخصصة غير مدعومة</string>
<string name="custom_driver_not_supported_description">تحميل برنامج التشغيل المخصص غير معتمد حاليًا لهذا الجهاز.\nحدد هذا الخيار مرة أخرى في المستقبل لمعرفة ما إذا تمت إضافة الدعم!</string>
<string name="manage_yuzu_data">إدارة بيانات يوزو</string>
<string name="manage_yuzu_data_description">استيراد/تصدير البرامج الثابتة والمفاتيح وبيانات المستخدم والمزيد!</string>
<string name="manage_yuzu_data_description">استيراد/تصدير فيرموير والمفاتيح وبيانات المستخدم والمزيد</string>
<string name="share_save_file">مشاركة ملف الحفظ</string>
<string name="export_save_failed">فشل تصدير الحفظ</string>
<string name="game_folders">مجلدات اللعبة</string>
<string name="deep_scan">فحص عميق</string>
<string name="add_game_folder">إضافة مجلد اللعبة</string>
<string name="folder_already_added">تمت إضافة هذا المجلد بالفعل</string>
<string name="game_folder_properties">خصائص مجلد اللعبة</string>
<string name="no_save_data_found">لم يتم العثور على بيانات الحفظ</string>
<!-- Applet launcher strings -->
<string name="applets">قائمة التطبيقات المصغرة</string>
<string name="applets_description">قم بتشغيل تطبيقات النظام باستخدام فيرموير المثبت</string>
<string name="applets_error_firmware">فيرموير غير مثبت</string>
<string name="applets_error_applet">التطبيق المصغر غير متوفر</string>
<string name="album_applet">الألبوم</string>
<string name="album_applet_description">شاهد الصور المخزنة في مجلد لقطات شاشة المستخدم باستخدام عارض صور النظام</string>
<string name="mii_edit_applet">تحرير Mii</string>
<string name="mii_edit_applet_description">باستخدام محرر النظام Miis عرض وتحرير</string>
<string name="cabinet_applet_description">تحرير وحذف البيانات المخزنة على أميبو</string>
<string name="cabinet_nickname_and_owner">إعدادات الاسم المستعار والمالك</string>
<string name="cabinet_game_data_eraser">ممحاة بيانات اللعبة</string>
<string name="copied_to_clipboard">نسخ إلى الحافظة</string>
<string name="about_app_description">محاكي سويتش مفتوح المصدر</string>
<string name="contributors">المساهمين</string>
<string name="contributors_description">مصنوع من فريق يوزو</string>
<string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string>
<string name="licenses_description">المشاريع التي تجعل تطبيق يوزو لنظام أندرويد ممكنًا</string>
<string name="build">البناء</string>
<string name="user_data">بيانات المستخدم</string>
<string name="exporting_user_data">جارٍ تصدير بيانات المستخدم</string>
<string name="importing_user_data">جارٍ استيراد بيانات المستخدم</string>
<string name="user_data_description">استيراد/تصدير جميع بيانات التطبيق. عند استيراد بيانات المستخدم، سيتم حذف جميع بيانات المستخدم الحالية!</string>
<string name="exporting_user_data">جاري تصدير بيانات المستخدم</string>
<string name="importing_user_data">جاري استيراد بيانات المستخدم</string>
<string name="import_user_data">استيراد بيانات المستخدم</string>
<string name="invalid_yuzu_backup">نسخة احتياطية يوزو غير صالحة</string>
<string name="user_data_export_success">تم تصدير بيانات المستخدم بنجاح</string>
@ -153,7 +182,7 @@
<string name="use_docked_mode">وضع الإرساء</string>
<string name="use_docked_mode_description">زيادة الدقة، وانخفاض الأداء. يتم استخدام الوضع المحمول عند تعطيله، مما يؤدي إلى خفض الدقة وزيادة الأداء.</string>
<string name="emulated_region">المنطقة التي تمت محاكاتها</string>
<string name="emulated_language">لغة المحاكاه</string>
<string name="emulated_language">لغة المحاكاة</string>
<string name="select_rtc_date">حدد التاريخ و الساعة في الوقت الحقيقي</string>
<string name="select_rtc_time">حدد وقت الساعة في الوقت الفعلي</string>
<string name="use_custom_rtc">ساعة مخصصة في الوقت الحقيقي</string>
@ -164,7 +193,7 @@
<string name="renderer_accuracy">مستوى الدقة</string>
<string name="renderer_resolution">(Handheld/Docked) الدقة</string>
<string name="renderer_vsync">VSync وضع</string>
<string name="renderer_screen_layout">الاتجاه</string>
<string name="renderer_screen_layout">اتجاه العرض</string>
<string name="renderer_aspect_ratio">تناسب الابعاد</string>
<string name="renderer_anti_aliasing">طريقة مكافحة التعرج</string>
<string name="renderer_asynchronous_shaders">استخدم تظليل غير متزامن</string>
@ -172,31 +201,32 @@
<string name="renderer_reactive_flushing">استخدم التنظيف التفاعلي</string>
<string name="renderer_reactive_flushing_description">تحسين دقة العرض في بعض الألعاب على حساب الأداء</string>
<string name="use_disk_shader_cache_description">يقلل من التأتأة عن طريق تخزين وتحميل التظليلات التي تم إنشاؤها محليًا.</string>
<!-- Debug settings strings -->
<string name="cpu">وحدة المعالج المركزية</string>
<string name="cpu_debug_mode">تصحيح أخطاء وحدة المعالجة المركزية</string>
<string name="cpu_debug_mode_description">يضع وحدة المعالجة المركزية في وضع التصحيح البطيء.</string>
<string name="gpu">GPU</string>
<string name="renderer_api">API</string>
<string name="gpu">وحدة معالجة الرسومات</string>
<string name="renderer_api">واجهة برمجة التطبيقات</string>
<string name="renderer_debug">تصحيح الأخطاء الرسومية</string>
<string name="renderer_debug_description">يضبط واجهة برمجة تطبيقات الرسومات على وضع تصحيح الأخطاء البطيء.</string>
<string name="fastmem">Fastmem</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">محرك الإخراج</string>
<string name="audio_volume">حجم</string>
<string name="audio_volume_description">يحدد حجم إخراج الصوت</string>
<string name="audio_volume">مستوى الصوت</string>
<string name="audio_volume_description">يحدد مستوى إخراج الصوت</string>
<!-- Miscellaneous -->
<string name="slider_default">افتراضي</string>
<string name="ini_saved">الإعدادات المحفوظة</string>
<string name="gameid_saved">الإعدادات المحفوظة لـ %1$s</string>
<string name="error_saving">خطأ في حفظ %1$s.ini: %2$s</string>
<string name="unimplemented_menu">القائمة غير المنفذة</string>
<string name="loading">جاري تحميل</string>
<string name="shutting_down">إيقاف تشغيل</string>
<string name="loading">جاري التحميل</string>
<string name="shutting_down">إيقاف التشغيل</string>
<string name="reset_setting_confirmation">هل تريد إعادة تعيين هذا الإعداد مرة أخرى إلى قيمته الافتراضية؟</string>
<string name="reset_to_default">إعادة تعيين إلى الافتراضي</string>
<string name="reset_to_default">إعادة التعيين إلى الوضع الافتراضي</string>
<string name="reset_to_default_description">إعادة تعيين جميع الإعدادات المتقدمة</string>
<string name="reset_all_settings">إعادة تعيين جميع الإعدادات؟</string>
<string name="reset_all_settings_description">سيتم إعادة تعيين كافة الإعدادات المتقدمة إلى تكوينها الافتراضي. هذا لا يمكن التراجع عنها.</string>
<string name="settings_reset">إعادة تعيين الأعدادات</string>
@ -204,32 +234,77 @@
<string name="learn_more">معرفة المزيد</string>
<string name="auto">تلقائي</string>
<string name="submit">إرسال</string>
<string name="string_null">قيمه خاليه</string>
<string name="string_null">لا شيء</string>
<string name="string_import">استيراد</string>
<string name="export">تصدير</string>
<string name="export_failed">فشل التصدير</string>
<string name="import_failed">فشل الاستيراد</string>
<string name="cancelling">إلغاء</string>
<string name="install">تثبيت</string>
<string name="delete">حذف</string>
<string name="edit">حرر</string>
<string name="export_success">تم التصدير بنجاح</string>
<string name="start">Start</string>
<string name="clear">مسح</string>
<string name="global">عالمي</string>
<string name="custom">مخصص</string>
<string name="notice">إشعار</string>
<string name="import_complete">اكتمل الاستيراد</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">GPU حدد برنامج تشغيل</string>
<string name="select_gpu_driver_title">الحالي الخاص بك؟ GPU هل ترغب في استبدال برنامج تشغيل</string>
<string name="select_gpu_driver_install">تثبيت</string>
<string name="select_gpu_driver_default">افتراضي</string>
<string name="select_gpu_driver_use_default">يستخدم تعريف معالج الرسوميات الافتراضي</string>
<string name="select_gpu_driver_error">تم تحديد برنامج تشغيل غير صالح ، باستخدام النظام الافتراضي</string>
<string name="system_gpu_driver">تعريف معالج الرسوميات الخاص بالنظام</string>
<string name="installing_driver">جارٍ تثبيت برنامج التشغيل…</string>
<string name="select_gpu_driver_use_default">يستخدم تعريف معالج الرسومات الافتراضي</string>
<string name="select_gpu_driver_error">تم تحديد برنامج تشغيل غير صالح</string>
<string name="driver_already_installed">برنامج التشغيل مثبت بالفعل</string>
<string name="system_gpu_driver">تعريف معالج الرسومات الخاص بالنظام</string>
<string name="installing_driver">جاري تثبيت برنامج التشغيل…</string>
<!-- Preferences Screen -->
<string name="preferences_settings">إعدادات</string>
<string name="preferences_general">عام</string>
<string name="preferences_system">النظام</string>
<string name="preferences_graphics">الرسوميات</string>
<string name="preferences_system_description">وضع الإرساء ،المنطقة ،اللغة</string>
<string name="preferences_graphics">الرسومات</string>
<string name="preferences_graphics_description">مستوى الدقة ،الدقة ،ذاكرة التخزين المؤقت للتظليل</string>
<string name="preferences_audio">الصوت</string>
<string name="preferences_audio_description">محرك الإخراج ، حجم الصوت</string>
<string name="preferences_theme">السمة واللون</string>
<string name="preferences_debug">تصحيح الأخطاء</string>
<!-- Game properties -->
<string name="info">معلومات</string>
<string name="info_description">معرف البرنامج، المطور، الإصدار</string>
<string name="per_game_settings">إعدادات كل لعبة</string>
<string name="per_game_settings_description">تحرير الإعدادات الخاصة بهذه اللعبة</string>
<string name="launch_options">تشغيل الإعدادات</string>
<string name="path">المسار</string>
<string name="program_id">معرف البرنامج</string>
<string name="developer">المطور</string>
<string name="version">إصدار</string>
<string name="copy_details">نسخ التفاصيل</string>
<string name="add_ons">الإضافات</string>
<string name="add_ons_description">DLCالتعديلات والتحديثات و</string>
<string name="clear_shader_cache">مسح ذاكرة التخزين المؤقت للتظليل</string>
<string name="clear_shader_cache_description">يزيل جميع التظليلات التي تم إنشاؤها أثناء لعب هذه اللعبة</string>
<string name="clear_shader_cache_warning_description">سوف تواجه المزيد من التأتأة مع تجديد ذاكرة التخزين المؤقت للتظليل</string>
<string name="cleared_shaders_successfully">تم مسح التظليل بنجاح</string>
<string name="addons_game">إضافات: %1$s</string>
<string name="save_data">حفظ البيانات</string>
<string name="save_data_description">إدارة حفظ البيانات الخاصة بهذه اللعبة</string>
<string name="delete_save_data">حذف حفظ البيانات</string>
<string name="delete_save_data_description">يزيل كافة البيانات المحفوظة الخاصة بهذه اللعبة</string>
<string name="delete_save_data_warning_description">يؤدي هذا إلى إزالة كافة البيانات المحفوظة لهذه اللعبة بشكل لا يمكن استرداده. هل أنت متأكد أنك تريد الاستمرار؟</string>
<string name="save_data_deleted_successfully">حفظ البيانات تم حذفها بنجاح</string>
<string name="select_content_type">نوع المحتوى</string>
<string name="updates_and_dlc">DLC التحديثات والمحتوى القابل للتنزيل </string>
<string name="mods_and_cheats">تعديل وغش</string>
<string name="addon_notice">إشعار إضافي مهم</string>
<string name="invalid_directory">مجلد غير صالح</string>
<string name="addon_installed_successfully">تم تثبيت الملحق بنجاح</string>
<string name="verifying_content">جاري التحقق من المحتوى</string>
<string name="content_install_notice">إشعار تثبيت المحتوى</string>
<string name="content_install_notice_description">المحتوى الذي حددته لا يتطابق مع هذه اللعبة.هل تريد التثبيت على أية حال؟</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">الخاص بك ROM تم تشفير</string>
<string name="loader_error_video_core">حدث خطأ أثناء تهيئة مركز الفيديو</string>
@ -238,24 +313,25 @@
<!-- Emulation Menu -->
<string name="emulation_exit">الخروج من المحاكاة</string>
<string name="emulation_done">منجز</string>
<string name="emulation_done">إنهاء</string>
<string name="emulation_fps_counter">عداد إطار/ثانية</string>
<string name="emulation_toggle_controls">تبديل عناصر التحكم</string>
<string name="emulation_toggle_controls">عناصر التحكم</string>
<string name="emulation_rel_stick_center">مركز العصا النسبي</string>
<string name="emulation_dpad_slide">مزلاق أزرار الاتجاهات</string>
<string name="emulation_dpad_slide">مزلاق الأسهم</string>
<string name="emulation_haptics">الاهتزازات الديناميكية</string>
<string name="emulation_show_overlay">عرض التراكب</string>
<string name="emulation_toggle_all">تبديل الكل</string>
<string name="emulation_toggle_all">الكل</string>
<string name="emulation_control_adjust">ضبط التراكب</string>
<string name="emulation_control_scale">حجم</string>
<string name="emulation_control_opacity">العتامه</string>
<string name="emulation_control_scale">الحجم</string>
<string name="emulation_control_opacity">الشفافية</string>
<string name="emulation_touch_overlay_reset">إعادة تعيين التراكب</string>
<string name="emulation_touch_overlay_edit">تحرير التراكب</string>
<string name="emulation_pause">إيقاف المحاكاة مؤقتًا</string>
<string name="emulation_unpause">إلغاء الإيقاف المؤقت للمضاهاة</string>
<string name="emulation_unpause">إلغاء الإيقاف المؤقت للمحاكاة</string>
<string name="emulation_input_overlay">خيارات التراكب</string>
<string name="touchscreen">شاشة اللمس</string>
<string name="load_settings">جارٍ تحميل الإعدادات</string>
<string name="load_settings">جاري تحميل الإعدادات</string>
<!-- Software keyboard -->
<string name="software_keyboard">لوحة المفاتيح البرمجية</string>
@ -282,6 +358,7 @@
<!-- Memory Sizes -->
<string name="memory_byte">Byte</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
@ -326,10 +403,9 @@
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_landscape">افقي</string>
<string name="screen_layout_portrait">عمودي</string>
<string name="screen_layout_auto">تلقائي</string>
<string name="screen_layout_landscape">أفقي</string>
<string name="screen_layout_portrait">عمودي</string>
<!-- Aspect Ratios -->
<string name="ratio_default">(16:9) افتراضي</string>
<string name="ratio_force_four_three">4:3 فرض</string>
@ -337,16 +413,20 @@
<string name="ratio_force_sixteen_ten">16:10 فرض</string>
<string name="ratio_stretch">تمتد إلى النافذة</string>
<!-- CPU Backend -->
<string name="cpu_backend_dynarmic">Dynarmic (بطيء)</string>
<string name="cpu_backend_nce">تنفيذ التعليمات البرمجية الأصلية (NCE)</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">دقه</string>
<string name="cpu_accuracy_unsafe">غير آمن</string>
<string name="cpu_accuracy_paranoid">Paranoid (Slow)</string>
<string name="cpu_accuracy_paranoid">Paranoid (بطيء)</string>
<!-- Gamepad Buttons -->
<string name="gamepad_d_pad">أزرار الاتجاهات</string>
<string name="gamepad_d_pad">الأسهم</string>
<string name="gamepad_left_stick">العصا اليسرى</string>
<string name="gamepad_right_stick">العصا اليمنى</string>
<string name="gamepad_home">شاشة الإستقبال</string>
<string name="gamepad_home">شاشة الرئيسية</string>
<string name="gamepad_screenshot">لقطة شاشة</string>
<!-- Disk shader cache -->
@ -362,11 +442,16 @@
<string name="change_theme_mode">تغيير وضع السمة</string>
<string name="theme_mode_follow_system">اتبع النظام</string>
<string name="theme_mode_light">فاتح</string>
<string name="theme_mode_dark">غامق</string>
<string name="theme_mode_dark">داكن</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">خلفيات سوداء</string>
<string name="use_black_backgrounds_description">عند استخدام المظهر الداكن، قم بتطبيق خلفيات سوداء.</string>

View File

@ -157,7 +157,6 @@
<string name="renderer_reactive_flushing_description">وردی ڕێندەرکردن لە هەندێک یاریدا باشتر دەکات لەسەر تێچووی کارایی.</string>
<string name="use_disk_shader_cache">بیرگەخێرای سێبەری دیسک</string>
<string name="use_disk_shader_cache_description">پچڕپچڕی کەمدەکاتەوە بە هەڵگرتن و بارکردنی سێبەری دروستکراو لە ناوخۆدا.</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="renderer_api">API گرافیک</string>
@ -183,13 +182,15 @@
<string name="submit">پێشکەشکردن</string>
<string name="string_import">هاوردەکردن</string>
<string name="export">هەناردەکردن</string>
<string name="install">دامەزراندن</string>
<string name="delete">سڕینەوە</string>
<string name="clear">سڕینەوە</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">هەڵبژاردنی وەگەڕخەری GPU</string>
<string name="select_gpu_driver_title">حەز دەکەیت وەگەڕخەری GPU ی ئێستات بگۆڕیت؟</string>
<string name="select_gpu_driver_install">دامەزراندن</string>
<string name="select_gpu_driver_default">بنەڕەت</string>
<string name="select_gpu_driver_use_default">بەکارهێنانی وەگەڕخەری GPU ی بنەڕەت</string>
<string name="select_gpu_driver_error">وەگەڕخەری نادروست هەڵبژێردرا، بە بەکارهێنانی بنەڕەتی سیستەم!</string>
<string name="system_gpu_driver">وەگەڕخەری GPU ی سیستەم</string>
<string name="installing_driver">دامەزراندنی وەگەڕخەر...</string>
@ -201,7 +202,8 @@
<string name="preferences_audio">دەنگ</string>
<string name="preferences_theme">ڕەنگ و ڕووکار</string>
<string name="preferences_debug">چاککردنەوە</string>
<string name="path">ڕێڕەو</string>
<string name="version">وەشان</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">ڕۆمەکەت کۆدکراوە</string>
<string name="loader_error_encrypted_keys_description"><![CDATA[تکایە دڵنیابەوە لەدامەزراوی <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> فایلەکەت بۆ ئەوەی بتوانرێت یارییەکان کۆد بکرێنەوە.]]></string>
@ -228,6 +230,7 @@
<string name="emulation_pause">وەستاندنی ئیمولەیشن</string>
<string name="emulation_unpause">لادانی وەستاندنی ئیمولەیشن</string>
<string name="emulation_input_overlay">هەڵبژاردەکانی داپۆشەر</string>
<string name="touchscreen">رووکاری لەمسی</string>
<string name="load_settings">بارکردنی ڕێکخستنەکان...</string>
@ -253,6 +256,7 @@
<string name="region_korea">کۆریا</string>
<string name="region_taiwan">تایوان</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_gigabyte">GB</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">ڤوڵکان</string>
@ -290,8 +294,8 @@
<string name="anti_aliasing_fxaa">FXAA</string>
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_auto">خودکار</string>
<!-- Aspect Ratios -->
<string name="ratio_default">بنەڕەت (16:9)</string>
<string name="ratio_force_four_three">ڕووبەری 4:3</string>
@ -326,6 +330,12 @@
<string name="theme_mode_light">ڕوناکی</string>
<string name="theme_mode_dark">تاریک</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">پاشبنەمای ڕەش</string>
<string name="use_black_backgrounds_description">لە کاتی بەکارهێنانی ڕووکاری تاریکدا، پاشبنەمای ڕەش دادەنێ.</string>

View File

@ -0,0 +1,265 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="emulation_notification_channel_name">Emulace je aktivní</string>
<string name="notice_notification_channel_name">Upozornění a chyby</string>
<string name="notice_notification_channel_description">Ukáže oznámení v případě chyby.</string>
<string name="notification_permission_not_granted">Oznámení nejsou oprávněna!</string>
<!-- Setup strings -->
<string name="welcome">Vítejte!</string>
<string name="get_started">Začít</string>
<string name="keys">Klíče</string>
<string name="select_keys">Vybrat klíče</string>
<string name="games">Hry</string>
<string name="done">Hotovo</string>
<string name="done_description">Vše je připraveno.\nUžijte si vaše hry!</string>
<string name="text_continue">Pokračovat</string>
<string name="next">Další</string>
<string name="back">Zpět</string>
<string name="add_games">Přidat hry</string>
<string name="add_games_description">Vyber svoji složku se hrami</string>
<!-- Home strings -->
<string name="home_games">Hry</string>
<string name="home_search">Hledat</string>
<string name="home_settings">Nastavení</string>
<string name="empty_gamelist">Nebyly nalezeny žádné soubory nebo ještě nebyl vybrán žádný adresář s hrami.</string>
<string name="search_and_filter_games">Hledat a filtrovat hry</string>
<string name="select_games_folder">Vybrat složku s hrami</string>
<string name="manage_game_folders">Spravovat složky s hrami</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
<string name="install_prod_keys">Instalovat prod.keys</string>
<string name="install_prod_keys_warning">Přeskočit přidávání klíčů?</string>
<string name="install_prod_keys_warning_help">https://yuzu-emu.org/help/quickstart/#guide-introduction</string>
<string name="notifications">Oznámení</string>
<string name="give_permission">Udělit oprávnění</string>
<string name="notification_warning">Přeskočit udělení oprávnění k oznámení?</string>
<string name="notification_warning_description">yuzu vám nebude schopno oznámit důležité informace.</string>
<string name="permission_denied">Oprávnění zamítnuto</string>
<string name="permission_denied_description">Zamítnul jste toto oprávnění příliš mnohokrát, musíte manuálně udělit oprávnění v nastavení systému.</string>
<string name="about">O aplikaci</string>
<string name="about_description">Verze sestavení, titulky a více</string>
<string name="warning_help">Pomoc</string>
<string name="warning_skip">Přeskočit</string>
<string name="warning_cancel">Zrušit</string>
<string name="install_amiibo_keys">Instalovat Amiibo klíče</string>
<string name="install_amiibo_keys_description">Povinné použití Amiibo ve hře</string>
<string name="invalid_keys_file">Vybrané klíče jsou neplatné</string>
<string name="install_keys_success">Klíče úspěšně nainstalovány</string>
<string name="reading_keys_failure">Chyba při čtení šifrovacích klíčů</string>
<string name="invalid_keys_error">Neplatné šifrovací klíče</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="gpu_driver_manager">Správce ovladače GPU</string>
<string name="install_gpu_driver">Instalovat GPU ovladač</string>
<string name="advanced_settings">Pokročilé nastavení</string>
<string name="settings_description">Konfigurovat nastavení emulátoru</string>
<string name="search_recently_played">Nedávno hrané</string>
<string name="search_recently_added">Nedávno přidané</string>
<string name="search_homebrew">Homebrew</string>
<string name="open_user_folder">Otevřít yuzu složku</string>
<string name="open_user_folder_description">Spravovat soubory yuzu</string>
<string name="no_file_manager">Nenalezen žádný správce souborů</string>
<string name="notification_no_directory_link">Nepovedlo se otevřít yuzu složku</string>
<string name="manage_save_data">Spravovat data postupu ve hře</string>
<string name="manage_save_data_description">Data postupu nalezeny. Prosím vyberte možnost.</string>
<string name="import_export_saves_description">Importovat nebo exportovat data postupu</string>
<string name="save_file_imported_success">Uspěšně importováno</string>
<string name="save_file_invalid_zip_structure">Neplatná struktura dat postupu</string>
<string name="import_saves">Importovat</string>
<string name="export_saves">Exportovat</string>
<string name="install_firmware">Nainstalovat firmware</string>
<string name="firmware_installing">Instalování firmwaru</string>
<string name="firmware_installed_success">Firmware byl úspěšně nainstalován</string>
<string name="firmware_installed_failure">Instalace firmwaru selhala</string>
<string name="install_game_content">Nainstalovat obsah hry</string>
<string name="install_game_content_description">Nainstalovat aktualizace hry nebo DLC</string>
<string name="installing_game_content">Instalování obsahu...</string>
<string name="install_game_content_failure">Chyba při instalaci soubor(ů) do NAND</string>
<string name="manage_yuzu_data">Spravovat data yuzu</string>
<string name="game_folders">Složky s hrami</string>
<string name="folder_already_added">Tato složka byla již přidána!</string>
<string name="game_folder_properties">Vlastnosti složky s hrami</string>
<string name="album_applet_description">Zobrazovat obrázky uložené v uživatelské složce se snímky obrazovky pomocí systémového prohlížeče fotografií</string>
<string name="cabinet_nickname_and_owner">Nastavení přezdívky a vlastníka</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia není skutečná</string>
<string name="copied_to_clipboard">Zkopírováno do schránky</string>
<string name="about_app_description">Open-source Switch emulátor</string>
<string name="contributors">Přispěvatelé</string>
<string name="contributors_description">Vyrobeno s \u2764 od yuzu týmu</string>
<string name="contributors_link">https://github.com/yuzu-emu/yuzu/graphs/contributors</string>
<string name="build">Číslo sestavení</string>
<string name="user_data">Uživatelská data</string>
<string name="exporting_user_data">Exportování uživatelských dat...</string>
<string name="importing_user_data">Importování uživatelských dat...</string>
<string name="import_user_data">Importovat uživatelská data</string>
<string name="invalid_yuzu_backup">Neplatná záloha yuzu</string>
<string name="user_data_export_success">Uživatelská data byla úspěšně exportována.</string>
<string name="user_data_import_success">Uživatelská data byla úspěšně importována.</string>
<string name="user_data_export_cancelled">Export zrušen</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://yuzu-emu.org/</string>
<string name="github_link">https://github.com/yuzu-emu</string>
<string name="play_store_link">https://play.google.com/store/apps/details?id=org.yuzu.yuzu_emu.ea</string>
<string name="no_manual_installation">Žádná manuální instalace</string>
<string name="prioritized_support">Prioritní podpora</string>
<string name="our_eternal_gratitude">Naše věčná vděčnost</string>
<string name="are_you_interested">Máte zájem?</string>
<!-- General settings strings -->
<string name="frame_limit_enable">Omezit rychlost</string>
<string name="cpu_accuracy">CPU přesnost</string>
<string name="emulated_region">Emulovaná oblast</string>
<string name="emulated_language">Emulovaný jazyk</string>
<string name="use_custom_rtc">Vlastní RTC</string>
<!-- Graphics settings strings -->
<string name="renderer_accuracy">Úroveň přesnosti</string>
<string name="renderer_vsync">VSync režim</string>
<string name="renderer_screen_layout">Orientace</string>
<string name="renderer_aspect_ratio">Poměr stran</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="renderer_api">API</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Výstupní engine</string>
<string name="audio_volume">Hlasitost</string>
<string name="audio_volume_description">Udává hlasitost zvukového výstupu.</string>
<!-- Miscellaneous -->
<string name="slider_default">Výchozí</string>
<string name="ini_saved">Nastavení uložena</string>
<string name="gameid_saved">Uložena nastavení pro %1$s</string>
<string name="loading">Načítání...</string>
<string name="shutting_down">Vypínání...</string>
<string name="reset_setting_confirmation">Chcete obnovit toto nastavení zpět na jeho výchozí hodnotu?</string>
<string name="reset_to_default">Navrátit k výchozímu</string>
<string name="reset_all_settings">Resetovat všechna nastavení?</string>
<string name="reset_all_settings_description">Všechna pokročilá nastavení budou obnovena na jejich výchozí konfiguraci. Toto nelze vrátit zpět.</string>
<string name="close">Zavřít</string>
<string name="learn_more">Zjistit více</string>
<string name="auto">Automatické</string>
<string name="string_import">Importovat</string>
<string name="export">Exportovat</string>
<string name="install">Nainstalovat</string>
<string name="delete">Smazat</string>
<string name="export_success">Úspěšně exportováno</string>
<string name="start">Start</string>
<string name="clear">Vymazat</string>
<string name="custom">Vlastní</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Vybrat GPU ovladač</string>
<string name="select_gpu_driver_title">Chcete nahradit váš aktuální ovladač GPU?</string>
<string name="select_gpu_driver_install">Nainstalovat</string>
<string name="select_gpu_driver_default">Výchozí</string>
<string name="select_gpu_driver_error">Vybrán neplatný ovladač</string>
<string name="driver_already_installed">Ovladač již nainstalován</string>
<string name="system_gpu_driver">Systémový ovladač GPU</string>
<string name="installing_driver">Instalování ovladače...</string>
<!-- Preferences Screen -->
<string name="preferences_settings">Nastavení</string>
<string name="preferences_general">Obecné</string>
<string name="preferences_system">Systém</string>
<string name="preferences_graphics">Grafika</string>
<string name="preferences_audio">Zvuk</string>
<string name="preferences_audio_description">Výstupní engine, hlasitost</string>
<string name="preferences_theme">Vzhled a barva</string>
<string name="preferences_debug">Ladění</string>
<!-- Game properties -->
<string name="info">Info</string>
<string name="path">Cesta</string>
<string name="developer">Vývojář</string>
<string name="version">Verze</string>
<string name="copy_details">Zkopírovat podrobnosti</string>
<string name="add_ons">Modifkace</string>
<string name="addons_game">Rozšíření: %1$s</string>
<string name="select_content_type">Typ obsahu</string>
<string name="updates_and_dlc">Aktualizace a DLC</string>
<string name="mods_and_cheats">Módy a cheaty</string>
<string name="addon_installed_successfully">Rozšíření úspěšně nainstalováno</string>
<string name="verifying_content">Ověřování obsahu...</string>
<string name="emulation_done">Hotovo</string>
<string name="emulation_control_scale">Měřítko</string>
<string name="emulation_control_opacity">Průhlednost</string>
<string name="touchscreen">Dotyková obrazovka</string>
<!-- Errors and warnings -->
<string name="abort_button">Přerušit</string>
<string name="continue_button">Pokračovat</string>
<string name="system_archive_not_found">Systémový Archív Nenalezen</string>
<string name="save_load_error">Ukládací/Načítací chyba</string>
<string name="fatal_error">Fatální Chyba</string>
<!-- Region Names -->
<string name="region_japan">Japonsko</string>
<string name="region_usa">USA</string>
<string name="region_europe">Evropa</string>
<string name="region_australia">Austrálie</string>
<string name="region_china">Čína</string>
<string name="region_korea">Korea</string>
<string name="region_taiwan">Taiwan</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_gigabyte">GB</string>
<!-- Renderer APIs -->
<string name="renderer_vulkan">Vulkan</string>
<string name="renderer_none">Žádné</string>
<!-- Renderer Accuracy -->
<string name="renderer_accuracy_normal">Normální</string>
<string name="renderer_accuracy_high">Vysoká</string>
<!-- Resolutions -->
<string name="resolution_half">0.5X (360p/540p)</string>
<string name="resolution_three_quarter">0.75X (540p/810p)</string>
<string name="resolution_one">1X (720p/1080p)</string>
<string name="resolution_two">2X (1440p/2160p) (Pomalé)</string>
<string name="resolution_three">3X (2160p/3240p) (Pomalé)</string>
<string name="resolution_four">4X (2880p/4320p) (Pomalé)</string>
<string name="scaling_filter_bilinear">Bilineární</string>
<string name="scaling_filter_fsr">AMD FidelityFX™ Super Resolution</string>
<!-- Anti-Aliasing -->
<string name="anti_aliasing_none">Žádné</string>
<string name="anti_aliasing_fxaa">FXAA</string>
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_auto">Automatické</string>
<!-- Aspect Ratios -->
<string name="ratio_default">Výchozí (16:9)</string>
<string name="ratio_force_four_three">Vynutit 4:3</string>
<string name="ratio_force_twenty_one_nine">Vynutit 21:9</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">Přesné</string>
<string name="cpu_accuracy_unsafe">Nebezpečné</string>
<string name="gamepad_home">Home</string>
<string name="building_shaders">Budování shaderů</string>
<!-- Theme options -->
<string name="change_app_theme">Změnit vzhled aplikace</string>
<string name="theme_default">Výchozí</string>
<string name="theme_material_you">Material You</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Změnit styl vzhledu</string>
<string name="theme_mode_follow_system">Podle systému</string>
<string name="theme_mode_light">Světlé</string>
<string name="theme_mode_dark">Tmavé</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Černá pozadí</string>
<!-- Picture-In-Picture -->
<string name="picture_in_picture">Obraz v obraze</string>
<string name="mute">Ztlumit</string>
<string name="unmute">Vypnout ztlumení</string>
<!-- Licenses screen strings -->
<string name="licenses">Licence</string>
</resources>

View File

@ -34,6 +34,7 @@
<string name="empty_gamelist">Es wurden keine Dateien gefunden oder es wurde noch kein Spielverzeichnis ausgewählt.</string>
<string name="search_and_filter_games">Spiele suchen und filtern</string>
<string name="select_games_folder">Spieleverzeichnis auswählen</string>
<string name="manage_game_folders">Spiele-Ordner verwalten</string>
<string name="select_games_folder_description">Erlaubt yuzu die Spieleliste zu füllen</string>
<string name="add_games_warning">Auswahl des Spieleverzeichnisses überspringen?</string>
<string name="add_games_warning_description">Spiele werden in der Spieleliste nicht angezeigt, wenn kein Ordner ausgewählt ist.</string>
@ -67,9 +68,11 @@
<string name="invalid_keys_error">Ungültige Schlüssel</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">Die ausgewählte Datei ist falsch oder beschädigt. Bitte kopieren Sie Ihre Schlüssel erneut.</string>
<string name="gpu_driver_manager">GPU-Treiber Verwaltung</string>
<string name="install_gpu_driver">GPU-Treiber installieren</string>
<string name="install_gpu_driver_description">Alternative Treiber für eventuell bessere Leistung oder Genauigkeit installieren</string>
<string name="advanced_settings">Erweiterte Einstellungen</string>
<string name="advanced_settings_game">Erweiterte Einstellungen: %1$s</string>
<string name="settings_description">Emulatoreinstellungen konfigurieren</string>
<string name="search_recently_played">Kürzlich gespielt</string>
<string name="search_recently_added">Kürzlich hinzugefügt</string>
@ -83,7 +86,11 @@
<string name="notification_no_directory_link_description">Bitte suche den Benutzerordner manuell über die Seitenleiste des Dateimanagers.</string>
<string name="manage_save_data">Speicherdaten verwalten</string>
<string name="manage_save_data_description">Speicherdaten gefunden. Bitte wähle unten eine Option aus.</string>
<string name="import_save_warning">Speicherdaten importieren</string>
<string name="import_save_warning_description">Das überschreibt alle existierenden Speicherdaten für dieses Spiel mit der ausgewählten Datei. Wirklich fortfahren?</string>
<string name="import_export_saves_description">Speicherdaten importieren oder exportieren</string>
<string name="save_files_importing">Importiere Speicherdaten...</string>
<string name="save_files_exporting">Exportiere Speicherdaten...</string>
<string name="save_file_imported_success">Erfolgreich importiert</string>
<string name="save_file_invalid_zip_structure">Ungültige Speicherverzeichnisstruktur</string>
<string name="save_file_invalid_zip_structure_description">Der erste Unterordnername muss die Titel-ID des Spiels sein.</string>
@ -98,8 +105,17 @@
<string name="share_log_description">Debug-Logs an yuzu zur Untersuchung absenden</string>
<string name="share_log_missing">Keine Log-Datei gefunden</string>
<string name="install_game_content">Spiel installieren</string>
<string name="install_game_content_description">Spiel Update oder DLC installieren</string>
<string name="install_game_content_description">Spiel-Updates oder DLCs installieren</string>
<string name="installing_game_content">Installiere...</string>
<string name="install_game_content_failed_count">%1$d Installationsfehler</string>
<string name="install_game_content_success_install">%1$d erfolgreich installiert</string>
<string name="install_game_content_success_overwrite">%1$d erfolgreich überschrieben</string>
<string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
<string name="manage_yuzu_data">yuzu-Daten Verwalten</string>
<string name="share_save_file">Speicherdaten teilen</string>
<string name="game_folders">Spiele-Ordner</string>
<string name="add_game_folder">Spiele-Ordner hinzufügen</string>
<string name="applets_error_firmware">Firmware nicht installiert</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia ist nicht real</string>
<string name="copied_to_clipboard">In die Zwischenablage kopiert</string>
@ -110,6 +126,10 @@
<string name="licenses_description">Projekte, die yuzu für Android möglich machen </string>
<string name="build">Build</string>
<string name="user_data">Nutzerdaten</string>
<string name="importing_user_data">Importiere Nutzerdaten...</string>
<string name="import_user_data">Nutzerdaten importieren</string>
<string name="user_data_export_success">Nutzerdaten erfolgreich exportiert</string>
<string name="user_data_import_success">Nutzerdaten erfolgreich importiert</string>
<string name="user_data_export_cancelled">Export abgebrochen</string>
<string name="support_link">https://discord.gg/u77vRWY</string>
<string name="website_link">https://yuzu-emu.org/</string>
@ -137,7 +157,7 @@
<string name="cpu_accuracy">CPU-Genauigkeit</string>
<!-- System settings strings -->
<string name="use_docked_mode">Gedockter Modus</string>
<string name="use_docked_mode_description">Der Docked Modus erhöht die Auflösung, verringert die aber die Leistung. Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die Leistung.</string>
<string name="use_docked_mode_description">Der Gedockte-Modus erhöht die Auflösung, verringert aber die Leistung. Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die Leistung.</string>
<string name="emulated_region">Emulierte Region</string>
<string name="emulated_language">Emulierte Sprache</string>
<string name="select_rtc_date">RTC-Datum auswählen</string>
@ -145,10 +165,12 @@
<string name="use_custom_rtc">Benutzerdefinierte Echtzeituhr</string>
<!-- Graphics settings strings -->
<string name="renderer_accuracy">Genauigkeitsstufe</string>
<string name="renderer_resolution">Auflösung (Mobil/Gedockt)</string>
<string name="renderer_vsync">VSync-Modus</string>
<string name="renderer_screen_layout">Orientierung</string>
<string name="renderer_aspect_ratio">Seitenverhältnis</string>
<string name="renderer_scaling_filter">Fensteranpassungsfilter</string>
<string name="renderer_anti_aliasing">Kantenglättung</string>
<string name="renderer_force_max_clock">Maximale Taktfrequenz erzwingen (nur Adreno)</string>
<string name="renderer_force_max_clock_description">Erzwingt den Betrieb der GPU mit der maximal möglichen Taktfrequenz (Temperaturbeschränkungen werden weiterhin angewendet).</string>
<string name="renderer_asynchronous_shaders">Asynchrone Shader nutzen</string>
@ -168,9 +190,12 @@
<string name="error_saving">Fehler beim Speichern von %1$s.ini: %2$s</string>
<string name="unimplemented_menu">Unimplementiertes Menü</string>
<string name="loading">Lädt...</string>
<string name="shutting_down">Beendet...</string>
<string name="reset_setting_confirmation">Möchtest du diese Einstellung auf den Standardwert zurücksetzen?</string>
<string name="reset_to_default">Auf Standard zurücksetzen</string>
<string name="reset_to_default_description">Setzt alle erweiterten Einstellungen zurück</string>
<string name="reset_all_settings">Alle Einstellungen zurücksetzen?</string>
<string name="reset_all_settings_description">Alle erweiterten Einstellungen werden auf ihren Standardwert zurückgesetzt. Dies kann nicht rückgängig gemacht werden.</string>
<string name="settings_reset">Einstellungen zurückgesetzt</string>
<string name="close">Schließen</string>
<string name="learn_more">Mehr erfahren</string>
@ -182,14 +207,20 @@
<string name="export_failed">Export fehlgeschlagen</string>
<string name="import_failed">Import fehlgeschlagen</string>
<string name="cancelling">Abbrechen</string>
<string name="install">Installieren</string>
<string name="delete">Löschen</string>
<string name="edit">Bearbeiten</string>
<string name="export_success">Erfolgreich exportiert</string>
<string name="start">Start</string>
<string name="clear">Löschen</string>
<string name="custom">Benutzerdefiniert</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">GPU-Treiber auswählen</string>
<string name="select_gpu_driver_title">Möchtest du deinen aktuellen GPU-Treiber ersetzen?</string>
<string name="select_gpu_driver_install">Installieren</string>
<string name="select_gpu_driver_default">Standard</string>
<string name="select_gpu_driver_use_default">Standard GPU-Treiber wird verwendet</string>
<string name="select_gpu_driver_error">Ungültiger Treiber ausgewählt, Standard-Treiber wird verwendet!</string>
<string name="driver_already_installed">Treiber bereits installiert</string>
<string name="system_gpu_driver">System GPU-Treiber</string>
<string name="installing_driver">Treiber wird installiert...</string>
@ -197,11 +228,37 @@
<string name="preferences_settings">Einstellungen</string>
<string name="preferences_general">Allgemein</string>
<string name="preferences_system">System</string>
<string name="preferences_system_description">Gedockter Modus, Region, Sprache</string>
<string name="preferences_graphics">Grafik</string>
<string name="preferences_graphics_description">Genauigkeitsstufe, Auflösung, Shader-Cache</string>
<string name="preferences_audio">Audio</string>
<string name="preferences_audio_description">Ausgabe-Engine, Lautstärke</string>
<string name="preferences_theme">Theme und Farbe</string>
<string name="preferences_debug">Debug</string>
<!-- Game properties -->
<string name="info">Info</string>
<string name="info_description">Programm-ID, Entwickler, Version</string>
<string name="per_game_settings">Spieleinstellungen</string>
<string name="per_game_settings_description">Einstellungen für dieses Spiel ändern</string>
<string name="path">Pfad</string>
<string name="program_id">Programm-ID</string>
<string name="developer">Entwickler</string>
<string name="version">Version</string>
<string name="copy_details">Details kopieren</string>
<string name="add_ons">Add-ons</string>
<string name="add_ons_description">Mods, Updates und DLC aktivieren oder deaktivieren</string>
<string name="clear_shader_cache">Shader-Cache löschen</string>
<string name="clear_shader_cache_description">Löscht alle für dieses Spiel erstellten Shader</string>
<string name="cleared_shaders_successfully">Shader erfolgreich gelöscht</string>
<string name="addons_game">Add-ons: %1$s</string>
<string name="save_data">Speicherdaten</string>
<string name="save_data_description">Importiert oder exportiert Speicherdaten für dieses Spiel</string>
<string name="delete_save_data">Speicherdaten löschen</string>
<string name="delete_save_data_description">Löscht alle Speicherdaten für dieses Spiel</string>
<string name="delete_save_data_warning_description">Das löscht unwiederbringlich alle Speicherdaten für dieses Spiel. Wirklich fortfahren?</string>
<string name="save_data_deleted_successfully">Speicherdaten erfolgreich gelöscht</string>
<string name="invalid_directory">Ungültiges Verzeichnis</string>
<string name="addon_installed_successfully">Add-on erfolgreich installiert</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">Das ROM ist verschlüsselt</string>
<string name="loader_error_encrypted_keys_description"><![CDATA[Bitte stelle sicher dass die <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> Datei installiert ist, damit Spiele entschlüsselt werden können.]]></string>
@ -220,7 +277,10 @@
<string name="emulation_control_opacity">Transparenz</string>
<string name="emulation_touch_overlay_reset">Overlay zurücksetzen</string>
<string name="emulation_touch_overlay_edit">Overlay bearbeiten</string>
<string name="emulation_pause">Emulation pausieren</string>
<string name="emulation_unpause">Emulation fortsetzen</string>
<string name="emulation_input_overlay">Overlay-Optionen</string>
<string name="touchscreen">Touchscreen</string>
<string name="load_settings">Lade Einstellungen...</string>
@ -248,6 +308,7 @@
<!-- Memory Sizes -->
<string name="memory_byte">Byte</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
@ -291,9 +352,10 @@
<string name="anti_aliasing_fxaa">FXAA</string>
<string name="anti_aliasing_smaa">SMAA</string>
<string name="screen_layout_portrait">Portrait</string>
<!-- Screen Layouts -->
<string name="screen_layout_auto">Auto</string>
<string name="screen_layout_landscape">Horizontal</string>
<string name="screen_layout_portrait">Vertikal</string>
<!-- Aspect Ratios -->
<string name="ratio_default">Standard (16:9)</string>
<string name="ratio_force_four_three">4:3 erzwingen</string>
@ -318,22 +380,27 @@
<string name="building_shaders">Shader werden erstellt</string>
<!-- Theme options -->
<string name="change_app_theme">App-Thema ändern</string>
<string name="change_app_theme">Theme</string>
<string name="theme_default">Standard</string>
<string name="theme_material_you">Material You</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Themen-Modus ändern</string>
<string name="change_theme_mode">Design</string>
<string name="theme_mode_follow_system">System folgen</string>
<string name="theme_mode_light">Hell</string>
<string name="theme_mode_dark">Dunkel</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Schwarze Hintergründe</string>
<string name="use_black_backgrounds_description">Bei Verwendung des dunklen Themes, schwarze Hintergründe verwenden.</string>
<string name="use_black_backgrounds_description">Bei Verwendung des dunklen Designs, schwarze Hintergründe verwenden.</string>
<!-- Picture-In-Picture -->
<string name="picture_in_picture">Bild im Bild</string>

View File

@ -4,7 +4,7 @@
<string name="app_disclaimer">Este software ejecuta juegos para la videoconsola Nintendo Switch. Los videojuegos o claves no vienen incluidos.&lt;br /&gt;&lt;br /&gt;Antes de empezar, por favor, localice el archivo <![CDATA[<b> prod.keys </b>]]>en el almacenamiento de su dispositivo..&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Saber más</a>]]></string>
<string name="emulation_notification_channel_name">Emulación activa</string>
<string name="emulation_notification_channel_description">Muestra una notificación persistente cuando la emulación está activa.</string>
<string name="emulation_notification_running">yuzu esta ejecutándose</string>
<string name="emulation_notification_running">yuzu está ejecutándose</string>
<string name="notice_notification_channel_name">Avisos y errores</string>
<string name="notice_notification_channel_description">Mostrar notificaciones cuándo algo vaya mal.</string>
<string name="notification_permission_not_granted">¡Permisos de notificación no concedidos!</string>
@ -34,6 +34,7 @@
<string name="empty_gamelist">No se ha encontrado ningún archivo o aún no se ha seleccionado ningún directorio de juegos.</string>
<string name="search_and_filter_games">Busca y filtra juegos</string>
<string name="select_games_folder">Seleccionar carpeta de juegos</string>
<string name="manage_game_folders">Gestionar carpetas de juegos</string>
<string name="select_games_folder_description">Permite que yuzu llene la lista de juegos</string>
<string name="add_games_warning">¿Omitir la selección de la carpeta de juegos?</string>
<string name="add_games_warning_description">No se mostrará ningún juego si no se ha seleccionado una carpeta de juegos.</string>
@ -44,23 +45,23 @@
<string name="install_prod_keys">Instalar prod.keys</string>
<string name="install_prod_keys_description">Requerido para descifrar juegos</string>
<string name="install_prod_keys_warning">¿Omitir agregar claves?</string>
<string name="install_prod_keys_warning_description">Se requieren claves válidas para emular juegos. Solo las aplicaciones homebrew funcionarán si continúas.</string>
<string name="install_prod_keys_warning_description">Se requieren claves válidas para emular juegos. Solo las aplicaciones homebrew funcionarán si continúas.</string>
<string name="install_prod_keys_warning_help">https://yuzu-emu.org/help/quickstart/#guide-introduction</string>
<string name="notifications">Notificaciones</string>
<string name="notifications_description">Otorgue el permiso de notificación con el botón de abajo.</string>
<string name="notifications_description">Otorga el permiso de notificación con el botón de abajo.</string>
<string name="give_permission">Conceder permiso</string>
<string name="notification_warning">¿Omitir conceder el permiso de notificación?</string>
<string name="notification_warning_description">yuzu no podrá notificarte información importante.</string>
<string name="permission_denied">Permiso denegado</string>
<string name="permission_denied_description">Negó este permiso demasiadas veces y ahora debe otorgarlo manualmente en la configuración del sistema.</string>
<string name="permission_denied_description">Se ha denegado este permiso demasiadas veces y ahora debes otorgarlo de forma manual en la configuración del sistema.</string>
<string name="about">Acerca de</string>
<string name="about_description">Versión, créditos y más</string>
<string name="warning_help">Ayuda</string>
<string name="warning_skip">Siguiente</string>
<string name="warning_cancel">Cancelar</string>
<string name="install_amiibo_keys">Instalar clave de Amiiboo</string>
<string name="install_amiibo_keys_description">Necesario para usar Amiibo en el juego</string>
<string name="invalid_keys_file">Archivo de claves seleccionado inválido</string>
<string name="install_amiibo_keys">Instalar claves de Amiibo</string>
<string name="install_amiibo_keys_description">Necesario para usar Amiibos en el juego</string>
<string name="invalid_keys_file">Archivo de claves seleccionado no válido</string>
<string name="install_keys_success">Claves instaladas correctamente</string>
<string name="reading_keys_failure">Error al leer las claves de cifrado</string>
<string name="install_prod_keys_failure_extension_description">Compruebe que el archivo de claves tenga una extensión .keys y pruebe otra vez.</string>
@ -68,6 +69,7 @@
<string name="invalid_keys_error">Claves de cifrado no válidas</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">El archivo seleccionado es incorrecto o está corrupto. Vuelva a redumpear sus claves.</string>
<string name="gpu_driver_manager">Explorador de drivers de GPU</string>
<string name="install_gpu_driver">Instalar driver de GPU</string>
<string name="install_gpu_driver_description">Instale drivers alternativos para obtener un rendimiento o una precisión potencialmente mejores</string>
<string name="advanced_settings">Opciones avanzadas</string>
@ -85,7 +87,11 @@
<string name="notification_no_directory_link_description">Por favor, busque la carpeta user con el panel lateral del explorador de archivos de forma manual.</string>
<string name="manage_save_data">Administrar datos de guardado</string>
<string name="manage_save_data_description">Guardar los datos encontrados. Por favor, seleccione una opción de abajo.</string>
<string name="import_save_warning">Importar datos de guardado</string>
<string name="import_save_warning_description">Ésto sobreescribirá todos los datos de guardado existentes con el archivo proporcionado. ¿Está seguro de querer continuar?</string>
<string name="import_export_saves_description">Importar o exportar archivos de guardado</string>
<string name="save_files_importing">Importando archivos de guardado...</string>
<string name="save_files_exporting">Exportando archivos de guardado...</string>
<string name="save_file_imported_success">Importado correctamente</string>
<string name="save_file_invalid_zip_structure">Estructura del directorio de guardado no válido</string>
<string name="save_file_invalid_zip_structure_description">El nombre de la primera subcarpeta debe ser el Title ID del juego.</string>
@ -95,7 +101,7 @@
<string name="install_firmware_description">El firmware debe estar en un archivo ZIP y es necesario para ejecutar algunos juegos</string>
<string name="firmware_installing">Instalando firmware</string>
<string name="firmware_installed_success">Firmware instalado con éxito</string>
<string name="firmware_installed_failure">Falló la instalación de firmware</string>
<string name="firmware_installed_failure">Error en la instalación de firmware</string>
<string name="firmware_installed_failure_description">Asegúrese de que los archivos nca del firmware estén en la raíz del zip e inténtelo de nuevo.</string>
<string name="share_log">Compartir registros de depuración</string>
<string name="share_log_description">Comparta el archivo de registro de yuzu para depurar problemas</string>
@ -115,9 +121,43 @@
<string name="custom_driver_not_supported">Drivers personalizados no soportados</string>
<string name="custom_driver_not_supported_description">En estos momentos, la carga de drivers personalizados no está disponible para este dispositivo..\n¡Comprueba esta opción en el futuro para ver si ya está añadido el soporte a ese dispositivo!</string>
<string name="manage_yuzu_data">Administrar datos de yuzu</string>
<string name="manage_yuzu_data_description">Importa/exporta el firmware, las keys, los datos de usuario, ¡y más!</string>
<string name="manage_yuzu_data_description">Importa/exporta el firmware, las claves, los datos de usuario, ¡y más!</string>
<string name="share_save_file">Compartir archivo de guardado</string>
<string name="export_save_failed">La exportación del guardado falló</string>
<string name="export_save_failed">Error al exportar el archivo de guardado</string>
<string name="game_folders">Carpetas de juegos</string>
<string name="deep_scan">Escaneo recursivo </string>
<string name="add_game_folder">Añadir carpeta con juegos</string>
<string name="folder_already_added">¡Está carpeta ya se había añadido!</string>
<string name="game_folder_properties">Propiedades de la carpeta de juegos</string>
<plurals name="saves_import_failed">
<item quantity="one">No se ha podido importar %d archivo de guardado.</item>
<item quantity="many">No se han podido importar %d archivos de guardado.</item>
<item quantity="other">No se han podido importar %d archivos de guardado.</item>
</plurals>
<plurals name="saves_import_success">
<item quantity="one">%d archivo de guardado importado con éxito.</item>
<item quantity="many">%d archivos de guardado importados con éxito.</item>
<item quantity="other">%d archivos de guardado importados con éxito.</item>
</plurals>
<string name="no_save_data_found">No hay archivos de guardado</string>
<!-- Applet launcher strings -->
<string name="applets">Ejecutador de applet</string>
<string name="applets_description">Ejecutar applets de sistema usando el firmware instalado</string>
<string name="applets_error_firmware">Firmware no instalado</string>
<string name="applets_error_applet">Applet no disponible</string>
<string name="applets_error_description"><![CDATA[Asegúrese de que el archivo<a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> y el <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-system-firmware\">firmware</a> estén instalados e inténtelo de nuevo.]]></string>
<string name="album_applet">Álbum</string>
<string name="album_applet_description">Ver las imágenes que están en la carpeta \"screenshots\" del usuario con el visor de fotos del sistema</string>
<string name="mii_edit_applet">Editor de Mii</string>
<string name="mii_edit_applet_description">Mira y edita Mii con el editor del sistema</string>
<string name="cabinet_applet">Cabinet</string>
<string name="cabinet_applet_description">Edita y borra los datos guardado del amiibo</string>
<string name="cabinet_launcher">Ejecutador de Cabinet</string>
<string name="cabinet_nickname_and_owner">Configuración del apodo y propietario</string>
<string name="cabinet_game_data_eraser">Borrador de datos de juego</string>
<string name="cabinet_restorer">Restaurador</string>
<string name="cabinet_formatter">Formateador</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia no es real</string>
@ -161,6 +201,7 @@
<string name="frame_limit_enable_description">Limita la velocidad de emulación a un porcentaje específico de la velocidad normal.</string>
<string name="frame_limit_slider">Limitar porcentaje de velocidad</string>
<string name="frame_limit_slider_description">Especifica el porcentaje para limitar la velocidad de emulación. 100% es la velocidad normal. Valores más altos o bajos incrementarán o disminuirán el límite de velocidad.</string>
<string name="cpu_backend">Motor de CPU</string>
<string name="cpu_accuracy">Precisión de CPU</string>
<string name="value_with_units">%1$s%2$s</string>
@ -186,11 +227,13 @@
<string name="renderer_force_max_clock">Forzar velocidad al máximo (solo Adreno)</string>
<string name="renderer_force_max_clock_description">Fuerza a la GPU a ejecutarse a la velocidad máxima de reloj posible (se seguirán aplicando restricciones térmicas).</string>
<string name="renderer_asynchronous_shaders">Usar shaders asíncronos</string>
<string name="renderer_asynchronous_shaders_description">Compila shaders de manera asíncrona, reduciendo los parones, pero puede introducir fallos.</string>
<string name="renderer_asynchronous_shaders_description">Compila shaders de manera asíncrona, reduce los parones pero puede introducir fallos.</string>
<string name="renderer_reactive_flushing">Usar limpieza reactiva</string>
<string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string>
<string name="use_disk_shader_cache">Caché de shaders en disco</string>
<string name="use_disk_shader_cache_description">Reduce los parones almacenando y cargando shaders generados.</string>
<string name="anisotropic_filtering">Filtrado anisotrópico</string>
<string name="anisotropic_filtering_description">Mejora la calidad de las texturas al ser observadas desde ángulos oblicuos</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
@ -217,6 +260,7 @@
<string name="shutting_down">Saliendo...</string>
<string name="reset_setting_confirmation">¿Desea restablecer esta configuración a su valor predeterminado?</string>
<string name="reset_to_default">Restablecer a predeterminado</string>
<string name="reset_to_default_description">Reinicia todos los ajustes avanzados</string>
<string name="reset_all_settings">¿Restablecer todas las configuraciones?</string>
<string name="reset_all_settings_description">Todas las opciones avanzadas se restablecerán a su configuración predeterminada. Esta acción no se puede deshacer.</string>
<string name="settings_reset">Reiniciar la configuracion</string>
@ -230,14 +274,24 @@
<string name="export_failed">La exportación falló</string>
<string name="import_failed">La importación falló</string>
<string name="cancelling">Cancelando</string>
<string name="install">Instalar</string>
<string name="delete">Borrar</string>
<string name="edit">Editar</string>
<string name="export_success">Exportado correctamente</string>
<string name="start">Comenzar</string>
<string name="clear">Limpiar</string>
<string name="global">Global</string>
<string name="custom">Perzonalizado</string>
<string name="notice">Aviso</string>
<string name="import_complete">La importación se completó</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Seleccionar driver GPU</string>
<string name="select_gpu_driver_title">¿Quiere reemplazar el driver de GPU actual?</string>
<string name="select_gpu_driver_install">Instalar</string>
<string name="select_gpu_driver_default">Predeterminado</string>
<string name="select_gpu_driver_use_default">Usando el driver de GPU por defecto </string>
<string name="select_gpu_driver_error">¡Driver no válido, utilizando el predeterminado del sistema!</string>
<string name="select_gpu_driver_error">Driver no válido seleccionado</string>
<string name="driver_already_installed">Driver ya instalado</string>
<string name="system_gpu_driver">Driver GPU del sistema</string>
<string name="installing_driver">Instalando driver...</string>
@ -245,11 +299,52 @@
<string name="preferences_settings">Ajustes</string>
<string name="preferences_general">General</string>
<string name="preferences_system">Sistema</string>
<string name="preferences_system_description">Modo en Dock, región, idioma</string>
<string name="preferences_graphics">Gráficos</string>
<string name="preferences_graphics_description">Nivel de precisión, resolución, caché de shaders</string>
<string name="preferences_audio">Audio</string>
<string name="preferences_audio_description">Motor de salida, volumen</string>
<string name="preferences_theme">Tema y color</string>
<string name="preferences_debug">Depuración</string>
<string name="preferences_debug_description">CPU/GPU debug, API gráfica, fastMEM</string>
<!-- Game properties -->
<string name="info">Información</string>
<string name="info_description">ID de programa, desarrollador, versión</string>
<string name="per_game_settings">Configuración por juego</string>
<string name="per_game_settings_description">Editar opciones específicas para este juego</string>
<string name="launch_options">Ejecutar configuración</string>
<string name="path">Ruta</string>
<string name="program_id">ID de programa</string>
<string name="developer">Desarrollador</string>
<string name="version">Versión</string>
<string name="copy_details">Copiar detalles</string>
<string name="add_ons">Extras/Add-ons</string>
<string name="add_ons_description">Activa/desactiva mods, actualizaciones y DLC</string>
<string name="clear_shader_cache">Limpiar la caché de shaders</string>
<string name="clear_shader_cache_description">Elimina todos los shaders construidos mientras se jugaba al juego</string>
<string name="clear_shader_cache_warning_description">Experimentarás más parones mientras que la caché de shaders se regenera</string>
<string name="cleared_shaders_successfully">Shaders limpiados con éxito</string>
<string name="addons_game">Addons: %1$s</string>
<string name="save_data">Datos de guardado</string>
<string name="save_data_description">Controla los datos de guardado de este juego</string>
<string name="delete_save_data">Borrar datos de guardado</string>
<string name="delete_save_data_description">Elimina todos los datos de guardado de este juego</string>
<string name="delete_save_data_warning_description">Ésto elimina de manera permanente todos los datos de guardado de este juego. ¿Seguro que quieres continuar?</string>
<string name="save_data_deleted_successfully">Datos de guardado eliminados con éxito</string>
<string name="select_content_type">Tipo de contenido</string>
<string name="updates_and_dlc">Actualizaciones y DLC</string>
<string name="mods_and_cheats">Mods y trucos</string>
<string name="addon_notice">Aviso importante de addons</string>
<!-- "cheats/" "romfs/" and "exefs/ should not be translated -->
<string name="addon_notice_description">Para instalar mods y trucos, debes seleccionar una carpeta que contiene los directorios cheats/, romfs/, o exefs/ . ¡No podemos confirmar si éstos serán compatibles con tu juego, así que ten cuidado!</string>
<string name="invalid_directory">Directorio no válido</string>
<!-- "cheats/" "romfs/" and "exefs/ should not be translated -->
<string name="invalid_directory_description">Por favor, asegúrese de que el directorio que ha selecionado incluye las carpetas cheats/, romfs/, o exefs/ e inténtelo de nuevo.</string>
<string name="addon_installed_successfully">Addon instalado con éxito</string>
<string name="verifying_content">Verificando contenido...</string>
<string name="content_install_notice">Aviso importante de contenido</string>
<string name="content_install_notice_description">El contenido seleccionado no es de este juego.\n¿Instalar de todas maneras?</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">Su ROM está encriptada</string>
<string name="loader_error_encrypted_roms_description"><![CDATA[Por favor, siga las guías para redumpear<a href=\"https://yuzu-emu.org/help/quickstart/#dumping-physical-titles-game-cards\">cartuchos de juegos</a> o <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-digital-titles-eshop\">títulos instalados</a>.]]></string>
@ -277,6 +372,7 @@
<string name="emulation_pause">Pausar emulación</string>
<string name="emulation_unpause">Despausar emulación</string>
<string name="emulation_input_overlay">Opciones de overlay</string>
<string name="touchscreen">Pantalla táctil</string>
<string name="load_settings">Cargando configuración...</string>
@ -308,6 +404,7 @@
<!-- Memory Sizes -->
<string name="memory_byte">Byte</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
@ -352,9 +449,13 @@
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_landscape">Paisaje</string>
<string name="screen_layout_portrait">Retrato</string>
<string name="screen_layout_auto">Auto</string>
<string name="screen_layout_sensor_landscape">Sensor paisaje</string>
<string name="screen_layout_landscape">Paisaje</string>
<string name="screen_layout_reverse_landscape">Paisaje inverso</string>
<string name="screen_layout_sensor_portrait">Sensor retrato</string>
<string name="screen_layout_portrait">Retrato</string>
<string name="screen_layout_reverse_portrait">Retrato inverso</string>
<!-- Aspect Ratios -->
<string name="ratio_default">Predeterminado (16:9)</string>
@ -363,6 +464,10 @@
<string name="ratio_force_sixteen_ten">Forzar 16:10</string>
<string name="ratio_stretch">Ajustar a la ventana</string>
<!-- CPU Backend -->
<string name="cpu_backend_dynarmic">DynARMic (lento)</string>
<string name="cpu_backend_nce">Ejecución nativa de código (NCE)</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">Preciso</string>
<string name="cpu_accuracy_unsafe">Impreciso</string>
@ -391,8 +496,15 @@
<string name="theme_mode_dark">Oscuro</string>
<!-- Audio output engines -->
<string name="oboe">oboe</string>
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">x2</string>
<string name="multiplier_four">x4</string>
<string name="multiplier_eight">x8</string>
<string name="multiplier_sixteen">x16</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Fondos oscuros</string>
<string name="use_black_backgrounds_description">Cuando utilice el modo oscuro, aplique fondos negros.</string>

View File

@ -34,6 +34,7 @@
<string name="empty_gamelist">Aucun fichier n\'a été trouvé ou aucun répertoire de jeu n\'a encore été sélectionné.</string>
<string name="search_and_filter_games">Rechercher et filtrer les jeux</string>
<string name="select_games_folder">Sélectionner le dossier des jeux</string>
<string name="manage_game_folders">Gérer les dossiers de jeux</string>
<string name="select_games_folder_description">Permet à yuzu de remplir la liste des jeux</string>
<string name="add_games_warning">Ne pas sélectionner le dossier des jeux ?</string>
<string name="add_games_warning_description">Les jeux ne seront pas affichés dans la liste des jeux si aucun dossier n\'est sélectionné.</string>
@ -47,7 +48,7 @@
<string name="install_prod_keys_warning_description">Des clés valides sont nécessaires pour émuler des jeux commerciaux. Seules les applications homebrew fonctionneront si vous continuez.</string>
<string name="install_prod_keys_warning_help">https://yuzu-emu.org/help/quickstart/#guide-introduction</string>
<string name="notifications">Notifications</string>
<string name="notifications_description">Accordez l\'autorisation de notification avec le bouton ci-dessous.</string>
<string name="notifications_description">Accorder la permission de notification avec le bouton ci-dessous.</string>
<string name="give_permission">Accorder la permission</string>
<string name="notification_warning">Ne pas accorder la permission de notification ?</string>
<string name="notification_warning_description">yuzu ne pourra pas vous communiquer d\'informations importantes.</string>
@ -68,6 +69,7 @@
<string name="invalid_keys_error">Clés de chiffrement invalides</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">Le fichier sélectionné est incorrect ou corrompu. Veuillez dumper à nouveau vos clés.</string>
<string name="gpu_driver_manager">Gestionnaire de pilotes du GPU</string>
<string name="install_gpu_driver">Installer le pilote du GPU</string>
<string name="install_gpu_driver_description">Installer des pilotes alternatifs pour des performances ou une précision potentiellement meilleures</string>
<string name="advanced_settings">Paramètres avancés</string>
@ -85,7 +87,11 @@
<string name="notification_no_directory_link_description">Veuillez localiser manuellement le dossier utilisateur avec le panneau latéral du gestionnaire de fichiers.</string>
<string name="manage_save_data">Gérer les données de sauvegarde</string>
<string name="manage_save_data_description">Données de sauvegarde trouvées. Veuillez sélectionner une option ci-dessous.</string>
<string name="import_save_warning">Importer les données de sauvegarde</string>
<string name="import_save_warning_description">Cela écrasera toutes les données de sauvegarde existantes avec le fichier fourni. Êtes-vous sûr de vouloir continuer ?</string>
<string name="import_export_saves_description">Importer ou exporter des fichiers de sauvegarde</string>
<string name="save_files_importing">Importation des fichiers de sauvegarde...</string>
<string name="save_files_exporting">Exportation des fichiers de sauvegarde...</string>
<string name="save_file_imported_success">Importé avec succès</string>
<string name="save_file_invalid_zip_structure">Structure de répertoire de sauvegarde non valide</string>
<string name="save_file_invalid_zip_structure_description">Le nom du premier sous-dossier doit être l\'identifiant du titre du jeu.</string>
@ -118,6 +124,40 @@
<string name="manage_yuzu_data_description">Importer/exporter le firmware, les clés, les données utilisateur, et bien plus encore !</string>
<string name="share_save_file">Partager le fichier de sauvegarde</string>
<string name="export_save_failed">Échec de l\'exportation de la sauvegarde</string>
<string name="game_folders">Dossiers de jeux</string>
<string name="deep_scan">Analyse approfondie</string>
<string name="add_game_folder">Ajouter un dossier de jeu</string>
<string name="folder_already_added">Ce dossier a déjà été ajouté !</string>
<string name="game_folder_properties">Propriétés du dossier du jeu</string>
<plurals name="saves_import_failed">
<item quantity="one">Échec de l\'importation de %d sauvegarde</item>
<item quantity="many">Échec de l\'importation de %d sauvegardes </item>
<item quantity="other">Échec de l\'importation de %d sauvegardes</item>
</plurals>
<plurals name="saves_import_success">
<item quantity="one">%d sauvegarde importée avec succès</item>
<item quantity="many">%d sauvegardes importées avec succès</item>
<item quantity="other">%d sauvegardes importées avec succès</item>
</plurals>
<string name="no_save_data_found">Aucune donnée de sauvegarde trouvée</string>
<!-- Applet launcher strings -->
<string name="applets">Lanceur d\'applets</string>
<string name="applets_description">Lancer des applets système en utilisant le firmware installé</string>
<string name="applets_error_firmware">Firmware non installé</string>
<string name="applets_error_applet">Applet non disponible</string>
<string name="applets_error_description"><![CDATA[Veuillez vous assurer que le fichier <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> et le <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-system-firmware\">firmware</a> sont installés et essayez à nouveau.]]></string>
<string name="album_applet">Album</string>
<string name="album_applet_description">Afficher les images stockées dans le dossier de captures d\'écran de l\'utilisateur avec le visualiseur de photos système.</string>
<string name="mii_edit_applet">Éditeur Mii</string>
<string name="mii_edit_applet_description">Visualiser et modifier les Miis avec l\'éditeur système.</string>
<string name="cabinet_applet">Cabinet</string>
<string name="cabinet_applet_description">Modifier et supprimer des données stockées sur un amiibo</string>
<string name="cabinet_launcher">Cabinet</string>
<string name="cabinet_nickname_and_owner">Paramètres du surnom et du propriétaire</string>
<string name="cabinet_game_data_eraser">Effaceur de données de jeu</string>
<string name="cabinet_restorer">Restaurateur</string>
<string name="cabinet_formatter">Formateur</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia n\'est pas réel</string>
@ -157,10 +197,11 @@
<string name="are_you_interested">Es tu intéressé ?</string>
<!-- General settings strings -->
<string name="frame_limit_enable">Limitation de vitesse</string>
<string name="frame_limit_enable">Limiter la vitesse</string>
<string name="frame_limit_enable_description">Limiter la vitesse d\'émulation à un pourcentage spécifié de la vitesse normale</string>
<string name="frame_limit_slider">Limite en pourcentage de vitesse</string>
<string name="frame_limit_slider">Limiter le pourcentage de vitesse</string>
<string name="frame_limit_slider_description">Spécifier le pourcentage pour limiter la vitesse d\'émulation. 100% correspond à la vitesse normale. Des valeurs plus élevées ou plus basses augmenteront ou diminueront la limite de vitesse.</string>
<string name="cpu_backend">Backend du CPU</string>
<string name="cpu_accuracy">Précision du CPU</string>
<string name="value_with_units">%1$s%2$s</string>
@ -191,6 +232,8 @@
<string name="renderer_reactive_flushing_description">Améliore la précision du rendu dans certains jeux au détriment des performances.</string>
<string name="use_disk_shader_cache">Utiliser les shader cache</string>
<string name="use_disk_shader_cache_description">Réduire les saccades en stockant et en chargeant localement les shaders générés</string>
<string name="anisotropic_filtering">Filtrage anisotropique</string>
<string name="anisotropic_filtering_description">Améliore la qualité des textures lorsqu\'elles sont visualisées sous des angles obliques</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
@ -217,7 +260,8 @@
<string name="shutting_down">Extinction en cours...</string>
<string name="reset_setting_confirmation">Voulez-vous réinitialiser ce paramètre à sa valeur par défaut ?</string>
<string name="reset_to_default">Réinitialiser par défaut</string>
<string name="reset_all_settings">Réinitialiser tous les réglages ?</string>
<string name="reset_to_default_description">Réinitialiser tous les paramètres avancés</string>
<string name="reset_all_settings">Réinitialiser tous les paramètres ?</string>
<string name="reset_all_settings_description">Tous les paramètres avancés seront réinitialisés à leur configuration par défaut. Ça ne peut pas être annulé.</string>
<string name="settings_reset">Paramètres réinitialisés</string>
<string name="close">Fermer</string>
@ -230,14 +274,24 @@
<string name="export_failed">L\'exportation a échoué</string>
<string name="import_failed">L\'importation a échoué</string>
<string name="cancelling">Annulation</string>
<string name="install">Installer</string>
<string name="delete">Supprimer</string>
<string name="edit">Éditer</string>
<string name="export_success">Exportation réussie</string>
<string name="start">Start</string>
<string name="clear">Effacer</string>
<string name="global">Global</string>
<string name="custom">Personnalisé</string>
<string name="notice">Avis</string>
<string name="import_complete">Importation terminée</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Sélectionner le pilote du GPU</string>
<string name="select_gpu_driver_title">Souhaitez vous remplacer votre pilote actuel ?</string>
<string name="select_gpu_driver_install">Installer</string>
<string name="select_gpu_driver_default">Par défaut</string>
<string name="select_gpu_driver_use_default">Utilisation du pilote du GPU par défaut</string>
<string name="select_gpu_driver_error">Pilote non valide sélectionné, utilisation du paramètre par défaut du système !</string>
<string name="select_gpu_driver_error">Pilote non valide sélectionné</string>
<string name="driver_already_installed">Pilote déjà installé</string>
<string name="system_gpu_driver">Pilote du GPU du système</string>
<string name="installing_driver">Installation du pilote...</string>
@ -245,11 +299,52 @@
<string name="preferences_settings">Paramètres</string>
<string name="preferences_general">Général</string>
<string name="preferences_system">Système</string>
<string name="preferences_system_description">Mode TV, région, langue</string>
<string name="preferences_graphics">Vidéo</string>
<string name="preferences_graphics_description">Niveau de précision, résolution, cache de shaders</string>
<string name="preferences_audio">Audio</string>
<string name="preferences_audio_description">Moteur de sortie, volume</string>
<string name="preferences_theme">Thème et couleur</string>
<string name="preferences_debug">Débogage</string>
<string name="preferences_debug_description">Débogage CPU/GPU, API graphique, fastmem</string>
<!-- Game properties -->
<string name="info">Info</string>
<string name="info_description">ID du programme, développeur, version</string>
<string name="per_game_settings">Paramètres spécifiques au jeu</string>
<string name="per_game_settings_description">Modifier les paramètres spécifiques à ce jeu</string>
<string name="launch_options">Lancer la configuration</string>
<string name="path">Chemin</string>
<string name="program_id">ID du programme</string>
<string name="developer">Développeur</string>
<string name="version">Version</string>
<string name="copy_details">Copier les détails</string>
<string name="add_ons">Extensions</string>
<string name="add_ons_description">Activer les mods, mises à jour et DLC</string>
<string name="clear_shader_cache">Effacer le cache des shaders</string>
<string name="clear_shader_cache_description">Supprime tous les shaders générés en jouant à ce jeu</string>
<string name="clear_shader_cache_warning_description">Vous risquez de rencontrer davantage de saccades pendant que le cache des shaders se régénère.</string>
<string name="cleared_shaders_successfully">Shaders effacés avec succès</string>
<string name="addons_game">Addons : %1$s</string>
<string name="save_data">Données de sauvegarde</string>
<string name="save_data_description">Gérer les données de sauvegarde spécifiques à ce jeu</string>
<string name="delete_save_data">Supprimer les données de sauvegarde</string>
<string name="delete_save_data_description">Supprime toutes les données de sauvegarde spécifiques à ce jeu</string>
<string name="delete_save_data_warning_description">Cela supprime de manière irréversible toutes les données de sauvegarde de ce jeu. Êtes-vous sûr de vouloir continuer ?</string>
<string name="save_data_deleted_successfully">Données de sauvegarde supprimées avec succès</string>
<string name="select_content_type">Type de contenu</string>
<string name="updates_and_dlc">Mises à jour et DLC</string>
<string name="mods_and_cheats">Mods et cheats</string>
<string name="addon_notice">Notification importante concernant l\'addon</string>
<!-- "cheats/" "romfs/" and "exefs/ should not be translated -->
<string name="addon_notice_description">Pour installer des mods et des cheats, vous devez sélectionner un dossier contenant un répertoire cheats/, romfs/ ou exefs/. Nous ne pouvons pas garantir leur compatibilité avec votre jeu, alors soyez prudent !</string>
<string name="invalid_directory">Répertoire non valide</string>
<!-- "cheats/" "romfs/" and "exefs/ should not be translated -->
<string name="invalid_directory_description">Veuillez vous assurer que le répertoire que vous avez sélectionné contient un dossier cheats/, romfs/ ou exefs/, puis réessayez.</string>
<string name="addon_installed_successfully">Addon installé avec succès</string>
<string name="verifying_content">Vérification du contenu...</string>
<string name="content_install_notice">Avis d\'installation du contenu</string>
<string name="content_install_notice_description">Le contenu que vous avez sélectionné ne correspond pas à ce jeu.\nInstaller quand même ?</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">Votre ROM est cryptée</string>
<string name="loader_error_encrypted_roms_description"><![CDATA[Veuillez suivre les guides pour refaire un dump de vos <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-physical-titles-game-cards\">cartouches de jeu</a> ou de vos <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-digital-titles-eshop\">titres installés</a>.]]></string>
@ -277,6 +372,7 @@
<string name="emulation_pause">Mettre en pause l\'émulation</string>
<string name="emulation_unpause">Reprendre l\'émulation</string>
<string name="emulation_input_overlay">Options de l\'overlay</string>
<string name="touchscreen">Écran tactile</string>
<string name="load_settings">Chargement des paramètres…</string>
@ -308,6 +404,7 @@
<!-- Memory Sizes -->
<string name="memory_byte">Octet</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">Ko</string>
<string name="memory_megabyte">Mo</string>
<string name="memory_gigabyte">GB</string>
@ -352,9 +449,13 @@
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_landscape">Paysage</string>
<string name="screen_layout_portrait">Portrait</string>
<string name="screen_layout_auto">Auto</string>
<string name="screen_layout_sensor_landscape">Paysage</string>
<string name="screen_layout_landscape">Paysage</string>
<string name="screen_layout_reverse_landscape">Paysage inversé</string>
<string name="screen_layout_sensor_portrait">Portrait</string>
<string name="screen_layout_portrait">Portrait</string>
<string name="screen_layout_reverse_portrait">Portrait inversé</string>
<!-- Aspect Ratios -->
<string name="ratio_default">Par défaut (16:9)</string>
@ -363,6 +464,10 @@
<string name="ratio_force_sixteen_ten">Forcer le 16:10</string>
<string name="ratio_stretch">Étirer à la fenêtre</string>
<!-- CPU Backend -->
<string name="cpu_backend_dynarmic">Dynarmic (Lent)</string>
<string name="cpu_backend_nce">Exécution de code natif (NCE)</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">Précis</string>
<string name="cpu_accuracy_unsafe">Risqué</string>
@ -391,8 +496,15 @@
<string name="theme_mode_dark">Sombre</string>
<!-- Audio output engines -->
<string name="oboe">oboe</string>
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Arrière-plan noir</string>
<string name="use_black_backgrounds_description">Lorsque vous utilisez le thème sombre, appliquer un arrière-plan noir.</string>

View File

@ -34,6 +34,7 @@
<string name="empty_gamelist">לא נמצאו קבצים או לנבחרה ספריית קבצים בינתיים.</string>
<string name="search_and_filter_games">חפש וסנן משחקים</string>
<string name="select_games_folder">בחר תיקיית משחקים</string>
<string name="manage_game_folders">נהל את תיקיית המשחקים</string>
<string name="select_games_folder_description">אפשר ל yuzu לאכלס את רשימת המשחקים</string>
<string name="add_games_warning">לדלג על בחירת תיקיית המשחקים?</string>
<string name="add_games_warning_description">משחקים לא יוצגו ברשימת המשחקים אם לנבחרה תיקיית משחקים.</string>
@ -68,6 +69,7 @@
<string name="invalid_keys_error">מפתחות הצפנה לא חוקיים</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">קבוץ שנבחר מושחת או לא נכון. בבקשה הוצא מחדש את המפתחות שלך.</string>
<string name="gpu_driver_manager">מנהל הדרייברים של המעבד הגרפי</string>
<string name="install_gpu_driver">התקן דרייבר למעבד הגרפי</string>
<string name="install_gpu_driver_description">התקן דרייברים אחרים בשביל סיכוי לביצועים או דיוק גבוההים יותר</string>
<string name="advanced_settings">הגדרות מתקדמות</string>
@ -86,6 +88,7 @@
<string name="manage_save_data">נהל מידע שמור</string>
<string name="manage_save_data_description">מידע שמור לא נמצא. בבקשה בחר/י אופציה מלמטה</string>
<string name="import_export_saves_description">יבא או יצא קבצי שמירה</string>
<string name="save_files_exporting">מייצא קבצי שמירה...</string>
<string name="save_file_imported_success">יובא בהצלחה</string>
<string name="save_file_invalid_zip_structure">מבנה ספריית השמירות לא חוקי</string>
<string name="save_file_invalid_zip_structure_description">התת תיקייה הראשונה חייב להיות ה title ID של המשחק</string>
@ -118,6 +121,28 @@
<string name="manage_yuzu_data_description">יבא/יצא firmware, keys, מידע של משתמש ועוד!</string>
<string name="share_save_file">שתף קובץ שמירה</string>
<string name="export_save_failed">נכשל בייצוא שמירה</string>
<string name="game_folders">תיקיית משחקים</string>
<string name="deep_scan">סריקה עמוקה</string>
<string name="add_game_folder">הוסף תיקיית משחקים</string>
<string name="folder_already_added">התיקייה הזו נוספה כבר!</string>
<string name="game_folder_properties">מאפייני תיקיית משחקים</string>
<!-- Applet launcher strings -->
<string name="applets">משגר Applet</string>
<string name="applets_description">מערכת שיגור Applet משתמשת בתוכנה המותקנת</string>
<string name="applets_error_firmware">ה Firmware לא מותקן</string>
<string name="applets_error_applet">Applet לא זמין</string>
<string name="applets_error_description"><![CDATA[בבקשה וודא שקבצי ה - <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a>ו <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-system-firmware\">firmware</a>שלך מותקנים ונסה שוב.]]></string>
<string name="album_applet">אלבום</string>
<string name="album_applet_description">צפה בתמונות השמורות בתיקיית צילומי המסך של המשתמש בעזרת מציג התמונות של המערכת</string>
<string name="mii_edit_applet">עורך Mii</string>
<string name="mii_edit_applet_description">צפה וערוך דמויות Mii בעזרת עורך המערכת</string>
<string name="cabinet_applet">ארון</string>
<string name="cabinet_applet_description">ערוך ומחק מידע השמור על ה amiibo</string>
<string name="cabinet_launcher">משגר ארונות</string>
<string name="cabinet_nickname_and_owner">כינוי והגדרות בעלים</string>
<string name="cabinet_game_data_eraser">מחק של נתוני משחק</string>
<string name="cabinet_restorer">שחזר</string>
<string name="cabinet_formatter">בונה תבניות</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia לא אמיתית</string>
@ -161,6 +186,7 @@
<string name="frame_limit_enable_description">מגביל את מהירות האמולציה לאחוז מהירות המבוקש מהמהירות הרגילה.</string>
<string name="frame_limit_slider">הגבל את אחוז המהירות</string>
<string name="frame_limit_slider_description">מדייק את אחוז מהירות האמולציה. 100% זה מהירות רגילה. ערכים גדולים או קטנים יאיצו או יאטו את מהירות האמולציה.</string>
<string name="cpu_backend">קצה האחורי של המעבד</string>
<string name="cpu_accuracy">דיוק המעבד</string>
<string name="value_with_units">%1$s%2$s</string>
@ -185,23 +211,38 @@
<string name="renderer_anti_aliasing">שיטת Anti-aliasing</string>
<string name="renderer_force_max_clock">החזק מהירות שעון מקסימלית (רק ל Adreno)</string>
<string name="renderer_force_max_clock_description">מכריח לדחוף את מהירויות המעבד הגרפי למקסימום (הגבלות חום ימשיכו לתפקד).</string>
<string name="renderer_asynchronous_shaders">השתמש בשיידרים אסינכרונים</string>
<string name="renderer_asynchronous_shaders_description">מקמפל שיידרים בצורה אסנכרונית, מפחית תקיעות אך עלול לגרום לבעיות גרפיות.</string>
<string name="renderer_reactive_flushing">השתמש בהבהוב תגובתי</string>
<string name="renderer_reactive_flushing_description">משפר את הדיוק של האמולציה במשחקים מסויימים במחיר של ביצועים.</string>
<string name="use_disk_shader_cache">מטמון השיידר של הדיסק</string>
<string name="use_disk_shader_cache_description">מפחית בתקיעות על ידי אחסון מקומי וטעינה של שיידרים הנוצרים. </string>
<!-- Debug settings strings -->
<string name="cpu">מעבד</string>
<string name="cpu_debug_mode">דיבאגינג למעבד</string>
<string name="cpu_debug_mode_description">מכניס את המעבד למצב דיבאג איטי</string>
<string name="gpu">מעבד גרפי</string>
<string name="renderer_api">ממשק תוכנה</string>
<string name="renderer_debug">דיבאגינג בגרפיקה</string>
<string name="renderer_debug_description">קובע את ממשק התוכנה של הגרפיקות למצב דיבאגינג איטי.</string>
<string name="fastmem">Fastmem</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">מנוע פלט</string>
<string name="audio_volume">עוצמת שמע</string>
<string name="audio_volume_description">מציין את עוצמת האודיו שיוצא.</string>
<!-- Miscellaneous -->
<string name="slider_default">ברירת מחדל</string>
<string name="ini_saved">הגדרות שמורות</string>
<string name="gameid_saved">הגדרות שמורות עבור %1$s</string>
<string name="error_saving">תקלה בשמירת %1$s.ini: %2$s</string>
<string name="unimplemented_menu">תפריט שלא יושם</string>
<string name="loading">טוען...</string>
<string name="shutting_down">כיבוי...</string>
<string name="reset_setting_confirmation">אתה מעוניין לאפס את ההגדרה הזו חזרה לברירת המחדל?</string>
<string name="reset_to_default">אפס לברירת המחדל</string>
<string name="reset_to_default_description">מאפס את כל ההגדרות המתקדמות.</string>
<string name="reset_all_settings">לאפס את כל ההגדרות?</string>
<string name="reset_all_settings_description">כל ההגדרות המתקדמות יאופסו לברירת המחדל. לא ניתן לבטל פעולה זו.</string>
<string name="settings_reset">אפס הגדרות</string>
@ -209,19 +250,26 @@
<string name="learn_more">למד עוד</string>
<string name="auto">אוטומטי</string>
<string name="submit">שלח</string>
<string name="string_null">ריק</string>
<string name="string_import">ייבוא</string>
<string name="export">ייצוא</string>
<string name="export_failed">ייצוא נכשל</string>
<string name="import_failed">ייבוא נכשל</string>
<string name="cancelling">מבטל</string>
<string name="install">התקן</string>
<string name="delete">מחק</string>
<string name="edit">ערוך</string>
<string name="export_success">יוצא בהצלחה</string>
<string name="start">התחלה</string>
<string name="clear">נקה</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">בחר דרייבר למעבד הגרפי</string>
<string name="select_gpu_driver_title">אתה מעוניין להחליף את הדרייבר של המעבד הגרפי שלך?</string>
<string name="select_gpu_driver_install">התקן</string>
<string name="select_gpu_driver_default">ברירת מחדל</string>
<string name="select_gpu_driver_use_default">משתמש בדרייבר ברירת המחדל של המעבד הגרפי</string>
<string name="select_gpu_driver_error">דרייבר לא חוקי נבחר, משתמש בברירת המחדל של המערכת!</string>
<string name="select_gpu_driver_error">נבחר דרייבר לא חוקי</string>
<string name="driver_already_installed">הדרייבר כבר מותקן</string>
<string name="system_gpu_driver">דרייבר של המעבד הגרפי של המערכת</string>
<string name="installing_driver">מתקין דרייבר...</string>
@ -229,11 +277,27 @@
<string name="preferences_settings">הגדרות</string>
<string name="preferences_general">כללי</string>
<string name="preferences_system">מערכת</string>
<string name="preferences_system_description">מצב מעוגן, איזור, שפה</string>
<string name="preferences_graphics">גרפיקה</string>
<string name="preferences_graphics_description">רמת דיוק, רזולוציה, מטמון שיידרים</string>
<string name="preferences_audio">שמע</string>
<string name="preferences_audio_description">מנוע פלט, עוצמת שמע</string>
<string name="preferences_theme">צבע ונושא</string>
<string name="preferences_debug">דיבאג</string>
<string name="preferences_debug_description">דיבאגינג עבור מעבד/מעבד גרפי, ממשק תוכנה עבור הגרפיקות, fastmem</string>
<!-- Game properties -->
<string name="info">מידע</string>
<string name="path">דרך</string>
<string name="developer">מפתח</string>
<string name="version">גרסה</string>
<string name="add_ons">תוספים</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">המשחק שלך מוצפן</string>
<string name="loader_error_encrypted_roms_description"><![CDATA[אנא עקוב אחרי המדריכים כדי לבצע redump של <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-physical-titles-game-cards\">כרטיסי המשחק</a>או <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-digital-titles-eshop\">הכותרות המותקנות</a> שלך.]]></string>
<string name="loader_error_encrypted_keys_description"><![CDATA[אנא וודא שקובץ ה-<a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> מותקן כך שניתן יהיה לפענח משחקים.]]></string>
<string name="loader_error_video_core">התרחשה בעיה באתחול של ליבת הווידאו</string>
<string name="loader_error_video_core_description">זה בדרך כלל נגרם על ידי דרייבר לא מתאים עבור המעבד הגרפי. התקנת דרייבר אשר מתאים למעבד הגרפי יכול לפתור את הבעיה הזו.</string>
<string name="loader_error_invalid_format">אין אפשרות לטעון את המשחק</string>
<string name="loader_error_file_not_found">קובץ המשחק לא קיים</string>
@ -241,10 +305,22 @@
<string name="emulation_exit">צא מהאמולציה</string>
<string name="emulation_done">סיום</string>
<string name="emulation_fps_counter">סופר FPS</string>
<string name="emulation_toggle_controls">החלפת בקרים</string>
<string name="emulation_rel_stick_center">מרכז ג׳ויסטיק יחסי</string>
<string name="emulation_dpad_slide">החלקת D-pad</string>
<string name="emulation_haptics">רטט מגע</string>
<string name="emulation_show_overlay">הצג את שכבת-העל</string>
<string name="emulation_toggle_all">החלף הכל</string>
<string name="emulation_control_adjust">התאם את שכבת-העל</string>
<string name="emulation_control_scale">קנה מידה</string>
<string name="emulation_control_opacity">שקיפות</string>
<string name="emulation_touch_overlay_reset">אפס את שכבת-העל</string>
<string name="emulation_touch_overlay_edit">ערוך שכבת-על</string>
<string name="emulation_pause">עצור אמולציה</string>
<string name="emulation_unpause">המשך אמולציה</string>
<string name="emulation_input_overlay">אופציות עבור שכבת-על</string>
<string name="touchscreen">מסך מגע</string>
<string name="load_settings">טוען הגדרות...</string>
<!-- Software keyboard -->
@ -258,6 +334,8 @@
<string name="system_archive_general">ארכיון מערכת</string>
<string name="save_load_error">בעיית שמירה/טעינה</string>
<string name="fatal_error">שגיאה חמורה</string>
<string name="fatal_error_message">שגיאה חמורה התרחשה. בדוק את היומן לפרטים./nהמשך הסימולציה עשוי לגרום לקריסות ולבאגים.</string>
<string name="performance_warning">כיבוי הגדרה זו ישפיע משמעותית על ביצועי הסימולציה! לחוויה הטובה ביותר, מומלץ להשאיר את הגדרה זו מופעלת.</string>
<string name="device_memory_inadequate">RAM המכשיר: %1$s/nמומלץ: %2$s</string>
<string name="memory_formatted">%1$s%2$s</string>
<string name="no_game_present">אין משחק שניתן להריץ!</string>
@ -273,6 +351,7 @@
<!-- Memory Sizes -->
<string name="memory_byte">בייט</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
@ -297,12 +376,17 @@
<string name="resolution_three">3X (2160p/3240p) (איטי)</string>
<string name="resolution_four">4X (2880p/4320p) (איטי)</string>
<!-- Renderer VSync -->
<string name="renderer_vsync_immediate">מיידי (כבוי)</string>
<string name="renderer_vsync_mailbox">תיבת דואר</string>
<string name="renderer_vsync_fifo">FIFO (On)</string>
<string name="renderer_vsync_fifo_relaxed">FIFO נינוח</string>
<!-- Scaling Filters -->
<string name="scaling_filter_nearest_neighbor">השכן הקרוב ביותר</string>
<string name="scaling_filter_bilinear">ביליניארי</string>
<string name="scaling_filter_bicubic">Bicubic</string>
<string name="scaling_filter_gaussian">Gaussian</string>
<string name="scaling_filter_scale_force">ScaleForce</string>
<string name="scaling_filter_fsr">AMD FidelityFX™ Super Resolution</string>
@ -312,10 +396,9 @@
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_auto">אוטומטי</string>
<string name="screen_layout_landscape">לרוחב</string>
<string name="screen_layout_portrait">לאורך</string>
<string name="screen_layout_auto">אוטומטי</string>
<!-- Aspect Ratios -->
<string name="ratio_default">ברירת מחדל (16:9)</string>
<string name="ratio_force_four_three">הכרח 4:3</string>
@ -323,6 +406,10 @@
<string name="ratio_force_sixteen_ten">הכרח 16:10</string>
<string name="ratio_stretch">הרחב לגודל המסך</string>
<!-- CPU Backend -->
<string name="cpu_backend_dynarmic">דינמי (איטי)</string>
<string name="cpu_backend_nce">ביצוע קוד מקורי (NCE)</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">מדויק</string>
<string name="cpu_accuracy_unsafe">לא בטוח</string>
@ -335,6 +422,10 @@
<string name="gamepad_home">בית</string>
<string name="gamepad_screenshot">צילום מסך</string>
<!-- Disk shader cache -->
<string name="preparing_shaders">מכין שיידרים</string>
<string name="building_shaders">בונה שיידרים</string>
<!-- Theme options -->
<string name="change_app_theme">שנה את נושא האפליקצייה</string>
<string name="theme_default">ברירת מחדל</string>
@ -346,9 +437,14 @@
<string name="theme_mode_light">בהיר</string>
<string name="theme_mode_dark">כהה</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">רקעים שחורים</string>
<string name="use_black_backgrounds_description">כשמתשמשים במצב כהה, שם רקעים שחורים.</string>

View File

@ -35,6 +35,7 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="empty_gamelist">Nem található fájl, vagy még nincs kiválasztva könyvtár.</string>
<string name="search_and_filter_games">Játékok keresése és szűrése</string>
<string name="select_games_folder">Játékmappa kiválasztása</string>
<string name="manage_game_folders">Játékmappák kezelése</string>
<string name="add_games_warning">Kihagyod a játékok mappa kiválasztását?</string>
<string name="add_games_warning_description">A játékok nem jelennek meg a Játékok listában, ha egy mappa nincs kijelölve.</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
@ -68,6 +69,7 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="invalid_keys_error">Érvénytelen titkosítókulcsok</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">A kiválasztott fájl helytelen, vagy sérült. Állíts össze egy új kulcsot.</string>
<string name="gpu_driver_manager">GPU illesztőprogram-kezelő</string>
<string name="install_gpu_driver">GPU illesztőprogram telepítése</string>
<string name="install_gpu_driver_description">Alternatív illesztőprogramok telepítése az esetlegesen elérhető teljesítmény és pontosság érdekében</string>
<string name="advanced_settings">Haladó beállítások</string>
@ -84,7 +86,11 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="notification_no_directory_link_description">Kérjük, manuálisan keresd meg a felhasználói mappát a fájlkezelő oldalsó paneljével.</string>
<string name="manage_save_data">Mentésadatok kezelése</string>
<string name="manage_save_data_description">Mentés található. Kérjük, válassz egyet az alábbi opciók közül.</string>
<string name="import_save_warning">Mentési fájlok importálása</string>
<string name="import_save_warning_description">Ezzel felülírod a fájlban lévő mentett adatokat. Biztosan szeretnéd folytatni?</string>
<string name="import_export_saves_description">Mentési fájlok importálás vagy exportálása</string>
<string name="save_files_importing">Mentési fájlok importálása...</string>
<string name="save_files_exporting">Mentési fájlok exportálása...</string>
<string name="save_file_imported_success">Sikeresen importálva</string>
<string name="save_file_invalid_zip_structure">Érvénytelen mentési könyvtárstruktúra</string>
<string name="save_file_invalid_zip_structure_description">Az első almappa neve a játék azonosítója kell, hogy legyen.</string>
@ -117,6 +123,38 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="manage_yuzu_data_description">Firmware, kulcsok, felhasználói adatok és egyebek importálása/exportálása</string>
<string name="share_save_file">Mentési fájl megosztása</string>
<string name="export_save_failed">A mentés exportálása sikertelen</string>
<string name="game_folders">Játékmappák</string>
<string name="deep_scan">Mély szkennelés</string>
<string name="add_game_folder">Játékmappa hozzáadása</string>
<string name="folder_already_added">Ez a mappa már hozzá lett adva!</string>
<string name="game_folder_properties">Játékmappa tulajdonságok</string>
<plurals name="saves_import_failed">
<item quantity="one">%dmentés importálása sikertelen</item>
<item quantity="other">%dmentés importálása sikertelen</item>
</plurals>
<plurals name="saves_import_success">
<item quantity="one">%dmentés sikeresen importálva</item>
<item quantity="other">%dmentés sikeresen importálva</item>
</plurals>
<string name="no_save_data_found">Nem található mentett adat</string>
<!-- Applet launcher strings -->
<string name="applets">Applet indító</string>
<string name="applets_description">Rendszer appletek indítása a telepített firmware-rel</string>
<string name="applets_error_firmware">Firmware nincs telepítve</string>
<string name="applets_error_applet">Applet nem elérhető</string>
<string name="applets_error_description"><![CDATA[Kérjük, győződj meg róla, hogy a <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> fájl és a <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-system-firmware\">firmware</a> telepítve van, majd próbáld újra.]]></string>
<string name="album_applet">Album</string>
<string name="album_applet_description">Képernyőképek megtekintése a rendszer fényképnézegetőjével</string>
<string name="mii_edit_applet">Mii szerkesztés</string>
<string name="mii_edit_applet_description">Miik megtekintése és szerkesztése a rendszerszerkesztővel</string>
<string name="cabinet_applet">Kabinet</string>
<string name="cabinet_applet_description">Amiibon tárolt adatok szerkesztése és törlése</string>
<string name="cabinet_launcher">Kabinet indító</string>
<string name="cabinet_nickname_and_owner">Becenév és tulajdonos beállítások</string>
<string name="cabinet_game_data_eraser">Játékadat eltávolító</string>
<string name="cabinet_restorer">Helyreállító</string>
<string name="cabinet_formatter">Formázó</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia nem valódi</string>
@ -158,6 +196,7 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="frame_limit_enable_description">Korlátozza az emuláció sebességét a normál sebesség adott százalékára.</string>
<string name="frame_limit_slider">Sebességkorlát százaléka</string>
<string name="frame_limit_slider_description">Az emuláció sebességét határozza meg. 100% a normál sebesség. A magasabb értékek növelik, az alacsonyabbak csökkentik a sebességkorlátot.</string>
<string name="cpu_backend">CPU backend</string>
<string name="cpu_accuracy">CPU pontosság</string>
<string name="value_with_units">%1$s%2$s</string>
@ -188,7 +227,7 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="renderer_reactive_flushing_description">Javítja a renderelési pontosságot néhány játékban a teljesítmény rovására.</string>
<string name="use_disk_shader_cache">Lemez árnyékoló gyorsítótár</string>
<string name="use_disk_shader_cache_description">Csökkenti az akadásokat azáltal, hogy helyileg tárolja és tölti be a generált árnyékolókat.</string>
<string name="anisotropic_filtering">Anizotropikus szűrés</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU hibakeresés</string>
@ -196,9 +235,9 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="gpu">GPU</string>
<string name="renderer_api">API</string>
<string name="renderer_debug">Grafikai hibakeresés</string>
<string name="renderer_debug_description">Lassú hibakeresési módba állítja a grafikus API-t .</string>
<string name="renderer_debug_description">Lassú hibakereső módba állítja a grafikus API-t .</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Kimeneti rendszer</string>
<string name="audio_output_engine">Kimeneti motor</string>
<string name="audio_volume">Hangerő</string>
<string name="audio_volume_description">Hangkimenet hangerejének megadása</string>
@ -212,6 +251,7 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="shutting_down">Leállítás...</string>
<string name="reset_setting_confirmation">Szeretnéd visszaállítani a beállítások az alapértelmezett értékekre?</string>
<string name="reset_to_default">Alaphelyzetbe állítás</string>
<string name="reset_to_default_description">Visszaállítja a haladó beállításokat</string>
<string name="reset_all_settings">Alaphelyzetbe állítod a beállításokat?</string>
<string name="reset_all_settings_description">Minden haladó beállítás vissza lesz állítva az alapértelmezett konfigurációra. Ez a művelet nem vonható vissza.</string>
<string name="settings_reset">Beállítások alaphelyzetbe állítva</string>
@ -219,12 +259,24 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="learn_more">Tudj meg többet</string>
<string name="auto">Automatikus</string>
<string name="submit">Küldés</string>
<string name="string_null">Nulla</string>
<string name="string_null">Null</string>
<string name="string_import">Importálás</string>
<string name="export">Exportálás</string>
<string name="export_failed">Exportálás sikertelen</string>
<string name="import_failed">Importálás sikertelen</string>
<string name="cancelling">Megszakítás</string>
<string name="install">Telepítés</string>
<string name="delete">Törlés</string>
<string name="edit">Szerkesztés</string>
<string name="export_success">Sikeresen exportálva</string>
<string name="start">Start</string>
<string name="clear">Törlés</string>
<string name="global">Globális</string>
<string name="custom">Egyéni</string>
<string name="notice">Értesítés</string>
<string name="import_complete">Importálás befejezve</string>
<string name="more_options">További opciók</string>
<string name="use_global_setting">Globális beállítás használata</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Válassz GPU illesztőprogramot</string>
@ -232,7 +284,8 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="select_gpu_driver_install">Telepítés</string>
<string name="select_gpu_driver_default">Alapértelmezett</string>
<string name="select_gpu_driver_use_default">Alapértelmezett GPU illesztőprogram használata</string>
<string name="select_gpu_driver_error">Érvénytelen driver kiválasztva, a rendszer alapértelmezett lesz használva!</string>
<string name="select_gpu_driver_error">Érvénytelen illesztőprogram kiválasztva</string>
<string name="driver_already_installed">Az illesztőprogram már telepítve van</string>
<string name="system_gpu_driver">Rendszer GPU illesztőprogram</string>
<string name="installing_driver">Illesztőprogram telepítése...</string>
@ -240,10 +293,54 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="preferences_settings">Beállítások</string>
<string name="preferences_general">Általános</string>
<string name="preferences_system">Rendszer</string>
<string name="preferences_system_description">Dokkolt mód, régió, nyelv</string>
<string name="preferences_graphics">Grafika</string>
<string name="preferences_graphics_description">Pontossági szint, felbontás, árnyékoló gyorsítótár</string>
<string name="preferences_audio">Hang</string>
<string name="preferences_audio_description">Kimeneti motor, hangerő</string>
<string name="preferences_theme">Téma és színek</string>
<string name="preferences_debug">Hibakeresés</string>
<string name="preferences_debug_description">CPU/GPU hibakeresés, grafikus API, fastmem</string>
<!-- Game properties -->
<string name="info">Infó</string>
<string name="info_description">Program ID, fejlesztő, verzió</string>
<string name="per_game_settings">Játékonkénti beállítások</string>
<string name="per_game_settings_description">Játékspecifikus beállítások szerkesztése</string>
<string name="launch_options">Indítási konfiguráció</string>
<string name="path">Útvonal</string>
<string name="program_id">Program ID</string>
<string name="developer">Fejlesztő</string>
<string name="version">Verzió</string>
<string name="copy_details">Részletek másolása</string>
<string name="add_ons">Kiegészítők</string>
<string name="add_ons_description">Modok, frissítések és DLC váltása</string>
<string name="clear_shader_cache">Árnyékoló gyorsítótár ürítése</string>
<string name="clear_shader_cache_description">Eltávolítja a játék által létrehozott árnyékolókat.</string>
<string name="clear_shader_cache_warning_description">Az árnyékoló gyorsítótár regenerálódása során több akadozást fogsz tapasztalni.</string>
<string name="cleared_shaders_successfully">Árnyékolók sikeresen ürítve</string>
<string name="addons_game">Kiegészítők: %1$s</string>
<string name="save_data">Mentett adatok</string>
<string name="save_data_description">Játékspecifikus mentett adatok kezelése</string>
<string name="delete_save_data">Mentett adatok törlése</string>
<string name="delete_save_data_description">Eltávolítja az összes játékhoz tartozó mentett adatot.</string>
<string name="delete_save_data_warning_description">Ez helyreállíthatatlanul eltávolítja a játék összes mentett adatát. Biztosan szeretnéd folytatni?</string>
<string name="save_data_deleted_successfully">Mentett adatok sikeresen törölve</string>
<string name="select_content_type">Tartalom típusa</string>
<string name="updates_and_dlc">Frissítések és DLC</string>
<string name="mods_and_cheats">Modok és csalások</string>
<string name="addon_notice">Fontos kiegészítő értesítés</string>
<!-- "cheats/" "romfs/" and "exefs/ should not be translated -->
<string name="addon_notice_description">A modok és csalások telepítéséhez olyan mappát válassz, amely tartalmaz cheats/, romfs/ vagy exefs/ könyvtárat. Nem tudjuk garantálni, hogy ezek kompatibilisek lesznek a játékoddal, ezért légy óvatos!</string>
<string name="invalid_directory">Érvénytelen könyvtár</string>
<!-- "cheats/" "romfs/" and "exefs/ should not be translated -->
<string name="invalid_directory_description">Kérjük, győződj meg róla, hogy a kiválasztott könyvtár tartalmazza a cheats/, romfs/ vagy exefs/ mappát, majd próbáld újra.</string>
<string name="addon_installed_successfully">Kiegészítő sikeresen telepítve</string>
<string name="verifying_content">Tartalom ellenőrzése...</string>
<string name="content_install_notice">Tartalom telepítési értesítés</string>
<string name="content_install_notice_description">A kiválasztott tartalom nem ehhez a játékhoz tartozik.\nÍgy is telepíted?</string>
<string name="confirm_uninstall">Eltávolítás megerősítése</string>
<string name="confirm_uninstall_description">Biztosan törölni szeretnéd ezt a kiegészítőt?</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">ROM titkosítva</string>
@ -270,6 +367,7 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="emulation_pause">Emuláció szünetelése</string>
<string name="emulation_unpause">Emuláció folytatása</string>
<string name="emulation_input_overlay">Átfedés beállításai</string>
<string name="touchscreen">Érintőképernyő</string>
<string name="load_settings">Beállítások betöltése...</string>
@ -301,6 +399,7 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<!-- Memory Sizes -->
<string name="memory_byte">Bájt</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
@ -345,9 +444,11 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_landscape">Fekvő</string>
<string name="screen_layout_portrait">Álló</string>
<string name="screen_layout_auto">Automatikus</string>
<string name="screen_layout_landscape">Fekvő</string>
<string name="screen_layout_reverse_landscape">Fekvő (fejjel lefelé)</string>
<string name="screen_layout_portrait">Álló</string>
<string name="screen_layout_reverse_portrait">Álló (fejjel lefelé)</string>
<!-- Aspect Ratios -->
<string name="ratio_default">Alapértelmezett (16:9)</string>
@ -356,6 +457,8 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="ratio_force_sixteen_ten">16:10 kényszerítése</string>
<string name="ratio_stretch">Ablakhoz nyújtás</string>
<!-- CPU Backend -->
<string name="cpu_backend_dynarmic">Dinamikus (lassú)</string>
<!-- CPU Accuracy -->
<string name="cpu_accuracy_accurate">Pontos</string>
<string name="cpu_accuracy_unsafe">Nem biztonságos</string>
@ -382,8 +485,15 @@ Válaszd ki a(z) &lt;b>Games&lt;/b> mappát az alábbi gombbal.</string>
<string name="theme_mode_dark">Sötét</string>
<!-- Audio output engines -->
<string name="oboe">oboe</string>
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Fekete háttér</string>
<string name="use_black_backgrounds_description">Sötét téma használatakor fekete háttér használata.</string>

View File

@ -17,7 +17,7 @@
<string name="keys_description">Seleziona il tuo file &lt;b>prod.keys&lt;/b> con il pulsante in basso.</string>
<string name="select_keys">Seleziona le chiavi</string>
<string name="games">Giochi</string>
<string name="games_description">Seleziona la cartella &lt;b>Games&lt;/b> con il pulsante in basso.</string>
<string name="games_description">Seleziona la cartella dei &lt;b>giochi&lt;/b> con il pulsante in basso.</string>
<string name="done">Fatto</string>
<string name="done_description">È tutto pronto.\nDivertiti a giocare!</string>
<string name="text_continue">Continua</string>
@ -33,7 +33,7 @@
<string name="home_settings">Impostazioni</string>
<string name="empty_gamelist">Non sono stati trovati file o non è stata ancora selezionata alcuna directory di gioco.</string>
<string name="search_and_filter_games">Cerca e filtra i giochi</string>
<string name="select_games_folder">Seleziona la cartella di gioco</string>
<string name="select_games_folder">Seleziona la cartella dei giochi</string>
<string name="select_games_folder_description">Consente a yuzu di popolare l\'elenco dei giochi</string>
<string name="add_games_warning">Saltare la selezione della cartella dei giochi?</string>
<string name="add_games_warning_description">I giochi non saranno mostrati nella lista dei giochi se una cartella non è selezionata.</string>
@ -68,6 +68,7 @@
<string name="invalid_keys_error">Chiavi di crittografia non valide</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">Il file selezionato è incorretto o corrotto. Per favore riesegui il dump delle tue chiavi.</string>
<string name="gpu_driver_manager">Gestore driver GPU</string>
<string name="install_gpu_driver">Installa i driver GPU</string>
<string name="install_gpu_driver_description">Installa driver alternativi per potenziali prestazioni migliori o accuratezza.</string>
<string name="advanced_settings">Impostazioni avanzate</string>
@ -118,6 +119,23 @@
<string name="manage_yuzu_data_description">Importa/Esporta il firmware, le keys, i dati utente, e altro!</string>
<string name="share_save_file">Condividi i tuoi dati di salvataggio</string>
<string name="export_save_failed">Errore durante l\'esportazione del salvataggio</string>
<!-- Applet launcher strings -->
<string name="applets">Avvia applet</string>
<string name="applets_description">Avvia applet di sistema usando il firmware installato</string>
<string name="applets_error_firmware">Firmware non installato</string>
<string name="applets_error_applet">Applet non disponibile</string>
<string name="applets_error_description"><![CDATA[Assicurati che il file <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> e il <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-system-firmware\">firmware</a> siano installati e riprova.]]></string>
<string name="album_applet">Album</string>
<string name="album_applet_description">Visualizza le immagini salvate nella cartella screenshots dell\'utente con il visualizzatore immagini di sistema</string>
<string name="mii_edit_applet">Modifica Mii</string>
<string name="mii_edit_applet_description">Visualizza e modifica Mii con l\'editor di sistema</string>
<string name="cabinet_applet">Cabinet</string>
<string name="cabinet_applet_description">Modifica ed elimina i dati salvati sugli amiibo</string>
<string name="cabinet_launcher">Avvia Cabinet</string>
<string name="cabinet_nickname_and_owner">Impostazioni nickname e proprietario</string>
<string name="cabinet_game_data_eraser">Cancella dati di gioco</string>
<string name="cabinet_restorer">Ripristina</string>
<string name="cabinet_formatter">Formatta</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia non è reale</string>
@ -191,7 +209,6 @@
<string name="renderer_reactive_flushing_description">Migliora l\'accuratezza della grafica in alcuni giochi, al costo delle performance.</string>
<string name="use_disk_shader_cache">Usa la cache delle shader</string>
<string name="use_disk_shader_cache_description">Riduce lo stuttering caricando le shader già compilate all\'avvio.</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="cpu_debug_mode">Debug della CPU</string>
@ -230,14 +247,19 @@
<string name="export_failed">Esportazione Fallita</string>
<string name="import_failed">Importazione Fallita</string>
<string name="cancelling">Cancellazione</string>
<string name="install">Installa</string>
<string name="delete">Elimina</string>
<string name="start">Start</string>
<string name="clear">Cancella</string>
<string name="custom">Personalizzato</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Seleziona il driver della GPU</string>
<string name="select_gpu_driver_title">Vuoi sostituire il driver della tua GPU attuale?</string>
<string name="select_gpu_driver_install">Installa</string>
<string name="select_gpu_driver_default">Predefinito</string>
<string name="select_gpu_driver_use_default">Utilizza il driver predefinito della GPU.</string>
<string name="select_gpu_driver_error">Il driver selezionato è invalido, è in utilizzo quello predefinito di sistema!</string>
<string name="select_gpu_driver_error">Driver selezionato non valido</string>
<string name="driver_already_installed">Driver già installato</string>
<string name="system_gpu_driver">Driver GPU del sistema</string>
<string name="installing_driver">Installando i driver...</string>
@ -249,7 +271,12 @@
<string name="preferences_audio">Audio</string>
<string name="preferences_theme">Tema e colori</string>
<string name="preferences_debug">Debug</string>
<!-- Game properties -->
<string name="info">Info</string>
<string name="path">Percorso</string>
<string name="developer">Sviluppatore</string>
<string name="version">Versione</string>
<string name="add_ons">Add-on</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">La tua ROM è criptata</string>
<string name="loader_error_encrypted_roms_description"><![CDATA[Segui la nostra guida per fare il <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-physical-titles-game-cards\">dump delle tue cartucce di gioco</a>oppure <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-digital-titles-eshop\">dei titoli già installati</a>.]]></string>
@ -263,20 +290,21 @@
<string name="emulation_exit">Arresta emulazione</string>
<string name="emulation_done">Fatto</string>
<string name="emulation_fps_counter">Contatore FPS</string>
<string name="emulation_toggle_controls">Controlli a interruttore</string>
<string name="emulation_toggle_controls">Attiva/disattiva comandi</string>
<string name="emulation_rel_stick_center">Centro relativo degli Stick</string>
<string name="emulation_dpad_slide">DPad A Scorrimento</string>
<string name="emulation_haptics">Feedback Aptico</string>
<string name="emulation_show_overlay">Mostra l\'Overlay</string>
<string name="emulation_show_overlay">Mostra l\'overlay</string>
<string name="emulation_toggle_all">Attiva/Disattiva tutto</string>
<string name="emulation_control_adjust">Modifica l\'Overlay</string>
<string name="emulation_control_adjust">Regola l\'overlay</string>
<string name="emulation_control_scale">Scala</string>
<string name="emulation_control_opacity">Opacità</string>
<string name="emulation_touch_overlay_reset">Reimposta l\'Overlay</string>
<string name="emulation_touch_overlay_edit">Modifica l\'Overlay</string>
<string name="emulation_touch_overlay_reset">Reimposta l\'overlay</string>
<string name="emulation_touch_overlay_edit">Modifica l\'overlay</string>
<string name="emulation_pause">Sospendi l\'emulazione</string>
<string name="emulation_unpause">Riprendi l\'emulazione</string>
<string name="emulation_input_overlay">Opzioni overlay</string>
<string name="touchscreen">Touchscreen</string>
<string name="load_settings">Carico le impostazioni...</string>
@ -308,6 +336,7 @@
<!-- Memory Sizes -->
<string name="memory_byte">Byte</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">Kb</string>
<string name="memory_megabyte">Mb</string>
<string name="memory_gigabyte">GB</string>
@ -352,10 +381,9 @@
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_auto">Automatico</string>
<string name="screen_layout_landscape">Layout Orizzontale</string>
<string name="screen_layout_portrait">Layout Verticale</string>
<string name="screen_layout_auto">Automatico</string>
<!-- Aspect Ratios -->
<string name="ratio_default">Predefinito (16:9)</string>
<string name="ratio_force_four_three">Forza 4:3</string>
@ -390,9 +418,14 @@
<string name="theme_mode_light">Chiaro</string>
<string name="theme_mode_dark">Scuro</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Sfondi neri</string>
<string name="use_black_backgrounds_description">Quando utilizzi il tema scuro, applica sfondi neri.</string>

View File

@ -39,7 +39,7 @@
<string name="add_games_warning_description">フォルダを選択しないと、ゲームがリストに表示されません。</string>
<string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
<string name="home_search_games">ゲームを検索</string>
<string name="search_settings">検索設定</string>
<string name="search_settings">設定を検索</string>
<string name="games_dir_selected">フォルダを選択しました</string>
<string name="install_prod_keys">prod.keys</string>
<string name="install_prod_keys_description">製品版ゲームの復号化に必要です</string>
@ -68,6 +68,7 @@
<string name="invalid_keys_error">暗号化キーが無効</string>
<string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
<string name="install_keys_failure_description">ファイルが間違っているか破損しています。キーを再ダンプしてください。</string>
<string name="gpu_driver_manager">GPUドライバーの管理</string>
<string name="install_gpu_driver">GPUドライバー</string>
<string name="install_gpu_driver_description">代替ドライバーをインストールしてパフォーマンスや精度を向上させます</string>
<string name="advanced_settings">高度な設定</string>
@ -111,6 +112,9 @@
<string name="custom_driver_not_supported">カスタムドライバはサポートされていません</string>
<string name="manage_yuzu_data">yuzu データを管理</string>
<string name="share_save_file">セーブファイルを共有</string>
<string name="applets_error_firmware">ファームウェア未インストール</string>
<string name="album_applet">アルバム</string>
<string name="cabinet_nickname_and_owner">ニックネームと所有者の設定</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">ガイアは実在しない</string>
<string name="copied_to_clipboard">クリップボードにコピーしました</string>
@ -178,10 +182,9 @@
<string name="renderer_reactive_flushing_description">一部のゲームにおいて、パフォーマンスを犠牲にしながらも、レンダリング精度を向上させます。</string>
<string name="use_disk_shader_cache">ディスクシェーダーキャッシュ</string>
<string name="use_disk_shader_cache_description">生成したシェーダーを端末に保存して読み込み、コマ落ちを軽減します。</string>
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU デバッギン</string>
<string name="cpu_debug_mode">CPUデバッグ</string>
<string name="gpu">GPU</string>
<string name="renderer_api">API</string>
<string name="renderer_debug">グラフィックデバッグ</string>
@ -215,14 +218,17 @@
<string name="export_failed">エクスポート失敗</string>
<string name="import_failed">インポート失敗</string>
<string name="cancelling">キャンセル中</string>
<string name="install">インストール</string>
<string name="delete">削除</string>
<string name="start">開始</string>
<string name="clear">クリア</string>
<string name="custom">カスタム</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">GPUドライバを選択</string>
<string name="select_gpu_driver_title">現在のGPUドライバを置き換えますか</string>
<string name="select_gpu_driver_install">インストール</string>
<string name="select_gpu_driver_default">デフォルト</string>
<string name="select_gpu_driver_use_default">デフォルトのドライバを使用します</string>
<string name="select_gpu_driver_error">選択されたドライバが無効、システムのデフォルトを使用します!</string>
<string name="system_gpu_driver">システムのGPUドライバ</string>
<string name="installing_driver">インストール中…</string>
@ -234,7 +240,12 @@
<string name="preferences_audio">サウンド</string>
<string name="preferences_theme">テーマと色</string>
<string name="preferences_debug">デバッグ</string>
<!-- Game properties -->
<string name="info">情報</string>
<string name="path">パス</string>
<string name="developer">開発元</string>
<string name="version">バージョン</string>
<string name="add_ons">アドオン</string>
<!-- ROM loading errors -->
<string name="loader_error_encrypted">ROMが暗号化されています</string>
<string name="loader_error_encrypted_keys_description"><![CDATA[ゲームの復号化に必要な <a href=\"https://yuzu-emu.org/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> ファイルがインストールされていることを確認してください。]]></string>
@ -261,6 +272,7 @@
<string name="emulation_pause">一時停止</string>
<string name="emulation_unpause">再開</string>
<string name="emulation_input_overlay">表示オプション</string>
<string name="touchscreen">タッチスクリーン</string>
<string name="load_settings">設定をロード中…</string>
@ -292,6 +304,7 @@
<!-- Memory Sizes -->
<string name="memory_byte">Byte</string>
<string name="memory_byte_shorthand">B</string>
<string name="memory_kilobyte">KB</string>
<string name="memory_megabyte">MB</string>
<string name="memory_gigabyte">GB</string>
@ -336,10 +349,9 @@
<string name="anti_aliasing_smaa">SMAA</string>
<!-- Screen Layouts -->
<string name="screen_layout_auto">自動</string>
<string name="screen_layout_landscape">横長</string>
<string name="screen_layout_portrait">縦長</string>
<string name="screen_layout_auto">自動</string>
<!-- Aspect Ratios -->
<string name="ratio_default">デフォルト (16:9)</string>
<string name="ratio_force_four_three">強制 4:3</string>
@ -374,9 +386,14 @@
<string name="theme_mode_light">ライト</string>
<string name="theme_mode_dark">ダーク</string>
<!-- Audio output engines -->
<string name="cubeb">cubeb</string>
<!-- Anisotropic filtering options -->
<string name="multiplier_two">2x</string>
<string name="multiplier_four">4x</string>
<string name="multiplier_eight">8x</string>
<string name="multiplier_sixteen">16x</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">完全な黒を使用</string>
<string name="use_black_backgrounds_description">ダークテーマの背景色に黒が適用されます。</string>

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