Merge branch 'master' into Shader-JIT-Multithreading

This commit is contained in:
jbm11208 2026-01-18 15:51:44 -05:00 committed by GitHub
commit 641691c497
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
234 changed files with 18196 additions and 13502 deletions

View File

@ -9,8 +9,14 @@ fi
cd src/android
chmod +x ./gradlew
./gradlew assembleRelease
./gradlew bundleRelease
if [[ "$TARGET" == "googleplay" ]]; then
./gradlew assembleGooglePlayRelease
./gradlew bundleGooglePlayRelease
else
./gradlew assembleVanillaRelease
./gradlew bundleVanillaRelease
fi
ccache -s -v

17
.ci/docker.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash -ex
GITREV="`git show -s --format='%h'`" || true
if [ "$GITHUB_REF_TYPE" = "tag" ]; then
TAG_NAME=$GITHUB_REF_NAME
elif [[ -n $GITREV ]]; then
TAG_NAME=$GITREV
else
TAG_NAME=unknown
fi
echo "Tag name is: $TAG_NAME"
docker build -f docker/azahar-room/Dockerfile -t azahar-room:$TAG_NAME .
mkdir -p build
docker save azahar-room:$TAG_NAME > build/azahar-room-$TAG_NAME.dockerimage

View File

@ -1,14 +1,16 @@
#!/bin/bash -ex
if [ "$TARGET" = "appimage" ]; then
if [[ "$TARGET" == "appimage"* ]]; then
# Compile the AppImage we distribute with Clang.
export EXTRA_CMAKE_FLAGS=(-DCMAKE_CXX_COMPILER=clang++
-DCMAKE_C_COMPILER=clang
-DCMAKE_LINKER=/etc/bin/ld.lld
-DENABLE_ROOM_STANDALONE=OFF)
# Bundle required QT wayland libraries
export EXTRA_QT_PLUGINS="waylandcompositor"
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
if [ "$TARGET" = "appimage-wayland" ]; then
# Bundle required QT wayland libraries
export EXTRA_QT_PLUGINS="waylandcompositor"
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
fi
else
# For the linux-fresh verification target, verify compilation without PCH as well.
export EXTRA_CMAKE_FLAGS=(-DCITRA_USE_PRECOMPILED_HEADERS=OFF)
@ -30,7 +32,7 @@ cmake .. -G Ninja \
ninja
strip -s bin/Release/*
if [ "$TARGET" = "appimage" ]; then
if [[ "$TARGET" == "appimage"* ]]; then
ninja bundle
# TODO: Our AppImage environment currently uses an older ccache version without the verbose flag.
ccache -s

View File

@ -22,12 +22,13 @@ jobs:
with:
name: source
path: artifacts/
linux:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: ["appimage", "fresh"]
target: ["appimage", "appimage-wayland", "fresh"]
container:
image: opensauce04/azahar-build-environment:latest
options: -u 1001
@ -51,16 +52,21 @@ jobs:
- name: Build
run: ./.ci/linux.sh
- name: Move AppImage to artifacts directory
if: ${{ matrix.target == 'appimage' }}
if: ${{ contains(matrix.target, 'appimage') }}
run: |
mkdir -p artifacts
mv build/bundle/*.AppImage artifacts/
- name: Rename AppImage
if: ${{ matrix.target == 'appimage-wayland' }}
run: |
mv artifacts/azahar.AppImage artifacts/azahar-wayland.AppImage
- name: Upload
if: ${{ matrix.target == 'appimage' }}
if: ${{ contains(matrix.target, 'appimage') }}
uses: actions/upload-artifact@v4
with:
name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/
macos:
runs-on: ${{ (matrix.target == 'x86_64' && 'macos-15-intel') || 'macos-26' }}
strategy:
@ -102,6 +108,7 @@ jobs:
with:
name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/
macos-universal:
runs-on: macos-26
needs: macos
@ -133,6 +140,7 @@ jobs:
with:
name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/
windows:
runs-on: windows-latest
strategy:
@ -210,54 +218,92 @@ jobs:
with:
name: ${{ env.OS }}-${{ env.TARGET }}
path: artifacts/
android:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target: ["vanilla", "googleplay"]
env:
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_COMPILERCHECK: content
CCACHE_SLOPPINESS: time_macros
OS: android
TARGET: universal
TARGET: ${{ matrix.target }}
SHOULD_RUN: ${{ (matrix.target == 'vanilla' || github.ref_type == 'tag') }}
steps:
- uses: actions/checkout@v4
if: ${{ env.SHOULD_RUN == 'true' }}
with:
submodules: recursive
- name: Set up cache
if: ${{ env.SHOULD_RUN == 'true' }}
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-android-${{ github.sha }}
key: ${{ runner.os }}-${{ env.OS }}-${{ matrix.target }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-android-
${{ runner.os }}-${{ env.OS }}-${{ matrix.target }}-
- name: Set tag name
if: ${{ env.SHOULD_RUN == 'true' }}
run: |
if [[ "$GITHUB_REF_TYPE" == "tag" ]]; then
echo "GIT_TAG_NAME=$GITHUB_REF_NAME" >> $GITHUB_ENV
fi
echo $GIT_TAG_NAME
- name: Deps
- name: Install tools
if: ${{ env.SHOULD_RUN == 'true' }}
run: |
sudo apt-get update -y
sudo apt-get install ccache apksigner -y
- name: Update Android SDK CMake version
if: ${{ env.SHOULD_RUN == 'true' }}
run: |
echo "y" | ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager "cmake;3.30.3"
- name: Build
if: ${{ env.SHOULD_RUN == 'true' }}
run: JAVA_HOME=$JAVA_HOME_17_X64 ./.ci/android.sh
env:
ANDROID_KEYSTORE_B64: ${{ secrets.ANDROID_KEYSTORE_B64 }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEYSTORE_PASS: ${{ secrets.ANDROID_KEYSTORE_PASS }}
- name: Pack
if: ${{ env.SHOULD_RUN == 'true' }}
run: ../../../.ci/pack.sh
working-directory: src/android/app
env:
UNPACKED: 1
- name: Upload
if: ${{ env.SHOULD_RUN == 'true' }}
uses: actions/upload-artifact@v4
with:
name: ${{ env.OS }}-${{ env.TARGET }}
path: src/android/app/artifacts/
docker:
runs-on: ubuntu-latest
container:
image: docker:dind
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install tools
run: apk add bash
- name: Fix git ownership
run: git config --global --add safe.directory .
- name: Build Docker image
run: ./.ci/docker.sh
- name: Move Docker image to artifacts directory
run: |
mkdir -p artifacts
mv build/*.dockerimage artifacts/
- name: Upload
uses: actions/upload-artifact@v4
with:
name: docker
path: artifacts/

3
.gitignore vendored
View File

@ -10,6 +10,9 @@ src/installer/*.exe
src/common/scm_rev.cpp
.travis.descriptor.json
# Docker image files
*.dockerimage
# Project/editor files
*.swp
*.kdev4

3
.gitmodules vendored
View File

@ -100,3 +100,6 @@
[submodule "spirv-headers"]
path = externals/spirv-headers
url = https://github.com/KhronosGroup/SPIRV-Headers
[submodule "externals/xxHash"]
path = externals/xxHash
url = https://github.com/Cyan4973/xxHash.git

View File

@ -1,7 +1,9 @@
![Azahar Emulator](https://azahar-emu.org/resources/images/logo/azahar-name-and-logo.svg)
![GitHub Release](https://img.shields.io/github/v/release/azahar-emu/azahar?label=Current%20Release)
![GitHub Downloads](https://img.shields.io/github/downloads/azahar-emu/azahar/total?logo=github&label=GitHub%20Downloads) <!-- ![Flathub Downloads](https://img.shields.io/flathub/downloads/org.azahar-emu.azahar?logo=Flathub&label=Flathub%20Downloads) -->
![GitHub Downloads](https://img.shields.io/github/downloads/azahar-emu/azahar/total?logo=github&label=GitHub%20Downloads)
![Google Play Downloads](https://playbadges.pavi2410.com/badge/downloads?id=io.github.lime3ds.android&pretty&label=Play%20Store%20Downloads)
![Flathub Downloads](https://img.shields.io/flathub/downloads/org.azahar_emu.Azahar?logo=flathub&label=Flathub%20Downloads)
![CI Build Status](https://github.com/azahar-emu/azahar/actions/workflows/build.yml/badge.svg)
<b>Azahar</b> is an open-source 3DS emulator project based on Citra.
@ -14,9 +16,11 @@ The goal of this project is to be the de-facto platform for future development.
### Windows
Download the latest release from [Releases](https://github.com/azahar-emu/azahar/releases).
Azahar is available as both an installer and a zip archive.
If you are unsure of whether you want to use MSYS2 or MSVC, use MSYS2.
Download the latest release in your preferred format from the [Releases](https://github.com/azahar-emu/azahar/releases) page.
If you are unsure of whether you want to use MSVC or MSYS2, use MSYS2.
---
@ -30,23 +34,30 @@ Alternatively, if you wish to download a build specifically for your Mac, you ca
- `macos-x86_64` for Intel Macs
---
### Android
The recommended method of downloading Azahar on Android is via the Google Play store:
There are two variants of Azahar available on Android, those being the Vanilla and Google Play builds.
The Vanilla build is technically superior, as it uses an alternative method of file management which is faster, but isn't permitted on the Google Play store.
For most users, we currently recommended downloading Azahar on Android via the Google Play Store for ease of accessibility:
<a href='https://play.google.com/store/apps/details?id=io.github.lime3ds.android'><img width='180' alt='Get it on Google Play' src='https://raw.githubusercontent.com/pioug/google-play-badges/06ccd9252af1501613da2ca28eaffe31307a4e6d/svg/English.svg'/></a>
Alternatively, you can install the app using Obtainium:
Alternatively, you can install the app using Obtainium, allowing you to use the Vanilla variant:
1. Download and install Obtainium from [here](https://github.com/ImranR98/Obtainium/releases) (use the file named `app-release.apk`)
2. Open Obtainium and click 'Add App'
3. Type `https://github.com/azahar-emu/azahar` into the 'App Source URL' section
4. Click 'Add'
5. Click 'Install'
5. Click 'Install', and select the preferred variant
If you wish, you can also simply install the latest APK from the [Releases](https://github.com/azahar-emu/azahar/releases) page.
Keep in mind that you will not recieve automatic updates when installing via the APK.
---
### Linux
The recommended format for using Azahar on Linux is the Flatpak available on Flathub:
@ -55,6 +66,13 @@ The recommended format for using Azahar on Linux is the Flatpak available on Fla
Azahar is also available as an AppImage on the [Releases](https://github.com/azahar-emu/azahar/releases) page.
There are two variants of the AppImage available, those being `azahar.AppImage` and `azahar-wayland.AppImage`.
If you are unsure of which variant to use, we recommend using the default `azahar.AppImage`. This is because of upstream issues in the Wayland ecosystem which may cause problems when running the emulator (e.g. [#1162](https://github.com/azahar-emu/azahar/issues/1162)).
Unless you explicitly require native Wayland support (e.g. you are running a system with no Xwayland), the non-Wayland variant is recommended.
The Flatpak build of Azahar also has native Wayland support disabled by default. If you require native Wayland support, it can be enabled using [Flatseal](https://flathub.org/en/apps/com.github.tchx84.Flatseal).
# Build instructions
@ -86,18 +104,23 @@ To do so, simply read https://github.com/azahar-emu/compatibility-list/blob/mast
Contributing compatibility data helps more accurately reflect the current capabilities of the emulator, so it would be highly appreciated if you could go through the reporting process after completing a game.
# Minimum requirements
Below are the minimum requirements to run Azahar:
### Desktop
```
Operating System: Windows 10 (64-bit), MacOS 13.4 (Ventura), or modern 64-bit Linux
CPU: x86-64/ARM64 CPU (Windows for ARM not supported). Single core performance higher than 1,800 on Passmark
CPU: x86-64/ARM64 CPU (Windows for ARM not supported).
Single core performance higher than 1,800 on Passmark.
SSE4.2 required on x86_64.
GPU: OpenGL 4.3 or Vulkan 1.1 support
Memory: 2GB of RAM. 4GB is recommended
```
### Android
```
Operating System: Android 9.0+ (64-bit)
Operating System: Android 10.0+ (64-bit)
CPU: Snapdragon 835 SoC or better
GPU: OpenGL ES 3.2 or Vulkan 1.1 support
Memory: 2GB of RAM. 4GB is recommended
@ -110,6 +133,7 @@ We share public roadmaps for upcoming releases in the form of GitHub milestones.
You can find these at https://github.com/azahar-emu/azahar/milestones.
# Join the conversation
We have a community Discord server where you can chat about the project, keep up to date with the latest announcements, or coordinate emulator development.
[![](https://dcbadge.vercel.app/api/server/4ZjMpAp3M6)](https://discord.gg/4ZjMpAp3M6)
Join at https://discord.gg/4ZjMpAp3M6

@ -1 +1 @@
Subproject commit a36decbe43d0e5a570ac3d3ba9a0b226dc832a17
Subproject commit eadcdfb84b6f3b95734e867d99fe16a9e8db717f

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1029
dist/languages/de.ts vendored

File diff suppressed because it is too large Load Diff

991
dist/languages/el.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

987
dist/languages/fi.ts vendored

File diff suppressed because it is too large Load Diff

1041
dist/languages/fr.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

993
dist/languages/id.ts vendored

File diff suppressed because it is too large Load Diff

1061
dist/languages/it.ts vendored

File diff suppressed because it is too large Load Diff

1071
dist/languages/ja_JP.ts vendored

File diff suppressed because it is too large Load Diff

1007
dist/languages/ko_KR.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

991
dist/languages/nb.ts vendored

File diff suppressed because it is too large Load Diff

1017
dist/languages/nl.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1069
dist/languages/pt_BR.ts vendored

File diff suppressed because it is too large Load Diff

1021
dist/languages/ro_RO.ts vendored

File diff suppressed because it is too large Load Diff

1029
dist/languages/ru_RU.ts vendored

File diff suppressed because it is too large Load Diff

1034
dist/languages/sv.ts vendored

File diff suppressed because it is too large Load Diff

1057
dist/languages/tr_TR.ts vendored

File diff suppressed because it is too large Load Diff

1007
dist/languages/vi_VN.ts vendored

File diff suppressed because it is too large Load Diff

1015
dist/languages/zh_CN.ts vendored

File diff suppressed because it is too large Load Diff

1003
dist/languages/zh_TW.ts vendored

File diff suppressed because it is too large Load Diff

1
dist/license.md vendored
View File

@ -16,6 +16,7 @@ qt_themes/default/icons/48x48/no_avatar.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/default/icons/48x48/star.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/default/icons/128x128/cartridge.png | CC0 1.0 | Designed by PabloMK7
qt_themes/qdarkstyle/icons/16x16/connected.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/qdarkstyle/icons/16x16/connected_notification.png | CC BY-ND 3.0 | https://icons8.com
qt_themes/qdarkstyle/icons/16x16/disconnected.png | CC BY-ND 3.0 | https://icons8.com

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -1,13 +1,16 @@
[Icon Theme]
Name=default
Comment=default theme
Directories=16x16,48x48,256x256
Directories=16x16,48x48,128x128,256x256
[16x16]
Size=16
[48x48]
Size=48
[128x128]
Size=128
[256x256]
Size=256

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -1,13 +1,16 @@
[Icon Theme]
Name=default
Comment=default theme
Directories=16x16,48x48,256x256
Directories=16x16,48x48,128x128,256x256
[16x16]
Size=16
[48x48]
Size=48
[128x128]
Size=128
[256x256]
Size=256

View File

@ -13,6 +13,7 @@
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
<file alias="128x128/cartridge.png">icons/128x128/cartridge.png</file>
<file alias="256x256/azahar.png">icons/256x256/azahar.png</file>
<file alias="48x48/star.png">icons/48x48/star.png</file>
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
@ -31,6 +32,7 @@
<file alias="48x48/no_avatar.png">icons_light/48x48/no_avatar.png</file>
<file alias="48x48/plus.png">icons_light/48x48/plus.png</file>
<file alias="48x48/sd_card.png">icons_light/48x48/sd_card.png</file>
<file alias="128x128/cartridge.png">icons_light/128x128/cartridge.png</file>
<file alias="256x256/azahar.png">icons_light/256x256/azahar.png</file>
<file alias="48x48/star.png">icons_light/48x48/star.png</file>
<file alias="256x256/plus_folder.png">icons_light/256x256/plus_folder.png</file>

View File

@ -0,0 +1,31 @@
# This Dockerfile assumes that it is being built from the project root directory, e.g.:
# $ docker build -f docker/azahar-room/Dockerfile -t azahar-room .
# --- Builder ----------------
FROM opensauce04/azahar-build-environment:latest AS builder
COPY . /var/azahar-src
RUN mkdir builddir && cd builddir && \
cmake /var/azahar-src -G Ninja \
-DENABLE_QT=OFF \
-DENABLE_TESTS=OFF \
-DENABLE_ROOM=ON \
-DENABLE_ROOM_STANDALONE=ON \
-DENABLE_OPENGL=OFF $( : "TODO: Can we disable these automatically when there's no frontend?") \
-DENABLE_VULKAN=OFF \
-DENABLE_SDL2=OFF \
-DENABLE_LIBUSB=OFF \
-DENABLE_CUBEB=OFF \
-DENABLE_OPENAL=OFF && \
ninja && \
mv bin/Release/azahar-room /usr/local/bin/ && \
cd .. && rm -rf builddir
# --- Final ------------------
FROM debian:trixie AS final
RUN apt-get update && apt-get -y full-upgrade
RUN apt-get install -y iputils-ping net-tools
COPY --from=builder /usr/local/bin/azahar-room /usr/local/bin/azahar-room

View File

@ -243,13 +243,8 @@ else()
)
target_link_libraries(zstd_seekable PUBLIC libzstd_static)
target_link_libraries(libzstd_static INTERFACE zstd_seekable)
add_library(zstd ALIAS libzstd_static)
install(TARGETS zstd_seekable
EXPORT zstdExports
)
add_library(zstd INTERFACE)
target_link_libraries(zstd INTERFACE libzstd_static zstd_seekable)
endif()
# ENet
@ -494,3 +489,17 @@ if (ENABLE_VULKAN)
add_subdirectory(libadrenotools)
endif()
endif()
set(XXHASH_BUILD_XXHSUM OFF)
add_subdirectory(xxHash/cmake_unofficial EXCLUDE_FROM_ALL)
target_compile_definitions(xxhash PRIVATE XXH_FORCE_MEMORY_ACCESS=2)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64")
target_compile_definitions(xxhash PRIVATE XXH_VECTOR=XXH_SSE2)
message(STATUS "Enabling SSE2 for xxHash")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|armv8")
target_compile_definitions(xxhash PRIVATE XXH_VECTOR=XXH_NEON)
message(STATUS "Enabling NEON for xxHash")
else()
target_compile_definitions(xxhash PRIVATE XXH_VECTOR=XXH_SCALAR)
message(STATUS "Disabling SIMD for xxHash")
endif()

2
externals/boost vendored

@ -1 +1 @@
Subproject commit 3c27c785ad0f8a742af02e620dc225673f3a12d8
Subproject commit 2c82bd787302398bcae990e3c9ab2b451284f4ca

2
externals/dynarmic vendored

@ -1 +1 @@
Subproject commit 278405bd71999ed3f3c77c5f78344a06fef798b9
Subproject commit 526227eebe1efff3fb14dbf494b9c5b44c2e9c1f

2
externals/teakra vendored

@ -1 +1 @@
Subproject commit 01db7cdd00aabcce559a8dddce8798dabb71949b
Subproject commit 3d697a18df504f4677b65129d9ab14c7c597e3eb

1
externals/xxHash vendored Submodule

@ -0,0 +1 @@
Subproject commit e626a72bc2321cd320e953a0ccf1584cad60f363

View File

@ -357,3 +357,4 @@ plus.png (Default, Dark) | CC0 1.0 | Designed by BreadFish64 fro
plus.png (Colorful, Colorful Dark) | CC BY-ND 3.0 | https://icons8.com
sd_card.png | CC BY-ND 3.0 | https://icons8.com
star.png | CC BY-ND 3.0 | https://icons8.com
cartridge.png | CC0 1.0 | Designed by PabloMK7

View File

@ -125,7 +125,7 @@ android {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
signingConfig = signingConfigs.getByName("debug")
isShrinkResources = true
isShrinkResources = true // TODO: Does this actually do anything when isDebuggable is enabled? -OS
isDebuggable = true
isJniDebuggable = true
proguardFiles(
@ -135,6 +135,22 @@ android {
isDefault = true
}
// Same as above, but with isDebuggable disabled.
// Primarily exists to allow development on hardened_malloc systems (e.g. GrapheneOS) without constantly tripping over years-old and seemingly harmless memory bugs.
// We should fix those bugs eventually, but for now this exists as a workaround to allow other work to be done.
register("relWithDebInfoLite") {
initWith(getByName("relWithDebInfo"))
signingConfig = signingConfigs.getByName("debug")
isDebuggable = false
installation {
enableBaselineProfile = false // Disabled by default when isDebuggable is true
}
lint {
checkReleaseBuilds = false // Ditto
// The name of this property is misleading, this doesn't actually disable linting for the `release` build.
}
}
// Signed by debug key disallowing distribution on Play Store.
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
debug {
@ -148,6 +164,18 @@ android {
flavorDimensions.add("version")
productFlavors {
register("vanilla") {
isDefault = true
dimension = "version"
versionNameSuffix = "-vanilla"
}
register("googlePlay") {
dimension = "version"
versionNameSuffix = "-googleplay"
}
}
externalNativeBuild {
cmake {
version = "3.25.0+"

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<!-- These permissions aren't allowed by Google. We asked, and they declined. -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:node="remove" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="remove" />
</manifest>

View File

@ -29,6 +29,8 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name="org.citra.citra_emu.CitraApplication"

View File

@ -7,10 +7,12 @@ package org.citra.citra_emu
import android.Manifest.permission
import android.app.Dialog
import android.content.DialogInterface
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.Surface
@ -18,11 +20,16 @@ import android.view.View
import android.widget.TextView
import androidx.annotation.Keep
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.citra.citra_emu.activities.EmulationActivity
import org.citra.citra_emu.utils.BuildUtil
import org.citra.citra_emu.utils.FileUtil
import org.citra.citra_emu.utils.Log
import org.citra.citra_emu.utils.RemovableStorageHelper
import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel
import java.lang.ref.WeakReference
import java.util.Date
@ -132,6 +139,12 @@ object NativeLibrary {
external fun createLogFile()
external fun logUserDirectory(directory: String)
/**
* Set the inserted cartridge that will appear
* in the home menu. Empty string to clear.
*/
external fun setInsertedCartridge(path: String)
/**
* Begins emulation.
*/
@ -267,6 +280,12 @@ object NativeLibrary {
canContinue = false
}
CoreError.ErrorN3DSApplication -> {
title = emulationActivity.getString(R.string.invalid_system_mode)
message = emulationActivity.getString(R.string.invalid_system_mode_message)
canContinue = false
}
CoreError.ErrorUnknown -> {
title = emulationActivity.getString(R.string.fatal_error)
message = emulationActivity.getString(R.string.fatal_error_message)
@ -589,6 +608,47 @@ object NativeLibrary {
*/
external fun logDeviceInfo()
enum class CompressStatus(val value: Int) {
SUCCESS(0),
COMPRESS_UNSUPPORTED(1),
COMPRESS_ALREADY_COMPRESSED(2),
COMPRESS_FAILED(3),
DECOMPRESS_UNSUPPORTED(4),
DECOMPRESS_NOT_COMPRESSED(5),
DECOMPRESS_FAILED(6),
INSTALLED_APPLICATION(7);
companion object {
fun fromValue(value: Int): CompressStatus =
CompressStatus.entries.first { it.value == value }
}
}
// Compression / Decompression
private external fun compressFileNative(inputPath: String?, outputPath: String): Int
fun compressFile(inputPath: String?, outputPath: String): CompressStatus {
return CompressStatus.fromValue(
compressFileNative(inputPath, outputPath)
)
}
private external fun decompressFileNative(inputPath: String?, outputPath: String): Int
fun decompressFile(inputPath: String?, outputPath: String): CompressStatus {
return CompressStatus.fromValue(
decompressFileNative(inputPath, outputPath)
)
}
external fun getRecommendedExtension(inputPath: String?, shouldCompress: Boolean): String
@Keep
@JvmStatic
fun onCompressProgress(total: Long, current: Long) {
CompressProgressDialogViewModel.update(total, current)
}
@Keep
@JvmStatic
fun createFile(directory: String, filename: String): Boolean =
@ -629,6 +689,38 @@ object NativeLibrary {
FileUtil.getFilesName(path)
}
@Keep
@JvmStatic
fun getUserDirectory(uriOverride: Uri? = null): String {
BuildUtil.assertNotGooglePlay()
val preferences: SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
val dirSep = "/"
val udUri = uriOverride ?:
preferences.getString("CITRA_DIRECTORY", "")!!.toUri()
val udPathSegment = udUri.lastPathSegment!!
val udVirtualPath = udPathSegment.substringAfter(":")
if (udPathSegment.startsWith("primary:")) { // User directory is located in primary storage
val primaryStoragePath = Environment.getExternalStorageDirectory().absolutePath
return primaryStoragePath + dirSep + udVirtualPath + dirSep
} else { // User directory probably located on a removable storage device
val storageIdString = udPathSegment.substringBefore(":")
val udRemovablePath = RemovableStorageHelper.getRemovableStoragePath(storageIdString)
if (udRemovablePath == null) {
android.util.Log.e("NativeLibrary",
"Unknown mount location for storage device '$storageIdString' (URI: $udUri)"
)
return ""
}
return udRemovablePath + dirSep + udVirtualPath + dirSep
}
}
@Keep
@JvmStatic
fun getSize(path: String): Long =
@ -638,6 +730,10 @@ object NativeLibrary {
FileUtil.getFileSize(path)
}
@Keep
@JvmStatic
fun getBuildFlavor(): String = BuildConfig.FLAVOR
@Keep
@JvmStatic
fun fileExists(path: String): Boolean =
@ -689,6 +785,24 @@ object NativeLibrary {
FileUtil.renameFile(path, destinationFilename)
}
@Keep
@JvmStatic
fun updateDocumentLocation(sourcePath: String, destinationPath: String): Boolean =
CitraApplication.documentsTree.updateDocumentLocation(sourcePath, destinationPath)
@Keep
@JvmStatic
fun moveFile(filename: String, sourceDirPath: String, destinationDirPath: String): Boolean =
if (FileUtil.isNativePath(sourceDirPath)) {
try {
CitraApplication.documentsTree.moveFile(filename, sourceDirPath, destinationDirPath)
} catch (e: Exception) {
false
}
} else {
FileUtil.moveFile(filename, sourceDirPath, destinationDirPath)
}
@Keep
@JvmStatic
fun deleteDocument(path: String): Boolean =
@ -702,6 +816,7 @@ object NativeLibrary {
ErrorSystemFiles,
ErrorSavestate,
ErrorArticDisconnected,
ErrorN3DSApplication,
ErrorUnknown
}

View File

@ -10,6 +10,7 @@ import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.InputDevice
import android.view.KeyEvent
@ -47,6 +48,7 @@ import org.citra.citra_emu.utils.FileBrowserHelper
import org.citra.citra_emu.utils.EmulationLifecycleUtil
import org.citra.citra_emu.utils.EmulationMenuSettings
import org.citra.citra_emu.utils.Log
import org.citra.citra_emu.utils.RefreshRateUtil
import org.citra.citra_emu.utils.ThemeUtil
import org.citra.citra_emu.viewmodel.EmulationViewModel
@ -82,6 +84,8 @@ class EmulationActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
requestWindowFeature(Window.FEATURE_NO_TITLE)
RefreshRateUtil.enforceRefreshRate(this, sixtyHz = true)
ThemeUtil.setTheme(this)
settingsViewModel.settings.loadSettings()
super.onCreate(savedInstanceState)
@ -338,6 +342,7 @@ class EmulationActivity : AppCompatActivity() {
preferences.getInt(InputBindingSetting.getInputAxisButtonKey(axis), -1)
val guestOrientation =
preferences.getInt(InputBindingSetting.getInputAxisOrientationKey(axis), -1)
val inverted = preferences.getBoolean(InputBindingSetting.getInputAxisInvertedKey(axis),false);
if (nextMapping == -1 || guestOrientation == -1) {
// Axis is unmapped
continue
@ -346,6 +351,8 @@ class EmulationActivity : AppCompatActivity() {
// Skip joystick wobble
value = 0f
}
if (inverted) value = -value;
when (nextMapping) {
NativeLibrary.ButtonType.STICK_LEFT -> {
axisValuesCirclePad[guestOrientation] = value

View File

@ -13,6 +13,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.content.Context
import android.content.SharedPreferences
import android.widget.TextView
import android.widget.ImageView
import android.widget.Toast
@ -57,13 +58,21 @@ import org.citra.citra_emu.utils.FileUtil
import org.citra.citra_emu.utils.GameIconUtils
import org.citra.citra_emu.viewmodel.GamesViewModel
class GameAdapter(private val activity: AppCompatActivity, private val inflater: LayoutInflater, private val openImageLauncher: ActivityResultLauncher<String>?) :
class GameAdapter(
private val activity: AppCompatActivity,
private val inflater: LayoutInflater,
private val openImageLauncher: ActivityResultLauncher<String>?,
private val onRequestCompressOrDecompress: ((inputPath: String, suggestedName: String, shouldCompress: Boolean) -> Unit)? = null
) :
ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()),
View.OnClickListener, View.OnLongClickListener {
private var lastClickTime = 0L
private var imagePath: String? = null
private var dialogShortcutBinding: DialogShortcutBinding? = null
private val preferences: SharedPreferences
get() = PreferenceManager.getDefaultSharedPreferences(CitraApplication.appContext)
fun handleShortcutImageResult(uri: Uri?) {
val path = uri?.toString()
if (path != null) {
@ -191,6 +200,11 @@ class GameAdapter(private val activity: AppCompatActivity, private val inflater:
binding.textGameTitle.text = game.title
binding.textCompany.text = game.company
binding.textGameRegion.text = game.regions
binding.imageCartridge.visibility = if (preferences.getString("insertedCartridge", "") != game.path) {
View.GONE
} else {
View.VISIBLE
}
val backgroundColorId =
if (
@ -340,12 +354,29 @@ class GameAdapter(private val activity: AppCompatActivity, private val inflater:
val bottomSheetDialog = BottomSheetDialog(context)
bottomSheetDialog.setContentView(bottomSheetView)
val insertable = game.isInsertable
val inserted = insertable && (preferences.getString("insertedCartridge", "") == game.path)
bottomSheetView.findViewById<TextView>(R.id.about_game_title).text = game.title
bottomSheetView.findViewById<TextView>(R.id.about_game_company).text = game.company
bottomSheetView.findViewById<TextView>(R.id.about_game_region).text = game.regions
bottomSheetView.findViewById<TextView>(R.id.about_game_id).text = context.getString(R.string.game_context_id) + " " + String.format("%016X", game.titleId)
bottomSheetView.findViewById<TextView>(R.id.about_game_filename).text = context.getString(R.string.game_context_file) + " " + game.filename
bottomSheetView.findViewById<TextView>(R.id.about_game_filetype).text = context.getString(R.string.game_context_type) + " " + game.fileType
val insertButton = bottomSheetView.findViewById<MaterialButton>(R.id.insert_cartridge_button)
insertButton.text = if (inserted) { context.getString(R.string.game_context_eject) } else { context.getString(R.string.game_context_insert) }
insertButton.visibility = if (insertable) View.VISIBLE else View.GONE
insertButton.setOnClickListener {
if (inserted) {
preferences.edit().putString("insertedCartridge", "").apply()
} else {
preferences.edit().putString("insertedCartridge", game.path).apply()
}
bottomSheetDialog.dismiss()
notifyItemRangeChanged(0, currentList.size)
}
GameIconUtils.loadGameIcon(activity, game, bottomSheetView.findViewById(R.id.game_icon))
bottomSheetView.findViewById<MaterialButton>(R.id.about_game_play).setOnClickListener {
@ -441,6 +472,27 @@ class GameAdapter(private val activity: AppCompatActivity, private val inflater:
bottomSheetDialog.dismiss()
}
val compressDecompressButton = bottomSheetView.findViewById<MaterialButton>(R.id.compress_decompress)
if (game.isInstalled) {
compressDecompressButton.setOnClickListener {
Toast.makeText(
context,
context.getString(R.string.compress_decompress_installed_app),
Toast.LENGTH_LONG
).show()
}
compressDecompressButton.alpha = 0.38f
} else {
compressDecompressButton.setOnClickListener {
val shouldCompress = !game.isCompressed
val recommendedExt = NativeLibrary.getRecommendedExtension(holder.game.path, shouldCompress)
val baseName = holder.game.filename.substringBeforeLast('.')
onRequestCompressOrDecompress?.invoke(holder.game.path, "$baseName.$recommendedExt", shouldCompress)
bottomSheetDialog.dismiss()
}
}
compressDecompressButton.text = context.getString(if (!game.isCompressed) R.string.compress else R.string.decompress)
bottomSheetView.findViewById<MaterialButton>(R.id.menu_button_open).setOnClickListener {
showOpenContextMenu(it, game)
}

View File

@ -63,4 +63,37 @@ enum class SecondaryDisplayLayout(val int: Int) {
return entries.firstOrNull { it.int == int } ?: NONE
}
}
}
enum class StereoWhichDisplay(val int: Int) {
// These must match what is defined in src/common/settings.h
NONE(0), // equivalent to StereoRenderOption = Off
BOTH(1),
PRIMARY_ONLY(2),
SECONDARY_ONLY(3);
companion object {
fun from(int: Int): StereoWhichDisplay {
return entries.firstOrNull { it.int == int } ?: NONE
}
}
}
enum class StereoMode(val int: Int) {
// These must match what is defined in src/common/settings.h
OFF(0),
SIDE_BY_SIDE(1),
SIDE_BY_SIDE_FULL(2),
ANAGLYPH(3),
INTERLACED(4),
REVERSE_INTERLACED (5),
CARDBOARD_VR (6);
companion object {
fun from(int: Int): StereoMode {
return entries.firstOrNull { it.int == int } ?: OFF
}
}
}

View File

@ -47,9 +47,18 @@ class SecondaryDisplay(val context: Context) : DisplayManager.DisplayListener {
private fun getExternalDisplay(context: Context): Display? {
val dm = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val internalId = context.display.displayId ?: Display.DEFAULT_DISPLAY
val displays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION)
return displays.firstOrNull { it.displayId != internalId && it.name != "HiddenDisplay" }
val currentDisplayId = context.display.displayId
val displays = dm.displays
val presDisplays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
return displays.firstOrNull {
val isPresentable = presDisplays.any { pd -> pd.displayId == it.displayId }
val isNotDefaultOrPresentable = it.displayId != Display.DEFAULT_DISPLAY || isPresentable
isNotDefaultOrPresentable &&
it.displayId != currentDisplayId &&
it.name != "HiddenDisplay" &&
it.state != Display.STATE_OFF &&
it.isValid
}
}
fun updateDisplay() {

View File

@ -19,6 +19,7 @@ enum class BooleanSetting(
INSTANT_DEBUG_LOG("instant_debug_log", Settings.SECTION_DEBUG, false),
ENABLE_RPC_SERVER("enable_rpc_server", Settings.SECTION_DEBUG, false),
CUSTOM_LAYOUT("custom_layout",Settings.SECTION_LAYOUT,false),
SWAP_EYES_3D("swap_eyes_3d",Settings.SECTION_RENDERER,false),
PERF_OVERLAY_ENABLE("performance_overlay_enable", Settings.SECTION_LAYOUT, false),
PERF_OVERLAY_SHOW_FPS("performance_overlay_show_fps", Settings.SECTION_LAYOUT, true),
PERF_OVERLAY_SHOW_FRAMETIME("performance_overlay_show_frame_time", Settings.SECTION_LAYOUT, false),
@ -51,7 +52,8 @@ enum class BooleanSetting(
USE_ARTIC_BASE_CONTROLLER("use_artic_base_controller", Settings.SECTION_CONTROLS, false),
UPRIGHT_SCREEN("upright_screen", Settings.SECTION_LAYOUT, false),
COMPRESS_INSTALLED_CIA_CONTENT("compress_cia_installs", Settings.SECTION_STORAGE, false),
ANDROID_HIDE_IMAGES("android_hide_images", Settings.SECTION_CORE, false);
ANDROID_HIDE_IMAGES("android_hide_images", Settings.SECTION_CORE, false),
APPLY_REGION_FREE_PATCH("apply_region_free_patch", Settings.SECTION_SYSTEM, true);
override var boolean: Boolean = defaultValue
@ -86,7 +88,8 @@ enum class BooleanSetting(
USE_ARTIC_BASE_CONTROLLER,
COMPRESS_INSTALLED_CIA_CONTENT,
ANDROID_HIDE_IMAGES,
PERF_OVERLAY_ENABLE // Works in overlay options, but not from the settings menu
PERF_OVERLAY_ENABLE, // Works in overlay options, but not from the settings menu
APPLY_REGION_FREE_PATCH
)
fun from(key: String): BooleanSetting? =

View File

@ -17,7 +17,7 @@ enum class IntSetting(
CAMERA_OUTER_RIGHT_FLIP("camera_outer_right_flip", Settings.SECTION_CAMERA, 0),
GRAPHICS_API("graphics_api", Settings.SECTION_RENDERER, 1),
RESOLUTION_FACTOR("resolution_factor", Settings.SECTION_RENDERER, 1),
STEREOSCOPIC_3D_MODE("render_3d", Settings.SECTION_RENDERER, 0),
STEREOSCOPIC_3D_MODE("render_3d", Settings.SECTION_RENDERER, 2),
STEREOSCOPIC_3D_DEPTH("factor_3d", Settings.SECTION_RENDERER, 0),
STEPS_PER_HOUR("steps_per_hour", Settings.SECTION_SYSTEM, 0),
CARDBOARD_SCREEN_SIZE("cardboard_screen_size", Settings.SECTION_LAYOUT, 85),
@ -53,6 +53,7 @@ enum class IntSetting(
ORIENTATION_OPTION("screen_orientation", Settings.SECTION_LAYOUT, 2),
TURBO_LIMIT("turbo_limit", Settings.SECTION_CORE, 200),
PERFORMANCE_OVERLAY_POSITION("performance_overlay_position", Settings.SECTION_LAYOUT, 0),
RENDER_3D_WHICH_DISPLAY("render_3d_which_display",Settings.SECTION_RENDERER,0),
ASPECT_RATIO("aspect_ratio", Settings.SECTION_LAYOUT, 0);
override var int: Int = defaultValue

View File

@ -16,6 +16,7 @@ import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.features.hotkeys.Hotkey
import org.citra.citra_emu.features.settings.model.AbstractSetting
import org.citra.citra_emu.features.settings.model.AbstractStringSetting
import org.citra.citra_emu.features.settings.model.Settings
class InputBindingSetting(
@ -161,12 +162,14 @@ class InputBindingSetting(
fun removeOldMapping() {
// Try remove all possible keys we wrote for this setting
val oldKey = preferences.getString(reverseKey, "")
(setting as AbstractStringSetting).string = ""
if (oldKey != "") {
preferences.edit()
.remove(abstractSetting.key) // Used for ui text
.remove(oldKey) // Used for button mapping
.remove(oldKey + "_GuestOrientation") // Used for axis orientation
.remove(oldKey + "_GuestButton") // Used for axis button
.remove(oldKey + "_Inverted") // used for axis inversion
.apply()
}
}
@ -200,7 +203,7 @@ class InputBindingSetting(
/**
* Helper function to write a gamepad axis mapping for the setting.
*/
private fun writeAxisMapping(axis: Int, value: Int) {
private fun writeAxisMapping(axis: Int, value: Int, inverted: Boolean) {
// Cleanup old mapping
removeOldMapping()
@ -208,6 +211,7 @@ class InputBindingSetting(
preferences.edit()
.putInt(getInputAxisOrientationKey(axis), if (isHorizontalOrientation()) 0 else 1)
.putInt(getInputAxisButtonKey(axis), value)
.putBoolean(getInputAxisInvertedKey(axis),inverted)
// Write next reverse mapping for future cleanup
.putString(reverseKey, getInputAxisKey(axis))
.apply()
@ -235,7 +239,7 @@ class InputBindingSetting(
*
* @param device InputDevice from which the input event originated.
* @param motionRange MotionRange of the movement
* @param axisDir Either '-' or '+' (currently unused)
* @param axisDir Either '-' or '+'
*/
fun onMotionInput(device: InputDevice, motionRange: MotionRange, axisDir: Char) {
if (!isAxisMappingSupported()) {
@ -251,8 +255,8 @@ class InputBindingSetting(
} else {
buttonCode
}
writeAxisMapping(motionRange.axis, button)
val uiString = "${device.name}: Axis ${motionRange.axis}"
writeAxisMapping(motionRange.axis, button, axisDir == '-')
val uiString = "${device.name}: Axis ${motionRange.axis}" + axisDir
value = uiString
}
@ -307,6 +311,11 @@ class InputBindingSetting(
*/
fun getInputAxisButtonKey(axis: Int): String = "${getInputAxisKey(axis)}_GuestButton"
/**
* Helper function to get the settings key for an whether a gamepad axis is inverted.
*/
fun getInputAxisInvertedKey(axis: Int): String = "${getInputAxisKey(axis)}_Inverted"
/**
* Helper function to get the settings key for an gamepad axis orientation.
*/

View File

@ -7,6 +7,7 @@ package org.citra.citra_emu.features.settings.ui
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
@ -37,6 +38,7 @@ import org.citra.citra_emu.features.settings.utils.SettingsFile
import org.citra.citra_emu.utils.SystemSaveGame
import org.citra.citra_emu.utils.DirectoryInitialization
import org.citra.citra_emu.utils.InsetsHelper
import org.citra.citra_emu.utils.RefreshRateUtil
import org.citra.citra_emu.utils.ThemeUtil
class SettingsActivity : AppCompatActivity(), SettingsActivityView {
@ -49,6 +51,8 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
override val settings: Settings get() = settingsViewModel.settings
override fun onCreate(savedInstanceState: Bundle?) {
RefreshRateUtil.enforceRefreshRate(this)
ThemeUtil.setTheme(this)
super.onCreate(savedInstanceState)

View File

@ -555,6 +555,21 @@ class SettingsAdapter(
return true
}
fun onInputBindingLongClick(setting: InputBindingSetting, position: Int): Boolean {
MaterialAlertDialogBuilder(context)
.setMessage(R.string.reset_setting_confirmation)
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
setting.removeOldMapping()
notifyItemChanged(position)
fragmentView.onSettingChanged()
fragmentView.loadSettingsList()
}
.setNegativeButton(android.R.string.cancel, null)
.show()
return true
}
fun onClickDisabledSetting(isRuntimeDisabled: Boolean) {
val titleId = if (isRuntimeDisabled)
R.string.setting_not_editable

View File

@ -16,6 +16,9 @@ import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.R
import org.citra.citra_emu.display.ScreenLayout
import org.citra.citra_emu.display.StereoMode
import org.citra.citra_emu.display.StereoWhichDisplay
import org.citra.citra_emu.features.settings.model.AbstractBooleanSetting
import org.citra.citra_emu.features.settings.model.AbstractIntSetting
import org.citra.citra_emu.features.settings.model.AbstractSetting
@ -44,7 +47,6 @@ import org.citra.citra_emu.utils.BirthdayMonth
import org.citra.citra_emu.utils.Log
import org.citra.citra_emu.utils.SystemSaveGame
import org.citra.citra_emu.utils.ThemeUtil
import org.citra.citra_emu.utils.EmulationMenuSettings
class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) {
private var menuTag: String? = null
@ -111,20 +113,24 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
}
/** Returns the portrait mode width */
private fun getWidth(): Int {
val dm = Resources.getSystem().displayMetrics;
return if (dm.widthPixels < dm.heightPixels)
dm.widthPixels
else
dm.heightPixels
private fun getDimensions(): IntArray {
val dm = Resources.getSystem().displayMetrics
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val wm = settingsActivity.windowManager.maximumWindowMetrics
val height = wm.bounds.height().coerceAtLeast(dm.heightPixels)
val width = wm.bounds.width().coerceAtLeast(dm.widthPixels)
intArrayOf(width, height)
} else {
intArrayOf(dm.widthPixels, dm.heightPixels)
}
}
private fun getHeight(): Int {
val dm = Resources.getSystem().displayMetrics;
return if (dm.widthPixels < dm.heightPixels)
dm.heightPixels
else
dm.widthPixels
private fun getSmallerDimension(): Int {
return getDimensions().min()
}
private fun getLargerDimension(): Int {
return getDimensions().max()
}
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
@ -354,6 +360,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.array.regionValues,
)
)
add(
SwitchSetting(
BooleanSetting.APPLY_REGION_FREE_PATCH,
R.string.apply_region_free_patch,
R.string.apply_region_free_patch_desc,
BooleanSetting.APPLY_REGION_FREE_PATCH.key,
BooleanSetting.APPLY_REGION_FREE_PATCH.defaultValue
)
)
val systemCountrySetting = object : AbstractShortSetting {
override var short: Short
get() {
@ -936,17 +951,30 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
)
add(HeaderSetting(R.string.stereoscopy))
add(
SingleChoiceSetting(
IntSetting.RENDER_3D_WHICH_DISPLAY,
R.string.render_3d_which_display,
R.string.render_3d_which_display_description,
R.array.render3dWhichDisplay,
R.array.render3dDisplayValues,
IntSetting.RENDER_3D_WHICH_DISPLAY.key,
IntSetting.RENDER_3D_WHICH_DISPLAY.defaultValue
)
)
add(
SingleChoiceSetting(
IntSetting.STEREOSCOPIC_3D_MODE,
R.string.render3d,
0,
R.string.render3d_description,
R.array.render3dModes,
R.array.render3dValues,
IntSetting.STEREOSCOPIC_3D_MODE.key,
IntSetting.STEREOSCOPIC_3D_MODE.defaultValue
IntSetting.STEREOSCOPIC_3D_MODE.defaultValue,
isEnabled = IntSetting.RENDER_3D_WHICH_DISPLAY.int != StereoWhichDisplay.NONE.int
)
)
add(
SliderSetting(
IntSetting.STEREOSCOPIC_3D_DEPTH,
@ -969,6 +997,17 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
)
)
add(
SwitchSetting(
BooleanSetting.SWAP_EYES_3D,
R.string.swap_eyes_3d,
R.string.swap_eyes_3d_description,
BooleanSetting.SWAP_EYES_3D.key,
BooleanSetting.SWAP_EYES_3D.defaultValue,
isEnabled = IntSetting.RENDER_3D_WHICH_DISPLAY.int != StereoWhichDisplay.NONE.int
)
)
add(HeaderSetting(R.string.cardboard_vr))
add(
SliderSetting(
@ -979,7 +1018,8 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
100,
"%",
IntSetting.CARDBOARD_SCREEN_SIZE.key,
IntSetting.CARDBOARD_SCREEN_SIZE.defaultValue.toFloat()
IntSetting.CARDBOARD_SCREEN_SIZE.defaultValue.toFloat(),
isEnabled = IntSetting.STEREOSCOPIC_3D_MODE.int == StereoMode.CARDBOARD_VR.int
)
)
add(
@ -991,7 +1031,8 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
100,
"%",
IntSetting.CARDBOARD_X_SHIFT.key,
IntSetting.CARDBOARD_X_SHIFT.defaultValue.toFloat()
IntSetting.CARDBOARD_X_SHIFT.defaultValue.toFloat(),
isEnabled = IntSetting.STEREOSCOPIC_3D_MODE.int == StereoMode.CARDBOARD_VR.int
)
)
add(
@ -1003,7 +1044,8 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
100,
"%",
IntSetting.CARDBOARD_Y_SHIFT.key,
IntSetting.CARDBOARD_Y_SHIFT.defaultValue.toFloat()
IntSetting.CARDBOARD_Y_SHIFT.defaultValue.toFloat(),
isEnabled = IntSetting.STEREOSCOPIC_3D_MODE.int == StereoMode.CARDBOARD_VR.int
)
)
@ -1137,7 +1179,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.array.aspectRatioValues,
IntSetting.ASPECT_RATIO.key,
IntSetting.ASPECT_RATIO.defaultValue,
isEnabled = IntSetting.SCREEN_LAYOUT.int == 1,
isEnabled = IntSetting.SCREEN_LAYOUT.int == ScreenLayout.SINGLE_SCREEN.int,
)
)
add(
@ -1185,7 +1227,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
"%",
FloatSetting.SECOND_SCREEN_OPACITY.key,
FloatSetting.SECOND_SCREEN_OPACITY.defaultValue,
isEnabled = IntSetting.SCREEN_LAYOUT.int == 5
isEnabled = IntSetting.SCREEN_LAYOUT.int == ScreenLayout.CUSTOM_LAYOUT.int
)
)
add(HeaderSetting(R.string.bg_color, R.string.bg_color_description))
@ -1396,7 +1438,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_x,
0,
0,
getHeight(),
getLargerDimension(),
"px",
IntSetting.LANDSCAPE_TOP_X.key,
IntSetting.LANDSCAPE_TOP_X.defaultValue.toFloat()
@ -1408,7 +1450,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_y,
0,
0,
getWidth(),
getSmallerDimension(),
"px",
IntSetting.LANDSCAPE_TOP_Y.key,
IntSetting.LANDSCAPE_TOP_Y.defaultValue.toFloat()
@ -1420,7 +1462,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_width,
0,
0,
getHeight(),
getLargerDimension(),
"px",
IntSetting.LANDSCAPE_TOP_WIDTH.key,
IntSetting.LANDSCAPE_TOP_WIDTH.defaultValue.toFloat()
@ -1432,7 +1474,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_height,
0,
0,
getWidth(),
getSmallerDimension(),
"px",
IntSetting.LANDSCAPE_TOP_HEIGHT.key,
IntSetting.LANDSCAPE_TOP_HEIGHT.defaultValue.toFloat()
@ -1445,7 +1487,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_x,
0,
0,
getHeight(),
getLargerDimension(),
"px",
IntSetting.LANDSCAPE_BOTTOM_X.key,
IntSetting.LANDSCAPE_BOTTOM_X.defaultValue.toFloat()
@ -1457,7 +1499,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_y,
0,
0,
getWidth(),
getSmallerDimension(),
"px",
IntSetting.LANDSCAPE_BOTTOM_Y.key,
IntSetting.LANDSCAPE_BOTTOM_Y.defaultValue.toFloat()
@ -1469,7 +1511,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_width,
0,
0,
getHeight(),
getLargerDimension(),
"px",
IntSetting.LANDSCAPE_BOTTOM_WIDTH.key,
IntSetting.LANDSCAPE_BOTTOM_WIDTH.defaultValue.toFloat()
@ -1481,7 +1523,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_height,
0,
0,
getWidth(),
getSmallerDimension(),
"px",
IntSetting.LANDSCAPE_BOTTOM_HEIGHT.key,
IntSetting.LANDSCAPE_BOTTOM_HEIGHT.defaultValue.toFloat()
@ -1501,7 +1543,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_x,
0,
0,
getWidth(),
getSmallerDimension(),
"px",
IntSetting.PORTRAIT_TOP_X.key,
IntSetting.PORTRAIT_TOP_X.defaultValue.toFloat()
@ -1513,7 +1555,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_y,
0,
0,
getHeight(),
getLargerDimension(),
"px",
IntSetting.PORTRAIT_TOP_Y.key,
IntSetting.PORTRAIT_TOP_Y.defaultValue.toFloat()
@ -1525,7 +1567,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_width,
0,
0,
getWidth(),
getSmallerDimension(),
"px",
IntSetting.PORTRAIT_TOP_WIDTH.key,
IntSetting.PORTRAIT_TOP_WIDTH.defaultValue.toFloat()
@ -1537,7 +1579,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_height,
0,
0,
getHeight(),
getLargerDimension(),
"px",
IntSetting.PORTRAIT_TOP_HEIGHT.key,
IntSetting.PORTRAIT_TOP_HEIGHT.defaultValue.toFloat()
@ -1550,7 +1592,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_x,
0,
0,
getWidth(),
getSmallerDimension(),
"px",
IntSetting.PORTRAIT_BOTTOM_X.key,
IntSetting.PORTRAIT_BOTTOM_X.defaultValue.toFloat()
@ -1562,7 +1604,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_y,
0,
0,
getHeight(),
getLargerDimension(),
"px",
IntSetting.PORTRAIT_BOTTOM_Y.key,
IntSetting.PORTRAIT_BOTTOM_Y.defaultValue.toFloat()
@ -1574,7 +1616,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_width,
0,
0,
getWidth(),
getSmallerDimension(),
"px",
IntSetting.PORTRAIT_BOTTOM_WIDTH.key,
IntSetting.PORTRAIT_BOTTOM_WIDTH.defaultValue.toFloat()
@ -1586,7 +1628,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
R.string.emulation_custom_layout_height,
0,
0,
getHeight(),
getLargerDimension(),
"px",
IntSetting.PORTRAIT_BOTTOM_HEIGHT.key,
IntSetting.PORTRAIT_BOTTOM_HEIGHT.defaultValue.toFloat()

View File

@ -51,7 +51,7 @@ class InputBindingSettingViewHolder(val binding: ListItemSettingBinding, adapter
override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) {
adapter.onLongClick(setting.setting!!, bindingAdapterPosition)
adapter.onInputBindingLongClick(setting, bindingAdapterPosition)
} else {
adapter.onClickDisabledSetting(!setting.isEditable)
}

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -60,7 +60,7 @@ class CitraDirectoryDialogFragment : DialogFragment() {
}
.setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int ->
if (!PermissionsHandler.hasWriteAccess(requireContext())) {
(requireActivity() as MainActivity)?.openCitraDirectory?.launch(null)
PermissionsHandler.compatibleSelectDirectory((requireActivity() as MainActivity).openCitraDirectory)
}
}
.show()

View File

@ -0,0 +1,89 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.fragments
import android.app.Dialog
import android.os.Bundle
import android.view.View
import android.widget.ProgressBar
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.Lifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import org.citra.citra_emu.R
import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel
import org.citra.citra_emu.NativeLibrary
class CompressProgressDialogFragment : DialogFragment() {
private lateinit var progressBar: ProgressBar
private var outputPath: String? = null
private var isCompressing: Boolean = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
isCompressing = it.getBoolean(ARG_IS_COMPRESSING, true)
outputPath = it.getString(ARG_OUTPUT_PATH)
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = layoutInflater.inflate(R.layout.dialog_compress_progress, null)
progressBar = view.findViewById(R.id.compress_progress)
val label = view.findViewById<android.widget.TextView>(R.id.compress_label)
label.text = if (isCompressing) getString(R.string.compressing) else getString(R.string.decompressing)
isCancelable = false
progressBar.isIndeterminate = true
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
combine(CompressProgressDialogViewModel.total, CompressProgressDialogViewModel.progress) { total, progress ->
total to progress
}.collectLatest { (total, progress) ->
if (total <= 0) {
progressBar.isIndeterminate = true
label.visibility = View.GONE
} else {
progressBar.isIndeterminate = false
label.visibility = View.VISIBLE
progressBar.max = total
progressBar.setProgress(progress, true)
}
}
}
}
val builder = MaterialAlertDialogBuilder(requireContext())
.setView(view)
.setCancelable(false)
.setNegativeButton(android.R.string.cancel) { _: android.content.DialogInterface, _: Int ->
outputPath?.let { path ->
NativeLibrary.deleteDocument(path)
}
}
return builder.show()
}
companion object {
const val TAG = "CompressProgressDialog"
private const val ARG_IS_COMPRESSING = "isCompressing"
private const val ARG_OUTPUT_PATH = "outputPath"
fun newInstance(isCompressing: Boolean, outputPath: String?): CompressProgressDialogFragment {
val frag = CompressProgressDialogFragment()
val args = Bundle()
args.putBoolean(ARG_IS_COMPRESSING, isCompressing)
args.putString(ARG_OUTPUT_PATH, outputPath)
frag.arguments = args
return frag
}
}
}

View File

@ -13,6 +13,7 @@ import android.content.IntentFilter
import android.content.SharedPreferences
import android.net.Uri
import android.os.BatteryManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@ -144,6 +145,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
}
}
val insertedCartridge = preferences.getString("insertedCartridge", "")
NativeLibrary.setInsertedCartridge(insertedCartridge ?: "")
try {
game = args.game ?: intentGame!!
} catch (e: NullPointerException) {
@ -1019,12 +1023,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
// Buttons that are disabled by default
var defaultValue = true
when (i) {
// TODO: Remove these magic numbers
6, 7, 12, 13, 14, 15 -> defaultValue = false
}
enabledButtons[i] = preferences.getBoolean("buttonToggle$i", defaultValue)
}
MaterialAlertDialogBuilder(requireContext())
val dialog = MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.emulation_toggle_controls)
.setMultiChoiceItems(
R.array.n3dsButtons, enabledButtons
@ -1036,6 +1041,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
binding.surfaceInputOverlay.refreshControls()
}
.show()
// Band-aid fix for strange dialog flickering issue
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val displayMetrics = requireActivity().windowManager.currentWindowMetrics
val displayHeight = displayMetrics.bounds.height()
// The layout visually breaks if we try to set the height directly rather than like this.
// Why? Fuck you, that's why!
val newAttributes = dialog.window?.attributes
newAttributes?.height = (displayHeight * 0.85f).toInt()
dialog.window?.attributes = newAttributes
}
}
private fun showAdjustScaleDialog(target: String) {

View File

@ -30,14 +30,17 @@ import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.transition.MaterialFadeThrough
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.adapters.GameAdapter
import org.citra.citra_emu.databinding.FragmentGamesBinding
import org.citra.citra_emu.features.settings.model.Settings
import org.citra.citra_emu.model.Game
import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel
import org.citra.citra_emu.viewmodel.GamesViewModel
import org.citra.citra_emu.viewmodel.HomeViewModel
@ -56,6 +59,58 @@ class GamesFragment : Fragment() {
gameAdapter.handleShortcutImageResult(uri)
}
private var shouldCompress: Boolean = true
private var pendingCompressInvocation: String? = null
companion object {
fun doCompression(fragment: Fragment, gamesViewModel: GamesViewModel, inputPath: String?, outputUri: Uri?, shouldCompress: Boolean) {
if (outputUri != null) {
CompressProgressDialogViewModel.reset()
val dialog = CompressProgressDialogFragment.newInstance(shouldCompress, outputUri.toString())
dialog.showNow(
fragment.requireActivity().supportFragmentManager,
CompressProgressDialogFragment.TAG
)
fragment.lifecycleScope.launch(Dispatchers.IO) {
val status = if (shouldCompress) {
NativeLibrary.compressFile(inputPath, outputUri.toString())
} else {
NativeLibrary.decompressFile(inputPath, outputUri.toString())
}
fragment.requireActivity().runOnUiThread {
dialog.dismiss()
val resId = when (status) {
NativeLibrary.CompressStatus.SUCCESS -> if (shouldCompress) R.string.compress_success else R.string.decompress_success
NativeLibrary.CompressStatus.COMPRESS_UNSUPPORTED -> R.string.compress_unsupported
NativeLibrary.CompressStatus.COMPRESS_ALREADY_COMPRESSED -> R.string.compress_already
NativeLibrary.CompressStatus.COMPRESS_FAILED -> R.string.compress_failed
NativeLibrary.CompressStatus.DECOMPRESS_UNSUPPORTED -> R.string.decompress_unsupported
NativeLibrary.CompressStatus.DECOMPRESS_NOT_COMPRESSED -> R.string.decompress_not_compressed
NativeLibrary.CompressStatus.DECOMPRESS_FAILED -> R.string.decompress_failed
NativeLibrary.CompressStatus.INSTALLED_APPLICATION -> R.string.compress_decompress_installed_app
}
MaterialAlertDialogBuilder(fragment.requireContext())
.setMessage(fragment.getString(resId))
.setPositiveButton(android.R.string.ok, null)
.show()
gamesViewModel.reloadGames(false)
}
}
}
}
}
private val onCompressDecompressLauncher = registerForActivityResult(
ActivityResultContracts.CreateDocument("application/octet-stream")
) { uri: Uri? ->
doCompression(this, gamesViewModel, pendingCompressInvocation, uri, shouldCompress)
pendingCompressInvocation = null
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterTransition = MaterialFadeThrough()
@ -81,7 +136,12 @@ class GamesFragment : Fragment() {
gameAdapter = GameAdapter(
requireActivity() as AppCompatActivity,
inflater,
openImageLauncher
openImageLauncher,
onRequestCompressOrDecompress = { inputPath, suggestedName, shouldCompress ->
pendingCompressInvocation = inputPath
onCompressDecompressLauncher.launch(suggestedName)
this.shouldCompress = shouldCompress
}
)
binding.gridGames.apply {

View File

@ -0,0 +1,81 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.fragments
import android.Manifest
import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.citra.citra_emu.R
import org.citra.citra_emu.ui.main.MainActivity
import org.citra.citra_emu.utils.BuildUtil
class GrantMissingFilesystemPermissionFragment : DialogFragment() {
private lateinit var mainActivity: MainActivity
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
BuildUtil.assertNotGooglePlay()
mainActivity = requireActivity() as MainActivity
isCancelable = false
val requestPermissionFunction =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
{
manageExternalStoragePermissionLauncher.launch(
Intent(
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
Uri.fromParts("package", mainActivity.packageName, null)
)
)
}
} else {
{ permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) }
}
return MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.filesystem_permission_warning)
.setMessage(R.string.filesystem_permission_lost)
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
requestPermissionFunction()
}
.show()
}
@RequiresApi(Build.VERSION_CODES.R)
private val manageExternalStoragePermissionLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (Environment.isExternalStorageManager()) {
return@registerForActivityResult
}
}
private val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
return@registerForActivityResult
}
}
companion object {
const val TAG = "GrantMissingFilesystemPermissionFragment"
fun newInstance(): GrantMissingFilesystemPermissionFragment {
BuildUtil.assertNotGooglePlay()
return GrantMissingFilesystemPermissionFragment()
}
}
}

View File

@ -159,7 +159,7 @@ class HomeSettingsFragment : Fragment() {
R.string.select_citra_user_folder,
R.string.select_citra_user_folder_home_description,
R.drawable.ic_home,
{ mainActivity?.openCitraDirectory?.launch(null) },
{ PermissionsHandler.compatibleSelectDirectory(mainActivity.openCitraDirectory) },
details = homeViewModel.userDir
),
HomeSetting(

View File

@ -7,11 +7,13 @@ package org.citra.citra_emu.fragments
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
@ -26,18 +28,19 @@ import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager
import info.debatty.java.stringsimilarity.Jaccard
import info.debatty.java.stringsimilarity.JaroWinkler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.R
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.adapters.GameAdapter
import org.citra.citra_emu.databinding.FragmentSearchBinding
import org.citra.citra_emu.model.Game
import org.citra.citra_emu.viewmodel.CompressProgressDialogViewModel
import org.citra.citra_emu.viewmodel.GamesViewModel
import org.citra.citra_emu.viewmodel.HomeViewModel
import java.time.temporal.ChronoField
import java.util.Locale
import android.net.Uri
import androidx.activity.result.contract.ActivityResultContracts
class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null
@ -53,6 +56,15 @@ class SearchFragment : Fragment() {
gameAdapter.handleShortcutImageResult(uri)
}
private var shouldCompress: Boolean = true
private var pendingCompressInvocation: String? = null
private val onCompressDecompressLauncher = registerForActivityResult(
ActivityResultContracts.CreateDocument("application/octet-stream")
) { uri: Uri? ->
GamesFragment.doCompression(this, gamesViewModel, pendingCompressInvocation, uri, shouldCompress)
pendingCompressInvocation = null
}
private lateinit var preferences: SharedPreferences
companion object {
@ -85,7 +97,13 @@ class SearchFragment : Fragment() {
gameAdapter = GameAdapter(
requireActivity() as AppCompatActivity,
inflater,
openImageLauncher
openImageLauncher,
onRequestCompressOrDecompress = { inputPath, suggestedName, shouldCompress ->
pendingCompressInvocation = inputPath
onCompressDecompressLauncher.launch(suggestedName)
this.shouldCompress = shouldCompress
}
)
binding.gridGamesSearch.apply {

View File

@ -13,21 +13,25 @@ import androidx.lifecycle.ViewModelProvider
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.citra.citra_emu.R
import org.citra.citra_emu.ui.main.MainActivity
import org.citra.citra_emu.utils.PermissionsHandler
import org.citra.citra_emu.viewmodel.HomeViewModel
class SelectUserDirectoryDialogFragment : DialogFragment() {
class SelectUserDirectoryDialogFragment(titleOverride: Int? = null, descriptionOverride: Int? = null) : DialogFragment() {
private lateinit var mainActivity: MainActivity
private val title = titleOverride ?: R.string.select_citra_user_folder
private val description = descriptionOverride ?: R.string.selecting_user_directory_without_write_permissions
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
mainActivity = requireActivity() as MainActivity
isCancelable = false
return MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.select_citra_user_folder)
.setMessage(R.string.selecting_user_directory_without_write_permissions)
.setTitle(title)
.setMessage(description)
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
mainActivity?.openCitraDirectoryLostPermission?.launch(null)
PermissionsHandler.compatibleSelectDirectory(mainActivity.openCitraDirectoryLostPermission)
}
.show()
}
@ -35,9 +39,10 @@ class SelectUserDirectoryDialogFragment : DialogFragment() {
companion object {
const val TAG = "SelectUserDirectoryDialogFragment"
fun newInstance(activity: FragmentActivity): SelectUserDirectoryDialogFragment {
fun newInstance(activity: FragmentActivity, titleOverride: Int? = null, descriptionOverride: Int? = null):
SelectUserDirectoryDialogFragment {
ViewModelProvider(activity)[HomeViewModel::class.java].setPickingUserDir(true)
return SelectUserDirectoryDialogFragment()
return SelectUserDirectoryDialogFragment(titleOverride, descriptionOverride)
}
}
}

View File

@ -11,11 +11,13 @@ import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
@ -30,7 +32,9 @@ import androidx.preference.PreferenceManager
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.MaterialFadeThrough
import org.citra.citra_emu.BuildConfig
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.adapters.SetupAdapter
import org.citra.citra_emu.databinding.FragmentSetupBinding
@ -41,6 +45,7 @@ import org.citra.citra_emu.model.PageState
import org.citra.citra_emu.model.SetupCallback
import org.citra.citra_emu.model.SetupPage
import org.citra.citra_emu.ui.main.MainActivity
import org.citra.citra_emu.utils.BuildUtil
import org.citra.citra_emu.utils.CitraDirectoryHelper
import org.citra.citra_emu.utils.GameHelper
import org.citra.citra_emu.utils.PermissionsHandler
@ -142,7 +147,56 @@ class SetupFragment : Fragment() {
false,
0,
pageButtons = mutableListOf<PageButton>().apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (!BuildUtil.isGooglePlayBuild) {
add(
PageButton(
R.drawable.ic_folder,
R.string.filesystem_permission,
R.string.filesystem_permission_description,
buttonAction = {
pageButtonCallback = it
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
manageExternalStoragePermissionLauncher.launch(
Intent(
android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
Uri.fromParts(
"package",
requireActivity().packageName,
null
)
)
)
} else {
permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
},
buttonState = {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (Environment.isExternalStorageManager()) {
ButtonState.BUTTON_ACTION_COMPLETE
} else {
ButtonState.BUTTON_ACTION_INCOMPLETE
}
} else {
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
ButtonState.BUTTON_ACTION_COMPLETE
} else {
ButtonState.BUTTON_ACTION_INCOMPLETE
}
}
},
isUnskippable = true,
hasWarning = true,
R.string.filesystem_permission_warning,
R.string.filesystem_permission_warning_description,
)
)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
add(
PageButton(
R.drawable.ic_notification,
@ -214,18 +268,35 @@ class SetupFragment : Fragment() {
)
},
) {
if (
var permissionsComplete =
// Microphone
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.RECORD_AUDIO
) == PackageManager.PERMISSION_GRANTED &&
// Camera
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED &&
// Notifications
NotificationManagerCompat.from(requireContext())
.areNotificationsEnabled()
) {
// External Storage
if (!BuildUtil.isGooglePlayBuild) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
permissionsComplete =
(permissionsComplete && Environment.isExternalStorageManager())
} else {
permissionsComplete =
(permissionsComplete && ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED)
}
}
if (permissionsComplete) {
PageState.PAGE_STEPS_COMPLETE
} else {
PageState.PAGE_STEPS_INCOMPLETE
@ -249,7 +320,7 @@ class SetupFragment : Fragment() {
R.string.select_citra_user_folder_description,
buttonAction = {
pageButtonCallback = it
openCitraDirectory.launch(null)
PermissionsHandler.compatibleSelectDirectory(openCitraDirectory)
},
buttonState = {
if (PermissionsHandler.hasWriteAccess(requireContext())) {
@ -452,6 +523,19 @@ class SetupFragment : Fragment() {
}
}
private fun showPermissionDeniedSnackbar() {
Snackbar.make(binding.root, R.string.permission_denied, Snackbar.LENGTH_LONG)
.setAnchorView(binding.buttonNext)
.setAction(R.string.grid_menu_core_settings) {
val intent =
Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", requireActivity().packageName, null)
intent.data = uri
startActivity(intent)
}
.show()
}
private val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
@ -459,16 +543,20 @@ class SetupFragment : Fragment() {
return@registerForActivityResult
}
Snackbar.make(binding.root, R.string.permission_denied, Snackbar.LENGTH_LONG)
.setAnchorView(binding.buttonNext)
.setAction(R.string.grid_menu_core_settings) {
val intent =
Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", requireActivity().packageName, null)
intent.data = uri
startActivity(intent)
}
.show()
showPermissionDeniedSnackbar()
}
// We can't use permissionLauncher because MANAGE_EXTERNAL_STORAGE is a special snowflake
@RequiresApi(Build.VERSION_CODES.R)
private val manageExternalStoragePermissionLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
BuildUtil.assertNotGooglePlay()
if (Environment.isExternalStorageManager()) {
checkForButtonState.invoke()
return@registerForActivityResult
}
showPermissionDeniedSnackbar()
}
private val openCitraDirectory = registerForActivityResult<Uri, Uri>(
@ -478,6 +566,17 @@ class SetupFragment : Fragment() {
return@registerForActivityResult
}
if (!BuildUtil.isGooglePlayBuild) {
if (NativeLibrary.getUserDirectory(result) == "") {
SelectUserDirectoryDialogFragment.newInstance(
mainActivity,
R.string.invalid_selection,
R.string.invalid_user_directory
).show(mainActivity.supportFragmentManager, SelectUserDirectoryDialogFragment.TAG)
return@registerForActivityResult
}
}
CitraDirectoryHelper(requireActivity(), true).showCitraDirectoryDialog(result, pageButtonCallback, checkForButtonState)
}

View File

@ -25,8 +25,10 @@ class Game(
val isInstalled: Boolean = false,
val isSystemTitle: Boolean = false,
val isVisibleSystemTitle: Boolean = false,
val isInsertable: Boolean = false,
val icon: IntArray? = null,
val fileType: String = "",
val isCompressed: Boolean = false,
val filename: String,
) : Parcelable {
val keyAddedToLibraryTime get() = "${filename}_AddedToLibraryTime"

View File

@ -37,6 +37,8 @@ class GameInfo(path: String) {
external fun getFileType(): String
external fun getIsInsertable(): Boolean
companion object {
@JvmStatic
private external fun initialize(path: String): Long

View File

@ -4,9 +4,13 @@
package org.citra.citra_emu.ui.main
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import android.view.WindowManager
@ -36,6 +40,8 @@ import androidx.work.WorkManager
import com.google.android.material.color.MaterialColors
import com.google.android.material.navigation.NavigationBarView
import kotlinx.coroutines.launch
import org.citra.citra_emu.BuildConfig
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R
import org.citra.citra_emu.contracts.OpenFileResultContract
import org.citra.citra_emu.databinding.ActivityMainBinding
@ -43,14 +49,17 @@ import org.citra.citra_emu.features.settings.model.Settings
import org.citra.citra_emu.features.settings.model.SettingsViewModel
import org.citra.citra_emu.features.settings.ui.SettingsActivity
import org.citra.citra_emu.features.settings.utils.SettingsFile
import org.citra.citra_emu.fragments.GrantMissingFilesystemPermissionFragment
import org.citra.citra_emu.fragments.SelectUserDirectoryDialogFragment
import org.citra.citra_emu.fragments.UpdateUserDirectoryDialogFragment
import org.citra.citra_emu.utils.BuildUtil
import org.citra.citra_emu.utils.CiaInstallWorker
import org.citra.citra_emu.utils.CitraDirectoryHelper
import org.citra.citra_emu.utils.CitraDirectoryUtils
import org.citra.citra_emu.utils.DirectoryInitialization
import org.citra.citra_emu.utils.FileBrowserHelper
import org.citra.citra_emu.utils.InsetsHelper
import org.citra.citra_emu.utils.RefreshRateUtil
import org.citra.citra_emu.utils.PermissionsHandler
import org.citra.citra_emu.utils.ThemeUtil
import org.citra.citra_emu.viewmodel.GamesViewModel
@ -66,6 +75,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
override var themeId: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
RefreshRateUtil.enforceRefreshRate(this)
val splashScreen = installSplashScreen()
CitraDirectoryUtils.attemptAutomaticUpdateDirectory()
splashScreen.setKeepOnScreenCondition {
@ -185,14 +196,53 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
if (!firstTimeSetup && !PermissionsHandler.hasWriteAccess(this) &&
!homeViewModel.isPickingUserDir.value
) {
if (firstTimeSetup) {
return
}
if (!BuildUtil.isGooglePlayBuild) {
fun requestMissingFilesystemPermission() =
GrantMissingFilesystemPermissionFragment.newInstance()
.show(supportFragmentManager, GrantMissingFilesystemPermissionFragment.TAG)
if (supportFragmentManager.findFragmentByTag(GrantMissingFilesystemPermissionFragment.TAG) == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
requestMissingFilesystemPermission()
}
} else {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
requestMissingFilesystemPermission()
}
}
}
}
if (homeViewModel.isPickingUserDir.value) {
return
}
if (!PermissionsHandler.hasWriteAccess(this)) {
SelectUserDirectoryDialogFragment.newInstance(this)
.show(supportFragmentManager, SelectUserDirectoryDialogFragment.TAG)
} else if (!firstTimeSetup && !homeViewModel.isPickingUserDir.value && CitraDirectoryUtils.needToUpdateManually()) {
return
} else if (CitraDirectoryUtils.needToUpdateManually()) {
UpdateUserDirectoryDialogFragment.newInstance(this)
.show(supportFragmentManager,UpdateUserDirectoryDialogFragment.TAG)
return
}
if (!BuildUtil.isGooglePlayBuild) {
if (supportFragmentManager.findFragmentByTag(SelectUserDirectoryDialogFragment.TAG) == null) {
if (NativeLibrary.getUserDirectory() == "") {
SelectUserDirectoryDialogFragment.newInstance(this)
.show(supportFragmentManager, SelectUserDirectoryDialogFragment.TAG)
}
}
}
}
@ -316,6 +366,17 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
return@registerForActivityResult
}
if (!BuildUtil.isGooglePlayBuild) {
if (NativeLibrary.getUserDirectory(result) == "") {
SelectUserDirectoryDialogFragment.newInstance(
this,
R.string.invalid_selection,
R.string.invalid_user_directory
).show(supportFragmentManager, SelectUserDirectoryDialogFragment.TAG)
return@registerForActivityResult
}
}
CitraDirectoryHelper(this@MainActivity, permissionsLost)
.showCitraDirectoryDialog(result, buttonState = {})
}

View File

@ -0,0 +1,25 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.utils
import org.citra.citra_emu.BuildConfig
object BuildUtil {
@Suppress("unused")
object BuildFlavors {
const val GOOGLEPLAY = "googlePlay"
const val VANILLA = "vanilla"
}
fun assertNotGooglePlay() {
if (isGooglePlayBuild) {
error("Non-GooglePlay code being called in GooglePlay build")
}
}
@Suppress("SimplifyBooleanWithConstants", "KotlinConstantConditions")
val isGooglePlayBuild =
BuildConfig.FLAVOR == BuildFlavors.GOOGLEPLAY
}

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -28,8 +28,8 @@ object DirectoryInitialization {
@Volatile
private var directoryState: DirectoryInitializationState? = null
var userPath: String? = null
val internalUserPath
get() = CitraApplication.appContext.getExternalFilesDir(null)!!.canonicalPath
val internalUserPath: String
get() = CitraApplication.appContext.filesDir.canonicalPath
private val isCitraDirectoryInitializationRunning = AtomicBoolean(false)
val context: Context get() = CitraApplication.appContext

View File

@ -6,10 +6,12 @@ package org.citra.citra_emu.utils
import android.net.Uri
import android.provider.DocumentsContract
import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.model.CheapDocument
import java.net.URLDecoder
import java.nio.file.Paths
import java.util.StringTokenizer
import java.util.concurrent.ConcurrentHashMap
@ -191,7 +193,7 @@ class DocumentsTree {
}
@Synchronized
fun renameFile(filepath: String, destinationFilename: String?): Boolean {
fun renameFile(filepath: String, destinationFilename: String): Boolean {
val node = resolvePath(filepath) ?: return false
try {
val filename = URLDecoder.decode(destinationFilename, FileUtil.DECODE_METHOD)
@ -203,6 +205,20 @@ class DocumentsTree {
}
}
@Synchronized
fun moveFile(filename: String, sourceDirPath: String, destDirPath: String): Boolean {
val sourceFileNode = resolvePath(sourceDirPath + "/" + filename) ?: return false
val sourceDirNode = resolvePath(sourceDirPath) ?: return false
val destDirNode = resolvePath(destDirPath) ?: return false
try {
val newUri = DocumentsContract.moveDocument(context.contentResolver, sourceFileNode.uri!!, sourceDirNode.uri!!, destDirNode.uri!!)
updateDocumentLocation("$sourceDirPath/$filename", "$destDirPath/$filename")
return true
} catch (e: Exception) {
error("[DocumentsTree]: Cannot move file, error: " + e.message)
}
}
@Synchronized
fun deleteDocument(filepath: String): Boolean {
val node = resolvePath(filepath) ?: return false
@ -219,6 +235,29 @@ class DocumentsTree {
}
}
@Synchronized
fun updateDocumentLocation(sourcePath: String, destinationPath: String): Boolean {
val sourceNode = resolvePath(sourcePath)
val newName = Paths.get(destinationPath).fileName.toString()
val parentPath = Paths.get(destinationPath).parent.toString()
val newParent = resolvePath(parentPath)
val newUri = (getUri(parentPath).toString() + "%2F$newName").toUri() // <- Is there a better way?
if (sourceNode == null || newParent == null) {
return false
}
sourceNode.parent!!.removeChild(sourceNode)
sourceNode.name = newName
sourceNode.parent = newParent
sourceNode.uri = newUri
newParent.addChild(sourceNode)
return true
}
@Synchronized
private fun resolvePath(filepath: String): DocumentsNode? {
root ?: return null

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -11,6 +11,7 @@ import android.net.Uri
import android.provider.DocumentsContract
import android.system.Os
import android.util.Pair
import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.model.CheapDocument
@ -434,6 +435,20 @@ object FileUtil {
return false
}
@JvmStatic
fun moveFile(filename: String, sourceDirUriString: String, destDirUriString: String): Boolean {
try {
val sourceFileUri = ("$sourceDirUriString%2F$filename").toUri()
val sourceDirUri = sourceDirUriString.toUri()
val destDirUri = destDirUriString.toUri()
DocumentsContract.moveDocument(context.contentResolver, sourceFileUri, sourceDirUri, destDirUri)
return true
} catch (e: Exception) {
Log.error("[FileUtil]: Cannot move file, error: " + e.message)
}
return false
}
@JvmStatic
fun deleteDocument(path: String): Boolean {
try {

View File

@ -88,8 +88,10 @@ object GameHelper {
isInstalled,
gameInfo?.isSystemTitle() ?: false,
gameInfo?.getIsVisibleSystemTitle() ?: false,
gameInfo?.getIsInsertable() ?: false,
gameInfo?.getIcon(),
gameInfo?.getFileType() ?: "",
gameInfo?.getFileType()?.contains("(Z)") ?: false,
if (FileUtil.isNativePath(filePath)) {
CitraApplication.documentsTree.getFilename(filePath)
} else {

View File

@ -8,6 +8,9 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.provider.DocumentsContract
import androidx.activity.result.ActivityResultLauncher
import androidx.preference.PreferenceManager
import androidx.documentfile.provider.DocumentFile
import org.citra.citra_emu.CitraApplication
@ -48,4 +51,17 @@ object PermissionsHandler {
fun setCitraDirectory(uriString: String?) =
preferences.edit().putString(CITRA_DIRECTORY, uriString).apply()
fun compatibleSelectDirectory(activityLauncher: ActivityResultLauncher<Uri?>) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
activityLauncher.launch(null)
} else {
val initialUri = DocumentsContract.buildRootUri(
"com.android.externalstorage.documents",
"primary"
)
activityLauncher.launch(initialUri)
}
}
}

View File

@ -0,0 +1,53 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.utils
import android.app.Activity
import android.os.Build
import androidx.annotation.RequiresApi
object RefreshRateUtil {
// Since Android 15, the OS automatically runs apps categorized as games with a
// 60hz refresh rate by default, regardless of the refresh rate set by the user.
//
// This function sets the refresh rate to either the maximum allowed refresh rate or
// 60hz depending on the value of the `sixtyHz` parameter.
//
// Note: This isn't always the maximum refresh rate that the display is *capable of*,
// but is instead the refresh rate chosen by the user in the Android system settings.
// For example, if the user selected 120hz in the settings, but the display is capable
// of 144hz, 120hz will be treated as the maximum within this function.
fun enforceRefreshRate(activity: Activity, sixtyHz: Boolean = false) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
return
}
val display = activity.display
val window = activity.window
display?.let {
// Get all supported modes and find the one with the highest refresh rate
val supportedModes = it.supportedModes
val maxRefreshRate = supportedModes.maxByOrNull { mode -> mode.refreshRate }
if (maxRefreshRate == null) {
return
}
var newModeId: Int?
if (sixtyHz) {
newModeId = supportedModes.firstOrNull { mode -> mode.refreshRate == 60f }?.modeId
} else {
// Set the preferred display mode to the one with the highest refresh rate
newModeId = maxRefreshRate.modeId
}
if (newModeId == null) {
return
}
window.attributes.preferredDisplayModeId = newModeId
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.utils
import org.citra.citra_emu.utils.BuildUtil
import java.io.File
object RemovableStorageHelper {
// This really shouldn't be necessary, but the Android API seemingly
// doesn't have a way of doing this?
fun getRemovableStoragePath(idString: String): String? {
BuildUtil.assertNotGooglePlay()
// On certain Android flavours the external storage mount location can
// vary, so add extra cases here if we discover them.
val possibleMountPaths = listOf("/mnt/media_rw/$idString", "/storage/$idString")
for (mountPath in possibleMountPaths) {
val pathFile = File(mountPath);
if (pathFile.exists()) {
// TODO: Cache which mount location is being used for the remainder of the
// session, as it should never change. -OS
return pathFile.absolutePath
}
}
return null
}
}

View File

@ -0,0 +1,33 @@
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
package org.citra.citra_emu.viewmodel
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
object CompressProgressDialogViewModel: ViewModel() {
private val _progress = MutableStateFlow(0)
val progress = _progress.asStateFlow()
private val _total = MutableStateFlow(0)
val total = _total.asStateFlow()
private val _message = MutableStateFlow("")
val message = _message.asStateFlow()
fun update(totalBytes: Long, currentBytes: Long) {
val percent = ((currentBytes * 100L) / totalBytes).coerceIn(0L, 100L).toInt()
_total.value = 100
_progress.value = percent
_message.value = ""
}
fun reset() {
_progress.value = 0
_total.value = 0
_message.value = ""
}
}

View File

@ -175,7 +175,8 @@ void Config::ReadValues() {
ReadSetting("Renderer", Settings::values.custom_second_layer_opacity);
ReadSetting("Renderer", Settings::values.delay_game_render_thread_us);
ReadSetting("Renderer", Settings::values.disable_right_eye_render);
ReadSetting("Renderer", Settings::values.swap_eyes_3d);
ReadSetting("Renderer", Settings::values.render_3d_which_display);
// Layout
// Somewhat inelegant solution to ensure layout value is between 0 and 5 on read
// since older config files may have other values
@ -262,6 +263,7 @@ void Config::ReadValues() {
ReadSetting("System", Settings::values.plugin_loader_enabled);
ReadSetting("System", Settings::values.allow_plugin_loader);
ReadSetting("System", Settings::values.steps_per_hour);
ReadSetting("System", Settings::values.apply_region_free_patch);
// Camera
using namespace Service::CAM;

View File

@ -170,13 +170,23 @@ bg_green =
custom_second_layer_opacity =
# Whether and how Stereoscopic 3D should be rendered
# 0 (default): Off, 1: Side by Side, 2: Reverse Side by Side, 3: Anaglyph, 4: Interlaced, 5: Reverse Interlaced, 6: Cardboard VR
# 0: Off, 1: Half Width Side by Side, 2 (default): Full Width Side by Side, 3: Anaglyph, 4: Interlaced, 5: Reverse Interlaced, 6: Cardboard VR
# 0 is no longer supported in the interface, as using render_3d_which_display = 0 has the same effect, but supported here for backwards compatibility
render_3d =
# Change 3D Intensity
# 0 - 255: Intensity. 0 (default)
factor_3d =
# Swap Eyes in 3d
# true: Swap eyes, false (default): Do not swap eyes
swap_eyes_3d =
# Which Display to render 3d mode to
# 0 (default) - None. Equivalent to render_3d=0
# 1: Both, 2: Primary Only, 3: Secondary Only
render_3d_which_display =
# The name of the post processing shader to apply.
# Loaded from shaders if render_3d is off or side by side.
pp_shader_name =
@ -413,6 +423,11 @@ steps_per_hour =
plugin_loader =
allow_plugin_loader =
# Apply region free patch to installed applications
# Patches the region of installed applications to be region free, so that they always appear on the home menu.
# 0: Disabled, 1 (default): Enabled
apply_region_free_patch =
[Camera]
# Which camera engine to use for the right outer camera
# blank: a dummy camera that always returns black image

View File

@ -25,6 +25,7 @@ struct GameInfoData {
bool loaded = false;
bool is_encrypted = false;
std::string file_type = "";
bool is_insertable = false;
};
GameInfoData* GetNewGameInfoData(const std::string& path) {
@ -89,6 +90,7 @@ GameInfoData* GetNewGameInfoData(const std::string& path) {
gid->is_encrypted = is_encrypted;
gid->title_id = program_id;
gid->file_type = Loader::GetFileTypeString(loader->GetFileType(), loader->IsFileCompressed());
gid->is_insertable = loader->GetFileType() == Loader::FileType::CCI;
return gid;
}
@ -222,7 +224,7 @@ jboolean Java_org_citra_citra_1emu_model_GameInfo_getIsVisibleSystemTitle(JNIEnv
return false;
}
return smdh->flags & Loader::SMDH::Flags::Visible;
return smdh->flags.visible;
}
jstring Java_org_citra_citra_1emu_model_GameInfo_getFileType(JNIEnv* env, jobject obj) {
@ -230,4 +232,7 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getFileType(JNIEnv* env, jobjec
return ToJString(env, file_type);
}
jboolean Java_org_citra_citra_1emu_model_GameInfo_getIsInsertable(JNIEnv* env, jobject obj) {
return GetPointer(env, obj)->is_insertable;
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2019 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -40,6 +40,7 @@ static jfieldID s_game_info_pointer;
static jclass s_disk_cache_progress_class;
static jmethodID s_disk_cache_load_progress;
static jmethodID s_compress_progress_method;
static std::unordered_map<VideoCore::LoadCallbackStage, jobject> s_java_load_callback_stages;
static jclass s_cia_install_helper_class;
@ -131,6 +132,10 @@ jmethodID GetDiskCacheLoadProgress() {
return s_disk_cache_load_progress;
}
jmethodID GetCompressProgressMethod() {
return s_compress_progress_method;
}
jobject GetJavaLoadCallbackStage(VideoCore::LoadCallbackStage stage) {
const auto it = s_java_load_callback_stages.find(stage);
ASSERT_MSG(it != s_java_load_callback_stages.end(), "Invalid LoadCallbackStage: {}", stage);
@ -205,6 +210,8 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
s_disk_cache_load_progress = env->GetStaticMethodID(
s_disk_cache_progress_class, "loadProgress",
"(Lorg/citra/citra_emu/utils/DiskShaderCacheProgress$LoadCallbackStage;II)V");
s_compress_progress_method =
env->GetStaticMethodID(s_native_library_class, "onCompressProgress", "(JJ)V");
// Initialize LoadCallbackStage map
const auto to_java_load_callback_stage = [env,
load_callback_stage_class](const std::string& stage) {

View File

@ -1,4 +1,4 @@
// Copyright 2019 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -40,6 +40,7 @@ jfieldID GetGameInfoPointer();
jclass GetDiskCacheProgressClass();
jmethodID GetDiskCacheLoadProgress();
jmethodID GetCompressProgressMethod();
jobject GetJavaLoadCallbackStage(VideoCore::LoadCallbackStage stage);
jclass GetCiaInstallHelperClass();

View File

@ -34,10 +34,12 @@
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "common/zstd_compression.h"
#include "core/core.h"
#include "core/frontend/applets/default_applets.h"
#include "core/frontend/camera/factory.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/nfc/nfc.h"
#include "core/hw/unique_data.h"
#include "core/loader/loader.h"
@ -74,6 +76,17 @@ namespace {
ANativeWindow* s_surface;
ANativeWindow* s_secondary_surface;
enum class CompressionStatus : jint {
Success = 0,
Compress_Unsupported = 1,
Compress_AlreadyCompressed = 2,
Compress_Failed = 3,
Decompress_Unsupported = 4,
Decompress_NotCompressed = 5,
Decompress_Failed = 6,
Installed_Application = 7,
};
std::shared_ptr<Common::DynamicLibrary> vulkan_library{};
std::unique_ptr<EmuWindow_Android> window;
std::unique_ptr<EmuWindow_Android> secondary_window;
@ -88,6 +101,8 @@ std::mutex paused_mutex;
std::mutex running_mutex;
std::condition_variable running_cv;
std::string inserted_cartridge;
} // Anonymous namespace
static jobject ToJavaCoreError(Core::System::ResultStatus result) {
@ -95,6 +110,7 @@ static jobject ToJavaCoreError(Core::System::ResultStatus result) {
{Core::System::ResultStatus::ErrorSystemFiles, "ErrorSystemFiles"},
{Core::System::ResultStatus::ErrorSavestate, "ErrorSavestate"},
{Core::System::ResultStatus::ErrorArticDisconnected, "ErrorArticDisconnected"},
{Core::System::ResultStatus::ErrorN3DSApplication, "ErrorN3DSApplication"},
{Core::System::ResultStatus::ErrorUnknown, "ErrorUnknown"},
};
@ -134,7 +150,10 @@ static void TryShutdown() {
secondary_window->DoneCurrent();
}
Core::System::GetInstance().Shutdown();
Core::System& system{Core::System::GetInstance()};
system.Shutdown();
system.EjectCartridge();
window.reset();
if (secondary_window) {
@ -165,6 +184,10 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
Core::System& system{Core::System::GetInstance()};
if (!inserted_cartridge.empty()) {
system.InsertCartridge(inserted_cartridge);
}
const auto graphics_api = Settings::values.graphics_api.GetValue();
EGLContext* shared_context;
switch (graphics_api) {
@ -463,6 +486,163 @@ jstring Java_org_citra_citra_1emu_NativeLibrary_getHomeMenuPath(JNIEnv* env,
return ToJString(env, "");
}
static CompressionStatus GetCompressFileInfo(Loader::AppLoader::CompressFileInfo& out_info,
size_t& out_frame_size, const std::string& filepath,
bool compress) {
if (Service::FS::IsInstalledApplication(filepath)) {
return CompressionStatus::Installed_Application;
}
Loader::AppLoader::CompressFileInfo compress_info{};
compress_info.is_supported = false;
size_t frame_size{};
auto loader = Loader::GetLoader(filepath);
if (loader) {
compress_info = loader->GetCompressFileInfo();
frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_FRAME_SIZE;
} else {
bool is_compressed = false;
if (Service::AM::CheckCIAToInstall(filepath, is_compressed, compress ? true : false) ==
Service::AM::InstallStatus::Success) {
compress_info.is_supported = true;
compress_info.is_compressed = is_compressed;
compress_info.recommended_compressed_extension = "zcia";
compress_info.recommended_uncompressed_extension = "cia";
compress_info.underlying_magic = std::array<u8, 4>({'C', 'I', 'A', '\0'});
frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_CIA_FRAME_SIZE;
if (compress) {
auto meta_info = Service::AM::GetCIAInfos(filepath);
if (meta_info.Succeeded()) {
const auto& meta_info_val = meta_info.Unwrap();
std::vector<u8> value(sizeof(Service::AM::TitleInfo));
memcpy(value.data(), &meta_info_val.first, sizeof(Service::AM::TitleInfo));
compress_info.default_metadata.emplace("titleinfo", value);
if (meta_info_val.second) {
value.resize(sizeof(Loader::SMDH));
memcpy(value.data(), meta_info_val.second.get(), sizeof(Loader::SMDH));
compress_info.default_metadata.emplace("smdh", value);
}
}
}
}
}
if (!compress_info.is_supported) {
LOG_ERROR(Frontend,
"Error {} file {}, the selected file is not a compatible 3DS ROM format or is "
"encrypted.",
compress ? "compressing" : "decompressing", filepath);
return compress ? CompressionStatus::Compress_Unsupported
: CompressionStatus::Decompress_Unsupported;
}
if (compress_info.is_compressed && compress) {
LOG_ERROR(Frontend, "Error compressing file {}, the selected file is already compressed",
filepath);
return CompressionStatus::Compress_AlreadyCompressed;
}
if (!compress_info.is_compressed && !compress) {
LOG_ERROR(Frontend,
"Error decompressing file {}, the selected file is already decompressed",
filepath);
return CompressionStatus::Decompress_NotCompressed;
}
out_info = compress_info;
out_frame_size = frame_size;
return CompressionStatus::Success;
}
jint Java_org_citra_citra_1emu_NativeLibrary_compressFileNative(JNIEnv* env, jobject obj,
jstring j_input_path,
jstring j_output_path) {
const std::string input_path = GetJString(env, j_input_path);
const std::string output_path = GetJString(env, j_output_path);
Loader::AppLoader::CompressFileInfo compress_info{};
size_t frame_size{};
CompressionStatus stat = GetCompressFileInfo(compress_info, frame_size, input_path, true);
if (stat != CompressionStatus::Success) {
return static_cast<jint>(stat);
}
auto progress = [](std::size_t processed, std::size_t total) {
JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
IDCache::GetCompressProgressMethod(), static_cast<jlong>(total),
static_cast<jlong>(processed));
};
bool success =
FileUtil::CompressZ3DSFile(input_path, output_path, compress_info.underlying_magic,
frame_size, progress, compress_info.default_metadata);
if (!success) {
FileUtil::Delete(output_path);
return static_cast<jint>(CompressionStatus::Compress_Failed);
}
return static_cast<jint>(CompressionStatus::Success);
}
jint Java_org_citra_citra_1emu_NativeLibrary_decompressFileNative(JNIEnv* env, jobject obj,
jstring j_input_path,
jstring j_output_path) {
const std::string input_path = GetJString(env, j_input_path);
const std::string output_path = GetJString(env, j_output_path);
Loader::AppLoader::CompressFileInfo compress_info{};
size_t frame_size{};
CompressionStatus stat = GetCompressFileInfo(compress_info, frame_size, input_path, false);
if (stat != CompressionStatus::Success) {
return static_cast<jint>(stat);
}
auto progress = [](std::size_t processed, std::size_t total) {
JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
IDCache::GetCompressProgressMethod(), static_cast<jlong>(total),
static_cast<jlong>(processed));
};
bool success = FileUtil::DeCompressZ3DSFile(input_path, output_path, progress);
if (!success) {
FileUtil::Delete(output_path);
return static_cast<jint>(CompressionStatus::Decompress_Failed);
}
return static_cast<jint>(CompressionStatus::Success);
}
jstring Java_org_citra_citra_1emu_NativeLibrary_getRecommendedExtension(
JNIEnv* env, jobject obj, jstring j_input_path, jboolean j_should_compress) {
const std::string input_path = GetJString(env, j_input_path);
std::string compressed_ext;
std::string uncompressed_ext;
auto loader = Loader::GetLoader(input_path);
if (loader) {
auto compress_info = loader->GetCompressFileInfo();
if (compress_info.is_supported) {
compressed_ext = compress_info.recommended_compressed_extension;
uncompressed_ext = compress_info.recommended_uncompressed_extension;
}
} else {
bool is_compressed = false;
if (Service::AM::CheckCIAToInstall(input_path, is_compressed, true) ==
Service::AM::InstallStatus::Success) {
compressed_ext = "zcia";
uncompressed_ext = "cia";
}
}
if (compressed_ext.empty()) {
return env->NewStringUTF("");
}
return env->NewStringUTF(j_should_compress ? compressed_ext.c_str() : uncompressed_ext.c_str());
}
void Java_org_citra_citra_1emu_NativeLibrary_setUserDirectory(JNIEnv* env,
[[maybe_unused]] jobject obj,
jstring j_directory) {
@ -919,4 +1099,9 @@ jlong Java_org_citra_citra_1emu_NativeLibrary_playTimeManagerGetCurrentTitleId(J
return ptm_current_title_id;
}
void Java_org_citra_citra_1emu_NativeLibrary_setInsertedCartridge(JNIEnv* env, jobject obj,
jstring path) {
inserted_cartridge = GetJString(env, path);
}
} // extern "C"

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -28,6 +28,16 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/image_cartridge"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/cartridge"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"

View File

@ -45,7 +45,8 @@
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:textSize="15sp"
android:textStyle="bold" app:layout_constraintStart_toStartOf="parent"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Application Title" />
@ -120,12 +121,13 @@
<com.google.android.material.button.MaterialButton
android:id="@+id/about_game_play"
style="@style/Widget.Material3.Button.Icon"
android:layout_width="0dp"
android:layout_width="142dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:contentDescription="@string/play"
android:focusedByDefault="true"
android:text="@string/play"
android:textAlignment="center"
app:icon="@drawable/ic_play" />
<com.google.android.material.button.MaterialButton
@ -166,7 +168,6 @@
android:layout_marginTop="16dp"
android:gravity="start|center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/horizontal_layout">
@ -179,6 +180,37 @@
android:contentDescription="@string/cheats"
android:text="@string/cheats" />
<com.google.android.material.button.MaterialButton
android:id="@+id/insert_cartridge_button"
style="@style/Widget.Material3.Button.TonalButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/compress_decompress"
style="@style/Widget.Material3.Button.TonalButton.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:contentDescription="@string/compress"
android:text="@string/compress" />
</LinearLayout>
<LinearLayout
android:id="@+id/compress_tray"
style="@style/ThemeOverlay.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="start|center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/game_button_tray">
</LinearLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:id="@+id/compress_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodyMedium"
android:textColor="?attr/colorOnSurface"
android:visibility="visible"
android:paddingBottom="8dp" />
<ProgressBar
android:id="@+id/compress_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="48dp"
android:indeterminate="false"
android:max="100"
android:progress="0"
android:layout_marginTop="8dp" />
</LinearLayout>

View File

@ -122,8 +122,6 @@
<string name="input_dialog_description">Pulsa o mou un botó/palanca.</string>
<string name="input_binding">Assignació de botons</string>
<string name="input_binding_description">Prem o mou una entrada per enllaçar-la a %1$s.</string>
<string name="input_binding_description_vertical_axis">Mou el joystick amunt o avall.</string>
<string name="input_binding_description_horizontal_axis">Mou el joystick a esquerra o dreta.</string>
<string name="button_home">HOME</string>
<string name="button_swap">Intercanviar Pantalles</string>
<string name="button_turbo">Turbo</string>
@ -217,21 +215,18 @@
<string name="spirv_shader_gen_description">Usa SPIR-V en vez de GLSL per a emetre el fragment de ombrejador utilitzat per a emular PICA.</string>
<string name="disable_spirv_optimizer">Desativar l\'optimitzador SPIR-V</string>
<string name="disable_spirv_optimizer_description">Desactiva la passada d\'optimització SPIR-V reduint considerablement el quequeig i afectant poc el rendiment.</string>
<string name="async_shaders">Activar compilació de ombrejadors asíncrona</string>
<string name="async_shaders_description">Compila els ombrejats en segón pla per a reduir les aturades durant la partida.
S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="linear_filtering">Filtre Linear</string>
<string name="linear_filtering_description">Activa el filtre linear, que fa que els gràfics del joc es vegen més suaus.</string>
<string name="texture_filter_name">Filtre de Textures</string>
<string name="texture_filter_description">Millora l\'aspecte visual de les aplicacions aplicant un filtre a les textures. Els filtres compatibles són Anime4K, Ultrafast, Bicubic, ScaleForce, xBRZ Freescale i MMPX.</string>
<string name="delay_render_thread">Endarrerir fil de renderitzat del joc</string>
<string name="delay_render_thread_description">Retarda el fil de renderitzat del joc en enviar dades a la GPU. Ajuda a solucionar problemes de rendiment en les (poques) aplicacions amb velocitats de fotogrames dinàmiques.</string>
<string name="advanced">Avançat</string>
<string name="texture_sampling_name">Mostreig de Textures</string>
<string name="texture_sampling_description">Sobreescriu el filtre de mostreig usat en jocs. Pot ser útil en uns certs casos de jocs amb baix rendiment en pujar la resolució. Si no estàs segur, possa\'l en Controlat per Joc.</string>
<string name="shaders_accurate_mul">Multiplicació Precisa</string>
<string name="shaders_accurate_mul_description">Usa multiplicacions més precises en els ombrejos de Hardware, que podrien arreglar uns certs problemes gràfics. Quan s\'active, el rendiment es reduirà.</string>
<string name="asynchronous_gpu">Activar Emulació Asíncrona de la GPU</string>
<string name="asynchronous_gpu_description">Usa un fil separat per a emular la GPU de manera asíncrona. Quan s\'active, el rendiment millorarà.</string>
<string name="frame_limit_enable">Límit de velocitat</string>
<string name="frame_limit_enable_description">Quan s\'active, la velocitat d\'emulació estarà limitada a un percentatge determinat de la velocitat normal. Quan es desactive, la velocitat d\'emulació no tindrà límit i la tecla d\'accés ràpid de velocitat turbo no funcionarà.</string>
@ -286,7 +281,6 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="audio_volume">Volum</string>
<string name="audio_stretch">Extensió d\'Àudio</string>
<string name="audio_stretch_description">Estén l\'àudio per a reduir les aturades. Quan s\'active, la latència d\'àudio s\'incrementarà i reduirà un poc el rendiment.</string>
<string name="realtime_audio">Activar àudio en temps real</string>
<string name="realtime_audio_description">Ajusta la velocitat de reproducció d\'àudio per a compensar les caigudes en la velocitat d\'emulació de quadres. Això significa que l\'àudio es reproduirà a velocitat completa fins i tot quan la velocitat de quadres del joc siga baixa. Pot causar problemes de desincronització d\'àudio.</string>
<string name="audio_input_type">Dispositiu d\'entrada d\'àudio</string>
<string name="sound_output_mode">Mode d\'eixida de l\'àudio</string>
@ -298,12 +292,9 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="hw_shaders_description">Usa el hardware per a emular els ombrejadors de 3DS. Quan s\'active, el rendiment millorarà notablement.</string>
<string name="cpu_clock_speed">Velocitat de rellotge de la CPU</string>
<string name="vsync">Activar Sincronització Vertical</string>
<string name="vsync_description">Sincronitza els quadres per segon del joc amb la taxa de refresc del teu dispositiu.</string>
<string name="renderer_debug">Renderitzador de depuració</string>
<string name="renderer_debug_description">Arxiva informació addicional gràfica relacionada amb la depuració. Quan està activada, el rendiment dels jocs serà reduït considerablement</string>
<string name="instant_debug_log">Guardar l\'eixida del registre en cada missatge</string>
<string name="instant_debug_log_description">Envia immediatament el registre de depuració a un arxiu. Usa-ho si Azahar falla i es talla l\'eixida del registre.</string>
<string name="delay_start_lle_modules">Inici diferit amb mòduls LLE</string>
<string name="delay_start_lle_modules_description">Retarda l\'inici de l\'aplicació quan els mòduls LLE estan habilitats.</string>
<string name="deterministic_async_operations">Operacions asíncrones deterministes</string>
<string name="deterministic_async_operations_description">Fa que les operacions asíncrones siguen deterministes per a la depuració. Habilitar esta opció pot causar bloquejos.</string>
@ -523,7 +514,6 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="fatal_error">Error Fatal</string>
<string name="fatal_error_message">Ha ocorregut un error fatal. Mira el registre per a més detalls.\nSeguir amb l\'emulació podria resultar en diversos penges i problemes.</string>
<string name="unsupported_encrypted">Aplicació cifrada no suportada</string>
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Preparant ombrejadors</string>
<string name="building_shaders">Construint ombrejadors</string>
@ -550,35 +540,11 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="game_context_id">ID:</string>
<string name="game_context_file">Fitxer:</string>
<string name="game_context_type">Tipus:</string>
<!-- Performance Overlay settings -->
<string name="performance_overlay_show">Mostrar informació de rendiment</string>
<string name="performance_overlay_options">Informació de rendiment</string>
<string name="performance_overlay_enable">Activar informació de rendiment</string>
<string name="performance_overlay_options_description">Configura la informació de rendiment</string>
<string name="overlay_show_fps">Mostrar FPS</string>
<string name="overlay_show_fps_description">Mostra els fotogrames per segon actuals.</string>
<string name="overlay_show_frametime">Mostrar duració de fotogrames</string>
<string name="overlay_show_frametime_description">Mostra la duració actual de cada fotograma.</string>
<string name="overlay_show_speed">Mostrar velocitat</string>
<string name="overlay_show_speed_description">Mostra el percentatge de velocitat d\'emulació actual.</string>
<string name="overlay_show_app_ram_usage">Mostrar l\'ús de memòria de l\'aplicació</string>
<string name="overlay_show_app_ram_usage_description">Mostra la quantitat de memòria RAM que esta usant l\'emulador.</string>
<string name="overlay_show_available_ram">Mostrar memòria disponible</string>
<string name="overlay_show_available_ram_description">Mostra la quantitat de memòria RAM que esta disponible.</string>
<string name="overlay_show_battery_temp">Mostrar la temperatura de la bateria</string>
<string name="overlay_show_battery_temp_description">Mostra la temperatura actual de la bateria en Celsius i Fahrenheit.</string>
<string name="overlay_position">Posició de la informació</string>
<string name="overlay_position_description">Tria on la informació de rendiment serà mostrada en la pantalla.</string>
<string name="overlay_position_top_left">Dalt a l\'esquerra</string>
<string name="overlay_position_top_right">Dalt a la dreta</string>
<string name="overlay_position_bottom_left">Avall a l\'esquerra</string>
<string name="overlay_position_bottom_right">Avall a la dreta</string>
<string name="overlay_position_center_top">Dalt al centre</string>
<string name="overlay_position_center_bottom">Avall al centre</string>
<string name="overlay_background">Fons de la informació</string>
<string name="overlay_background_description">Agrega un fons darrere de la informació per a fer-la més llegible.</string>
<!-- Cheats -->
<string name="cheats">Trucs</string>
<string name="cheats_add">Afegir trucs</string>
@ -681,7 +647,6 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<!-- Render 3D modes -->
<string name="side_by_side">De costat a costat</string>
<string name="reverse_side_by_side">De costat a costat invers</string>
<string name="anaglyph">Anàglifo</string>
<string name="interlaced">Entrellaçat</string>
<string name="reverse_interlaced">Entrellaçat invers</string>
@ -870,4 +835,4 @@ S\'esperen errors gràfics temporals quan estigue activat.</string>
<string name="emulation_occupied_quicksave_slot">Guardat ràpid - %1$tF %1$tR</string>
<string name="quickload_not_found">Guardat ràpid no disponible.</string>
</resources>
</resources>

View File

@ -67,10 +67,14 @@
<string name="give_permission">Giv tilladelse</string>
<string name="notification_warning">Vil du droppe at give tilladelse til meddelelser?</string>
<string name="notification_warning_description">Azahar vil ikke være i stand til at give dig meddelelse om vigtige oplysninger.</string>
<string name="filesystem_permission_warning">Manglende tilladelser</string>
<string name="filesystem_permission_warning_description">Azahar kræver tilladelse til at administrere filer på denne enhed for at kunne gemme og administrere dens data.\n\nGiv venligst tilladelsen \"Filsystem\", før du fortsætter.</string>
<string name="camera_permission">Kamera</string>
<string name="camera_permission_description">Giv kameraet tilladelse nedenfor til at efterligne 3DS-kameraet.</string>
<string name="microphone_permission">Mikrofon</string>
<string name="microphone_permission_description">Giv mikrofonen tilladelse nedenfor til at efterligne 3DS-mikrofonen.</string>
<string name="filesystem_permission">Filsystem</string>
<string name="filesystem_permission_description">Giv filsystemet tilladelse nedenfor for at tillade Azahar at gemme filer.</string>
<string name="permission_denied">Tilladelse nægtet</string>
<string name="add_games_warning">Vil du droppe at vælge applikationsmappen?</string>
<string name="add_games_warning_description">Software vil ikke blive vist på applikationslisten, hvis en mappe ikke er valgt.</string>
@ -90,6 +94,9 @@
<string name="cannot_skip">Du kan ikke springe opsætningen af brugermappen over </string>
<string name="cannot_skip_directory_description">Dette trin er påkrævet for at Azahar kan fungere. Vælg en mappe og så kan du fortsætte.</string>
<string name="selecting_user_directory_without_write_permissions">Du har mistet skrivetilladelse i din <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">brugerdata</a> mappe, hvor gemte tilstande og anden information er gemt. Dette kan ske efter en app- eller Android-opdatering. Vælg venligst mappen for at give tilladelse igen, så du kan fortsætte.</string>
<string name="invalid_selection">Ugyldigt valg</string>
<string name="invalid_user_directory">Valget af brugermappe var ugyldigt.\nVælg venligst brugermappen igen, og sørg for at navigere til den fra roden af din enheds lager.</string>
<string name="filesystem_permission_lost">Azahar har mistet tilladelsen til at administrere filer på denne enhed. Dette kan ske efter nogle app- eller Android-opdateringer. Giv venligst denne tilladelse igen på den næste skærm for at fortsætte med at bruge appen.</string>
<string name="set_up_theme_settings">Temaindstillinger</string>
<string name="setup_theme_settings_description">Konfigurer dine temaindstillinger for Azahar.</string>
<string name="setup_set_theme">Indstil tema</string>
@ -122,8 +129,8 @@
<string name="input_dialog_description">Tryk på eller flyt et input.</string>
<string name="input_binding">Inputbinding</string>
<string name="input_binding_description">Tryk på eller flyt et input for at binde det til %1$s.</string>
<string name="input_binding_description_vertical_axis">Bevæg joysticket op eller ned.</string>
<string name="input_binding_description_horizontal_axis">Bevæg joysticket til venstre eller højre</string>
<string name="input_binding_description_vertical_axis">Bevæg joysticket ned</string>
<string name="input_binding_description_horizontal_axis">Bevæg joysticket til højre</string>
<string name="button_home">HOME</string>
<string name="button_swap">Byt skærme</string>
<string name="button_turbo">Turbo</string>
@ -162,6 +169,8 @@
<string name="username">Brugernavn</string>
<string name="new_3ds">Ny 3DS tilstand</string>
<string name="lle_applets">Brug LLE Applets (hvis installeret)</string>
<string name="apply_region_free_patch">Anvend regionfri programrettelse på installerede programmer</string>
<string name="apply_region_free_patch_desc">Opdaterer regionen for installerede programmer, så de altid vises i startmenuen.</string>
<string name="enable_required_online_lle_modules">Aktiver nødvendige LLE moduler til onlinefunktioner (hvis installeret)</string>
<string name="enable_required_online_lle_modules_desc">Aktiverer de LLE moduler, der kræves til online multiplayer, eShop-adgang osv.</string>
<string name="clock">Ur</string>
@ -193,6 +202,10 @@
<string name="region_mismatch">Advarsel om uoverensstemmelse i region</string>
<string name="region_mismatch_emulated">Landeindstillingen er ikke gyldig for det valgte emulerede område.</string>
<string name="region_mismatch_console">Landeindstillingen er ikke gyldig for den aktuelle forbundne konsol.</string>
<string name="storage">Lager</string>
<string name="compress_cia_installs">Komprimer installeret CIA-indhold</string>
<string name="compress_cia_installs_description">Komprimerer indholdet af CIA-filer, når de installeres på det emulerede SD-kort. Påvirker kun CIA-indhold, der installeres, når indstillingen er aktiveret.</string>
<!-- Camera settings strings -->
<string name="inner_camera">Indre kamera</string>
<string name="outer_left_camera">Ydre venstre kamera</string>
@ -219,7 +232,7 @@
<string name="linear_filtering_description">Aktiverer lineær filtrering, hvilket får spillets grafik til at se mere jævnt ud.</string>
<string name="texture_filter_name">Teksturfilter</string>
<string name="texture_filter_description">Forbedrer det visuelle i applikationer ved at anvende et filter på teksturer. De understøttede filtre er Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale og MMPX.</string>
<string name="delay_render_thread">Forsinket spillets renderingstråd</string>
<string name="delay_render_thread">Forsink spillets renderingstråd</string>
<string name="delay_render_thread_description">Forsink spillets remderingstråd, når den sender data til GPU\'en. Hjælper med ydeevneproblemer i de (meget få) applikationer med dynamiske framerates.</string>
<string name="advanced">Avanceret</string>
<string name="texture_sampling_name">Tekstur sampling</string>
@ -232,6 +245,8 @@
<string name="frame_limit_enable_description">Når aktiveret, vil emuleringshastigheden være begrænset til en specificeret procentdel af normal hastighed. Hvis deaktiveret, vil emuleringshastigheden være ubegrænset, og genvejstasten for turbohastighed vil ikke fungere.</string>
<string name="frame_limit_slider">Begræns hastighedsprocent</string>
<string name="frame_limit_slider_description">Angiver procentdelen emuleringshastigheden skal begrænses til. Med standardværdien på 100% vil emulering være begrænset til normal hastighed. Værdier højere eller lavere vil øge eller mindske hastighedsgrænsen.</string>
<string name="android_hide_images">Skjul 3DS-afbildninger fra Android</string>
<string name="android_hide_images_description">Forhindre at Android indekserer og viser billeder fra 3DS-kamera, skærmbilleder og brugerdefinerede teksturer i galleriet. Din enhed skal muligvis genstartes, efter at du har ændret denne indstilling, for at den træder i kraft.</string>
<string name="turbo_limit">Turbohastighedsgrænse</string>
<string name="turbo_limit_description">Grænse for emuleringens hastighed bruges, når turbo-genvejstasten er aktiv.</string>
<string name="expand_to_cutout_area">Anvend området ved frontkamera</string>
@ -253,10 +268,18 @@
<string name="debug_warning">Advarsel: Ændringer i disse indstillinger vil gøre emuleringen langsommere</string>
<string name="stereoscopy">Stereoskopi</string>
<string name="render3d">Stereoskopisk 3D-tilstand</string>
<string name="render3d_description">Vælg den stereoskopiske 3D-tilstand til 3D-gengivelse. Side om side-tilstande er mest almindelige i moderne brug. Anaglyf- og interlaced-tilstande vil altid gælde for alle tilsluttede skærme.</string>
<string name="factor3d">Dybde</string>
<string name="factor3d_description">Angiver værdien af 3D-skyderen. Denne bør sættes højere end 0 %, når stereoskopisk 3D-tilstand er aktiveret.\nBemærk: Dybdeværdier over 100 % er ikke muligt på rigtig hardware og kan forårsage grafiske problemer</string>
<string name="disable_right_eye_render">Deaktiver rendering af højre øje</string>
<string name="disable_right_eye_render_description">Forbedrer ydeevnen betydeligt i nogle applikationer, men kan forårsage flimren i andre.</string>
<string name="swap_eyes_3d">Skift øjne</string>
<string name="swap_eyes_3d_description">Bytter om på hvilket øje, der skal se hvilken side. Kombineret med side om side-tilstanden er det muligt at se 3D ved at krydse øjnene!</string>
<string name="render_3d_which_display">Gengiv stereoskopisk 3D</string>
<string name="render_3d_which_display_description">Om stereoskopisk 3D skal aktiveres, og på hvilke skærme. Indstillingerne for en enkel skærm er kun relevant, når flere skærme er tilsluttet.</string>
<string name="render_3d_which_display_both">Til (alle skærme)</string>
<string name="render_3d_which_display_primary">Til (kun primær skærm)</string>
<string name="render_3d_which_display_secondary">Til (kun sekundær skærm)</string>
<string name="cardboard_vr">Cardboard VR</string>
<string name="cardboard_screen_size">Cardboard skærmstørrelse</string>
<string name="cardboard_screen_size_description">Skalerer skærmen til en procentdel af dens oprindelige størrelse.</string>
@ -293,12 +316,12 @@
<string name="hw_shaders_description">Bruger hardware til at efterligne 3DS shaders. Når det er aktiveret, vil spillets ydeevne blive væsentligt forbedret.</string>
<string name="cpu_clock_speed">CPU Clock hastighed</string>
<string name="vsync">Aktiver V-Sync</string>
<string name="vsync_description">Synkroniserer spillets frame rate med opdateringshastigheden på din enhed.</string>
<string name="vsync_description">Synkroniserer spillets billedhastighed med din enheds opdateringshastighed. Kan forårsage yderligere inputforsinkelse, men kan reducere tearing i nogle tilfælde.</string>
<string name="renderer_debug">Fejlsøg renderingen</string>
<string name="renderer_debug_description">Log yderligere grafikrelaterede fejlfindingsoplysninger. Når det er aktiveret, vil spillets ydeevne blive væsentligt reduceret.</string>
<string name="instant_debug_log">Tøm loggen for alle beskeder</string>
<string name="instant_debug_log">Tøm loggen ved hver besked</string>
<string name="instant_debug_log_description">Overfør øjeblikkeligt fejlretningsloggen til fil. Brug dette, hvis Azahar går ned, og logoutputtet afbrydes.</string>
<string name="delay_start_lle_modules">Forsinket start med LLE moduler</string>
<string name="delay_start_lle_modules">Forsink start med LLE moduler</string>
<string name="delay_start_lle_modules_description">Forsinker starten af appen, når LLE moduler er aktiveret.</string>
<string name="deterministic_async_operations">Deterministiske asynkrone operationer</string>
<string name="deterministic_async_operations_description">Gør asynkrone operationer deterministiske for fejlretning. Aktivering af dette kan forårsage at programmet fryser fast.</string>
@ -396,18 +419,24 @@
<string name="emulation_configure_controls">Konfigurer kontroller</string>
<string name="emulation_edit_layout">Rediger layout</string>
<string name="emulation_done">Færdig</string>
<string name="emulation_button_sliding">Knap flytning</string>
<string name="emulation_button_sliding_disabled">Hold den oprindeligt trykkede knap nede</string>
<string name="emulation_button_sliding_enabled">Hold den aktuelt nede knap nede</string>
<string name="emulation_button_sliding_alternative">Hold den oprindelige og den aktuelt nedtrykkede knap nede</string>
<string name="emulation_toggle_controls">Skift kontrol</string>
<string name="emulation_control_scale">Juster skala</string>
<string name="emulation_control_scale_global">Global skala</string>
<string name="emulation_control_scale_reset_all">Nulstil alle</string>
<string name="emulation_control_opacity">Juster opacitet</string>
<string name="emulation_control_joystick_rel_center">Relativt stick centrum</string>
<string name="emulation_control_dpad_slide_enable">D-Pad glidning</string>
<string name="emulation_control_dpad_slide_enable">D-Pad flytning</string>
<string name="emulation_open_settings">Åbn Indstillinger</string>
<string name="emulation_open_cheats">Åbn snydekoder</string>
<string name="emulation_aspect_ratio">Billedformat</string>
<string name="emulation_switch_screen_layout">Landskab skærmlayout</string>
<string name="emulation_switch_portrait_layout">Portræt skærmlayout</string>
<string name="emulation_switch_secondary_layout">Layout af sekundær skærm</string>
<string name="emulation_switch_secondary_layout_description">Layoutet, der bruges af en tilsluttet sekundær skærm, kablet eller trådløs (Chromecast, Miracast)</string>
<string name="emulation_screen_layout_largescreen">Stor skærm</string>
<string name="emulation_screen_layout_portrait">Portræt</string>
<string name="emulation_screen_layout_single">Enkelt skærm</string>
@ -415,7 +444,15 @@
<string name="emulation_screen_layout_hybrid">Hybrid skærme</string>
<string name="emulation_screen_layout_original">Original</string>
<string name="emulation_portrait_layout_top_full">Standard</string>
<string name="emulation_secondary_display_default">Systemstandard (spejl)</string>
<string name="emulation_screen_layout_custom">Brugerdefineret layout</string>
<string name="bg_color">Baggrundsfarve</string>
<string name="bg_color_description">Farven, der vises bag skærmene under emulering, repræsenteret som en RGB-værdi.</string>
<string name="bg_red">Rød</string>
<string name="bg_green">Grøn</string>
<string name="bg_blue">Blå</string>
<string name="second_screen_opacity">Brugerdefineret layout skærmopacitet for anden skærm</string>
<string name="second_screen_opacity_description">Opaciteten af den anden 3DS-skærm, når der bruges et brugerdefineret skærmlayout. Nyttig, hvis den anden skærm skal placeres oven på den første skærm.</string>
<string name="emulation_small_screen_position">Position for lille skærm</string>
<string name="small_screen_position_description">Hvor skal den lille skærm vises i forhold til den store i storskærmslayout?</string>
<string name="small_screen_position_top_right">Øverst til højre</string>
@ -511,6 +548,8 @@
<string name="fatal_error">Fatal fejl</string>
<string name="fatal_error_message">Der opstod en fatal fejl. Kontroller loggen for detaljer.\nFortsat emulering kan resultere i nedbrud og fejl.</string>
<string name="unsupported_encrypted">Ikke understøttet krypteret applikation</string>
<string name="invalid_system_mode">Ugyldig systemtilstand</string>
<string name="invalid_system_mode_message">Nye 3DS-eksklusive applikationer kan ikke indlæses uden at aktivere den nye 3DS-tilstand.</string>
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Forberedelse af shaders</string>
@ -535,33 +574,39 @@
<string name="create_shortcut">Opret genvej</string>
<string name="shortcut_name_empty">Genvejsnavnet må ikke være tomt</string>
<string name="shortcut_image_stretch_toggle">Stræk for at tilpasse billedet</string>
<string name="game_context_id">ID:</string>
<string name="game_context_file">Fil:</string>
<string name="game_context_type">Type:</string>
<string name="game_context_insert">Indsæt kassette</string>
<string name="game_context_eject">Udtag kassette</string>
<!-- Performance Overlay settings -->
<string name="performance_overlay_show">Vis ydelsesoverlejring</string>
<string name="performance_overlay_options">Ydelsesoverlejring</string>
<string name="performance_overlay_enable">Aktivér ydelsesoverlejring</string>
<string name="performance_overlay_options_description">Konfigurer, om ydelsesoverlejringen skal vises, og hvilke oplysninger der vises.</string>
<string name="overlay_show_fps">Vis FPS</string>
<string name="overlay_show_fps_description">Vis aktuelle billeder pr. sekund.</string>
<string name="overlay_show_frametime">Vis billedtid</string>
<string name="overlay_show_frametime_description">Vis aktuel billedtid.</string>
<string name="overlay_show_speed">Vis hastighed</string>
<string name="overlay_show_speed_description">Vis den aktuelle emuleringshastighed i procent.</string>
<string name="overlay_show_app_ram_usage">Vis hukommelsesforbrug for app</string>
<string name="overlay_show_app_ram_usage_description">Vis mængden af RAM, der bruges af emulatoren.</string>
<string name="overlay_show_available_ram">Vis tilgængelig hukommelse</string>
<string name="overlay_show_available_ram_description">Vis mængden af RAM, der er tilgængelig.</string>
<string name="overlay_show_battery_temp">Vis batteritemperatur</string>
<string name="overlay_show_battery_temp_description">Viser den aktuelle batteritemperatur i Celsius og Fahrenheit.</string>
<string name="overlay_position">Position af overlejring</string>
<string name="overlay_position_description">Vælg, hvor ydelsesoverlejringen skal vises på skærmen.</string>
<string name="overlay_position_top_left">Øverst til venstre</string>
<string name="overlay_position_top_right">Øverst til højre</string>
<string name="overlay_position_bottom_left">Nederst til venstre</string>
<string name="overlay_position_bottom_right">Nederst til højre</string>
<string name="overlay_position_center_top">Midten øverst</string>
<string name="overlay_position_center_bottom">Midten nederst</string>
<string name="overlay_background">Overlejret baggrund</string>
<string name="overlay_background_description">Tilføjer en baggrund bag overlejringen for lettere læsning.</string>
<string name="performance_overlay_show_fps">Vis FPS</string>
<string name="performance_overlay_show_fps_description">Vis aktuelle billeder pr. sekund.</string>
<string name="performance_overlay_show_frametime">Vis billedtid</string>
<string name="performance_overlay_show_frametime_description">Vis aktuel billedtid.</string>
<string name="performance_overlay_show_speed">Vis hastighed</string>
<string name="performance_overlay_show_speed_description">Vis den aktuelle emuleringshastighed i procent.</string>
<string name="performance_overlay_show_app_ram_usage">Vis hukommelsesforbrug for app</string>
<string name="performance_overlay_show_app_ram_usage_description">Vis mængden af RAM, der bruges af emulatoren.</string>
<string name="performance_overlay_show_available_ram">Vis tilgængelig hukommelse</string>
<string name="performance_overlay_show_available_ram_description">Vis mængden af RAM, der er tilgængelig.</string>
<string name="performance_overlay_show_battery_temp">Vis batteritemperatur</string>
<string name="performance_overlay_show_battery_temp_description">Viser den aktuelle batteritemperatur i Celsius og Fahrenheit.</string>
<string name="performance_overlay_position">Overlejret-position</string>
<string name="performance_overlay_position_description">Vælg, hvor performance-overlayet skal vises på skærmen.</string>
<string name="performance_overlay_position_top_left">Øverst til venstre</string>
<string name="performance_overlay_position_top_right">Øverst til højre</string>
<string name="performance_overlay_position_bottom_left">Nederst til venstre</string>
<string name="performance_overlay_position_bottom_right">Nederst til højre</string>
<string name="performance_overlay_position_center_top">Centreret top</string>
<string name="performance_overlay_position_center_bottom">Centreret bund</string>
<string name="performance_overlay_background">Overlejret baggrund</string>
<string name="performance_overlay_background_description">Tilføjer en baggrund bag det overlejrede for lettere læsning.</string>
<!-- Cheats -->
<string name="cheats">Snyd</string>
@ -665,7 +710,7 @@
<!-- Render 3D modes -->
<string name="side_by_side">Side om Side</string>
<string name="reverse_side_by_side">Omvendt side om side</string>
<string name="side_by_side_full">Side om side i fuld bredde</string>
<string name="anaglyph">Anaglyph</string>
<string name="interlaced">Interlaced</string>
<string name="reverse_interlaced">Omvendt interlaced</string>
@ -854,4 +899,19 @@
<string name="emulation_occupied_quicksave_slot">Hurtig lagring - %1$tF %1$tR</string>
<string name="quickload_not_found">Ingen hurtig lagring tilgængelig.</string>
<!-- File Compression -->
<string name="compress">Komprimer</string>
<string name="compressing">Komprimerer…</string>
<string name="decompress">Dekomprimer</string>
<string name="decompressing">Dekomprimerer…</string>
<string name="compress_success">Komprimering gennemført.</string>
<string name="compress_unsupported">Komprimering understøttes ikke for denne fil.</string>
<string name="compress_already">Filen er allerede komprimeret.</string>
<string name="compress_failed">Komprimeringen mislykkedes.</string>
<string name="decompress_success">Dekomprimeringen er gennemført.</string>
<string name="decompress_unsupported">Dekomprimering understøttes ikke for denne fil.</string>
<string name="decompress_not_compressed">Filen er ikke komprimeret.</string>
<string name="decompress_failed">Dekomprimeringen mislykkedes.</string>
<string name="compress_decompress_installed_app">Allerede installerede programmer kan ikke komprimeres eller dekomprimeres.</string>
</resources>

View File

@ -67,10 +67,13 @@
<string name="give_permission">Conceder permiso</string>
<string name="notification_warning">¿Saltarse la concesión del permiso de notificaciones?</string>
<string name="notification_warning_description">Azahar no podrá notificarte sobre información importante.</string>
<string name="filesystem_permission_warning">Falta Permisos</string>
<string name="camera_permission">Cámara</string>
<string name="camera_permission_description">Concede el permiso de cámara debajo para emular la cámara de la 3DS.</string>
<string name="microphone_permission">Micrófono</string>
<string name="microphone_permission_description">Concede el permiso de micrófono debajo para emular el micrófono de la 3DS.</string>
<string name="filesystem_permission">Sistema de archivos</string>
<string name="filesystem_permission_description">Concede el permiso de sistema de archivos debajo para permitir que Azahar almacene archivos.</string>
<string name="permission_denied">Permiso denegado</string>
<string name="add_games_warning">¿Saltarse la selección de la carpeta de aplicaciones?</string>
<string name="add_games_warning_description">Nada se mostrará en la lista de aplicaciones si no se selecciona una carpeta.</string>
@ -90,6 +93,7 @@
<string name="cannot_skip">No puedes saltarte el configuración de la carpeta de usuario</string>
<string name="cannot_skip_directory_description">Este paso es necesario para permitir que Azahar funcione. Por favor, seleccione un directorio y luego puede continuar.</string>
<string name="selecting_user_directory_without_write_permissions">Has perdido los permisos de escritura en tu <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">directorio de datos de usuario</a>, donde se guardan las partidas guardadas y otra información. Esto puede ocurrir después de algunas actualizaciones de aplicaciones o de Android. Vuelve a seleccionar el directorio para recuperar los permisos y poder continuar.</string>
<string name="invalid_selection">Selección no válido</string>
<string name="set_up_theme_settings">Configuración de tema</string>
<string name="setup_theme_settings_description">Configura tus preferencias de tema de Azahar.</string>
<string name="setup_set_theme">Establecer tema</string>
@ -122,8 +126,8 @@
<string name="input_dialog_description">Pulsa o mueve un botón/palanca.</string>
<string name="input_binding">Asignación de botones</string>
<string name="input_binding_description">Pulsa o mueve un botón para asignarlo a %1$s.</string>
<string name="input_binding_description_vertical_axis">Mueve el joystick arriba o abajo.</string>
<string name="input_binding_description_horizontal_axis">Mueve el joystick a izquierda o derecha.</string>
<string name="input_binding_description_vertical_axis">Mueve el joystick abajo</string>
<string name="input_binding_description_horizontal_axis">Mueve el joystick a la derecha</string>
<string name="button_home">HOME</string>
<string name="button_swap">Intercambiar Pantallas</string>
<string name="button_turbo">Turbo</string>
@ -237,6 +241,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="frame_limit_enable_description">Cuando se active, la velocidad de emulación estará limitada a un porcentaje determinado de la velocidad normal. Cuando se desactive, la velocidad de emulación no tendrá límite y la tecla de acceso rápido de velocidad turbo no funcionará.</string>
<string name="frame_limit_slider">Limitar porcentaje de velocidad</string>
<string name="frame_limit_slider_description">Especifica el valor al que se limita la velocidad de emulación. Con el valor por defecto del 100%, la emulación se limitará a la velocidad normal. Los valores altos o altos incrementarán o reducirán el límite de velocidad.</string>
<string name="android_hide_images">Ocultar imágenes 3DS de Android</string>
<string name="turbo_limit">Límite de Velocidad Turbo</string>
<string name="turbo_limit_description">Límite de velocidad de emulación utilizado mientras la tecla de acceso rápido turbo está activa.</string>
<string name="expand_to_cutout_area">Expandir al área de recorte</string>
@ -262,6 +267,11 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="factor3d_description">Especifica el valor del regulador 3D. Debería estar puesto a más allá del 0% cuando el Modo 3D Estereoscópico está activado.\nNota: Los valores de profundidad superiores al 100 % no son posibles en hardware real y pueden causar problemas gráficos.</string>
<string name="disable_right_eye_render">Desactivar Renderizado de Ojo Derecho</string>
<string name="disable_right_eye_render_description">Mejora significativamente el rendimiento en algunas aplicaciones, pero puede causar parpadeo en otros.</string>
<string name="swap_eyes_3d">Intercambiar Ojos</string>
<string name="render_3d_which_display">Renderizado 3D Estereoscópico</string>
<string name="render_3d_which_display_both">Activado (todas las pantallas)</string>
<string name="render_3d_which_display_primary">Activado (solo pantalla principal)</string>
<string name="render_3d_which_display_secondary">Activado (solo pantalla secundaria)</string>
<string name="cardboard_vr">Cardboard VR</string>
<string name="cardboard_screen_size">Tamaño de la pantalla Cardboard</string>
<string name="cardboard_screen_size_description">Escala la pantalla a un porcentaje de su tamaño original.</string>
@ -298,7 +308,6 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="hw_shaders_description">Usa el hardware para emular los sombreadores de 3DS. Cuando se active, el rendimiento mejorará notablemente.</string>
<string name="cpu_clock_speed">Velocidad de reloj de la CPU</string>
<string name="vsync">Activar Sincronización Vertical</string>
<string name="vsync_description">Sincroniza los cuadros por segundo del juego con la tasa de refresco de tu dispositivo.</string>
<string name="renderer_debug">Renderizador de depuración</string>
<string name="renderer_debug_description">Archiva información adicional gráfica relacionada con la depuración. Cuando está activada, el rendimiento de los juegos será reducido considerablemente</string>
<string name="instant_debug_log">Limpiar la salida del registro en cada mensaje</string>
@ -428,6 +437,12 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="emulation_portrait_layout_top_full">Por defecto</string>
<string name="emulation_secondary_display_default">Por defecto del sistema (espejo)</string>
<string name="emulation_screen_layout_custom">Estilo personalizado</string>
<string name="bg_color">Color de fondo</string>
<string name="bg_red">Rojo</string>
<string name="bg_green">Verde</string>
<string name="bg_blue">Azul</string>
<string name="second_screen_opacity">Opacidad personalizado de la segunda pantalla</string>
<string name="second_screen_opacity_description">La opacidad de la segunda pantalla 3DS al usar el pantalla personalizado. Útil si la segunda pantalla ésta posición en la parte superior de la primera pantalla.</string>
<string name="emulation_small_screen_position">Posición Pantalla Pequeña</string>
<string name="small_screen_position_description">¿Dónde debería aparecer la pantalla pequeña en relación con la grande en Disposicion de Pantalla Grande?</string>
<string name="small_screen_position_top_right">Arriba a la Derecha</string>
@ -523,7 +538,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="fatal_error">Error Fatal</string>
<string name="fatal_error_message">Ha ocurrido un error fatal. Mira el registro para más detalles.\nSeguir con la emulación podría resultar en diversos cuelgues y bugs.</string>
<string name="unsupported_encrypted">Aplicación encriptada no soportada</string>
<string name="invalid_system_mode">Modo de sistema no válido</string>
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Preparando shaders</string>
<string name="building_shaders">Construyendo shaders</string>
@ -550,34 +565,36 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="game_context_id">ID:</string>
<string name="game_context_file">Archivo:</string>
<string name="game_context_type">Tipo:</string>
<string name="game_context_insert">Insertar Cartucho</string>
<string name="game_context_eject">Expulsar Cartucho</string>
<!-- Performance Overlay settings -->
<string name="performance_overlay_show">Mostrar información de rendimiento</string>
<string name="performance_overlay_options">Información de rendimiento</string>
<string name="performance_overlay_enable">Activar información de rendimiento</string>
<string name="performance_overlay_options_description">Configura la información de rendimiento</string>
<string name="overlay_show_fps">Mostrar FPS</string>
<string name="overlay_show_fps_description">Muestra los fotogramas por segundo actuales.</string>
<string name="overlay_show_frametime">Mostrar duración de fotogramas</string>
<string name="overlay_show_frametime_description">Muestra la duración actual de cada fotograma.</string>
<string name="overlay_show_speed">Mostrar velocidad</string>
<string name="overlay_show_speed_description">Muestra el porcentaje de velocidad de emulación actual.</string>
<string name="overlay_show_app_ram_usage">Mostrar el uso de memoria de la aplicación</string>
<string name="overlay_show_app_ram_usage_description">Muestra la cantidad de memoria RAM que esta usando el emulador.</string>
<string name="overlay_show_available_ram">Mostrar memoria disponible</string>
<string name="overlay_show_available_ram_description">Muestra la cantidad de memoria RAM que esta disponible.</string>
<string name="overlay_show_battery_temp">Mostrar la temperatura de la batería</string>
<string name="overlay_show_battery_temp_description">Muestra la temperatura actual de la batería en Celsius y Fahrenheit.</string>
<string name="overlay_position">Posición de la información</string>
<string name="overlay_position_description">Elige donde la información de rendimiento será mostrada en la pantalla.</string>
<string name="overlay_position_top_left">Arriba a la izquierda</string>
<string name="overlay_position_top_right">Arriba a la derecha</string>
<string name="overlay_position_bottom_left">Abajo a la izquierda</string>
<string name="overlay_position_bottom_right">Abajo a la derecha</string>
<string name="overlay_position_center_top">Centro superior</string>
<string name="overlay_position_center_bottom">Centro inferior </string>
<string name="overlay_background">Fondo de la información</string>
<string name="overlay_background_description">Agrega un fondo detrás de la información para hacerla más legible.</string>
<string name="performance_overlay_show_fps">Mostrar FPS</string>
<string name="performance_overlay_show_fps_description">Muestra los fotogramas por segundo actuales.</string>
<string name="performance_overlay_show_frametime">Mostrar duración de fotogramas</string>
<string name="performance_overlay_show_frametime_description">Muestra la duración actual de cada fotograma.</string>
<string name="performance_overlay_show_speed">Mostrar velocidad</string>
<string name="performance_overlay_show_speed_description">Muestra el porcentaje de velocidad de emulación actual.</string>
<string name="performance_overlay_show_app_ram_usage">Mostrar el uso de memoria de la aplicación</string>
<string name="performance_overlay_show_app_ram_usage_description">Muestra la cantidad de memoria RAM que esta usando el emulador.</string>
<string name="performance_overlay_show_available_ram">Mostrar memoria disponible</string>
<string name="performance_overlay_show_available_ram_description">Muestra la cantidad de memoria RAM que esta disponible.</string>
<string name="performance_overlay_show_battery_temp">Mostrar la temperatura de la batería</string>
<string name="performance_overlay_show_battery_temp_description">Muestra la temperatura actual de la batería en Celsius y Fahrenheit.</string>
<string name="performance_overlay_position">Posición de la información</string>
<string name="performance_overlay_position_description">Elegir donde el superposición de rendimiento esta mostrado en el pantalla</string>
<string name="performance_overlay_position_top_left">Arriba a la Izquierda</string>
<string name="performance_overlay_position_top_right">Arriba a la Derecha</string>
<string name="performance_overlay_position_bottom_left">Abajo a la Izquierda</string>
<string name="performance_overlay_position_bottom_right">Abajo a la Derecha</string>
<string name="performance_overlay_position_center_top">Centro Superior</string>
<string name="performance_overlay_position_center_bottom">Centro Inferior</string>
<string name="performance_overlay_background">Fondo de la información</string>
<string name="performance_overlay_background_description">Agrega un fondo detrás de la información para hacerla más legible.</string>
<!-- Cheats -->
<string name="cheats">Trucos</string>
@ -682,7 +699,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<!-- Render 3D modes -->
<string name="side_by_side">De lado a lado</string>
<string name="reverse_side_by_side">De lado a lado inverso</string>
<string name="side_by_side_full">De lado a lado ancho completo</string>
<string name="anaglyph">Anáglifo</string>
<string name="interlaced">Entrelazado</string>
<string name="reverse_interlaced">Entrelazado inverso</string>
@ -871,4 +888,17 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="emulation_occupied_quicksave_slot">Guardado rápido - %1$tF %1$tR</string>
<string name="quickload_not_found">Guardado rápido no disponible.</string>
</resources>
<!-- File Compression -->
<string name="compress">Comprimir</string>
<string name="compressing">Compresando...</string>
<string name="decompress">Descomprimir</string>
<string name="decompressing">Descomprimiendo…</string>
<string name="compress_success">Compresión completada con éxito.</string>
<string name="compress_unsupported">Compresión no está soportado con este archivo.</string>
<string name="compress_already">Este archivo ya está comprimido.</string>
<string name="compress_failed">Falló la compresión.</string>
<string name="decompress_success">Descompresión completada con éxito.</string>
<string name="decompress_unsupported">Descompresión no está soportado con este archivo.</string>
<string name="decompress_not_compressed">El archivo no está comprimido.</string>
<string name="decompress_failed"> Falló la descompresión.</string>
</resources>

View File

@ -9,7 +9,6 @@
<string name="mac_address">MACアドレス</string>
<string name="regenerate_mac_address">MACアドレスを再生成</string>
<string name="regenerate_mac_address_description">これを行うと、今のMACアドレスを新しいもので置き換えます。セットアップツールで実機からMACアドレスを吸い出した場合、これをするのは推奨しません。続行しますか</string>
<string name="delay_render_thread">描写スレッドを遅延する</string>
<string name="delay_render_thread_description">GPUにデータを送信する間、ゲームの描写スレッドを遅延します。動的フレームレートであるほんの一部のアプリケーションでのパフォーマンスが向上します。</string>
<string name="instant_debug_log_description">デバッグログを即座にファイルに書き込みます。Azaharがクラッシュしてログが途切れるときに有効にしてください。</string>
<string name="miscellaneous">その他</string>

View File

@ -61,7 +61,6 @@
<!-- Audio settings strings -->
<string name="audio_volume">Garsumas</string>
<string name="audio_stretch">Garso ištempimas</string>
<string name="realtime_audio">Įjungti realaus laiko garsą</string>
<string name="layout_screen_orientation_auto_sensor">Automatinis</string>
<string name="learn_more">Sužinoti daugiau</string>
<string name="close">Uždaryti</string>

View File

@ -67,10 +67,14 @@
<string name="give_permission">Udzielenie zgody</string>
<string name="notification_warning">Pominąć udzielanie zgody na powiadomienie?</string>
<string name="notification_warning_description">Azahar nie będzie w stanie powiadomić cię o ważnych informacjach.</string>
<string name="filesystem_permission_warning">Brak uprawnień</string>
<string name="filesystem_permission_warning_description">Azahar wymaga uprawnień do zarządzania plikami na tym urządzeniu w celu przechowywania i zarządzania swoimi danymi. \n\nPrzed kontynuowaniem należy przyznać uprawnienia „System plików”.</string>
<string name="camera_permission">Kamera</string>
<string name="camera_permission_description">Udziel poniższych uprawnień kamery, aby emulować kamerę 3DS.</string>
<string name="microphone_permission">Mikrofon</string>
<string name="microphone_permission_description">Udziel poniższych uprawnień mikrofonu, aby emulować mikrofon 3DS.</string>
<string name="filesystem_permission">System plików</string>
<string name="filesystem_permission_description">Przyznaje poniższe uprawnienia systemu plików, aby umożliwić Azahar przechowywanie plików.</string>
<string name="permission_denied">Odmowa zezwolenia</string>
<string name="add_games_warning">Pominąć wybór folderu z aplikacjami?</string>
<string name="add_games_warning_description">Oprogramowania nie będą wyświetlane na liście aplikacji, jeśli nie wybrano folderu.</string>
@ -90,6 +94,9 @@
<string name="cannot_skip">Nie można pominąć konfiguracji folderu użytkownika.</string>
<string name="cannot_skip_directory_description">Ten krok jest wymagany, aby umożliwić działanie Azahar. Wybierz katalog, a następnie możesz kontynuować.</string>
<string name="selecting_user_directory_without_write_permissions">Utraciłeś uprawnienia do zapisu w katalogu <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">danych użytkownika</a>, w którym przechowywane są zapisy i inne informacje. Może się to zdarzyć po niektórych aktualizacjach aplikacji lub systemu Android. Wybierz ponownie katalog, aby odzyskać uprawnienia i móc kontynuować.</string>
<string name="invalid_selection">Nieprawidłowy wybór</string>
<string name="invalid_user_directory">Wybór katalogu użytkownika był nieprawidłowy.\nProszę ponownie wybrać katalog użytkownika, upewniając się, że przechodzisz do niego z katalogu głównego pamięci urządzenia.</string>
<string name="filesystem_permission_lost">Azahar utracił uprawnienia do zarządzania plikami na tym urządzeniu. Może się to zdarzyć po aktualizacji niektórych aplikacji lub systemu Android. Aby kontynuować korzystanie z aplikacji, należy ponownie przyznać te uprawnienia na następnym ekranie.</string>
<string name="set_up_theme_settings">Ustawienia motywu</string>
<string name="setup_theme_settings_description">Skonfiguruj ustawienia motywu dla Azahar.</string>
<string name="setup_set_theme">Ustaw motyw</string>
@ -122,8 +129,8 @@
<string name="input_dialog_description">Naciśnij lub przenieś wejście.</string>
<string name="input_binding">Powiązanie wejścia</string>
<string name="input_binding_description">Naciśnij lub przesuń wejście, aby powiązać je z %1$s.</string>
<string name="input_binding_description_vertical_axis">Przesuń analog w górę lub w dół.</string>
<string name="input_binding_description_horizontal_axis">Przesuń analog w lewo lub w prawo.</string>
<string name="input_binding_description_vertical_axis">Przesuń analog w dół.</string>
<string name="input_binding_description_horizontal_axis">Przesuń analog w prawo.</string>
<string name="button_home">HOME</string>
<string name="button_swap">Zamień ekrany</string>
<string name="button_turbo">Turbo</string>
@ -162,6 +169,8 @@
<string name="username">Nazwa użytkownika</string>
<string name="new_3ds">Tryb New 3DS</string>
<string name="lle_applets">Użyj apletów LLE (jeśli są zainstalowane)</string>
<string name="apply_region_free_patch">Zastosuj łatkę bez regionu do zainstalowanych aplikacji.</string>
<string name="apply_region_free_patch_desc">Naprawia region zainstalowanych aplikacji, aby były one wolne od ograniczeń regionalnych, dzięki czemu zawsze pojawiają się w menu głównym.</string>
<string name="enable_required_online_lle_modules">Włącz wymagane moduły LLE dla funkcji online (jeśli są zainstalowane)</string>
<string name="enable_required_online_lle_modules_desc">łącza moduły LLE potrzebne do gry wieloosobowej online, dostępu do eShopu itp.</string>
<string name="clock">Zegar</string>
@ -217,25 +226,27 @@
<string name="spirv_shader_gen_description">Emituje fragment shaderów używany do emulacji PICA przy użyciu SPIR-V zamiast GLSL.</string>
<string name="disable_spirv_optimizer">Wyłącz optymalizator SPIR-V</string>
<string name="disable_spirv_optimizer_description">Wyłącza optymalizację SPIR-V, znacznie zmniejszając zacinanie się obrazu przy minimalnym wpływie na wydajność.</string>
<string name="async_shaders">Włącz asynchroniczną kompilację shaderów</string>
<string name="async_shaders">Włącz Asynchroniczną Kompilację Shaderów</string>
<string name="async_shaders_description">Kompiluje shadery w tle, aby zmniejszyć zacinanie się podczas rozgrywki. Po włączeniu należy spodziewać się tymczasowych błędów graficznych</string>
<string name="linear_filtering">Filtrowanie Linear</string>
<string name="linear_filtering_description">Włącza filtrowanie liniowe, które sprawia, że grafika w grach jest płynniejsza.</string>
<string name="texture_filter_name">Filtr tekstur</string>
<string name="texture_filter_description">Ulepsza oprawę wizualną aplikacji poprzez zastosowanie filtrów do tekstur. Obsługiwane filtry to Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale i MMPX.</string>
<string name="delay_render_thread">Opóźnienie renderowania wątku gry</string>
<string name="delay_render_thread">Opóźnienie Renderowania Wątku Gry</string>
<string name="delay_render_thread_description">Opóźnia wątek renderowania aplikacji podczas przesyłania danych do GPU. Pomaga w kwestiach wydajności w (bardzo niewielu) aplikacjach z dynamiczną liczbą klatek na sekundę.</string>
<string name="advanced">Zaawansowane</string>
<string name="texture_sampling_name">Próbkowanie tekstur</string>
<string name="texture_sampling_description">Zastępuje filtr próbkowania używany przez gry. Może to być przydatne w niektórych przypadkach, gdy gry źle zachowują się podczas skalowania w górę. Jeśli nie masz pewności, ustaw tę opcję na Kontrolowane przez grę.</string>
<string name="shaders_accurate_mul">Dokładne mnożenie</string>
<string name="shaders_accurate_mul_description">Używa dokładniejszego mnożenia w shaderach sprzętu, dzięki czemu może naprawić niektóre błędy graficzne. Po włączeniu tej funkcji wydajność zostanie zmniejszona.</string>
<string name="asynchronous_gpu">Włącz asynchroniczną emulację GPU</string>
<string name="asynchronous_gpu">Włącz Asynchroniczną Emulację GPU</string>
<string name="asynchronous_gpu_description">Używa oddzielnego wątku do asynchronicznej emulacji GPU. Po włączeniu, wydajność zostanie poprawiona.</string>
<string name="frame_limit_enable">Ogranicz prędkość</string>
<string name="frame_limit_enable_description">Po włączeniu prędkość emulacji zostanie ograniczona do określonego procentu normalnej prędkości. Jeśli opcja ta jest wyłączona, prędkość emulacji nie zostanie ograniczona, a klawisz skrótu prędkości turbo nie będzie działał.</string>
<string name="frame_limit_slider">Ogranicz procent prędkości</string>
<string name="frame_limit_slider_description">Określa wartość procentową ograniczenia prędkości emulacji. Przy domyślnej wartości 100% emulacja będzie ograniczona do normalnej prędkości. Wyższe lub niższe wartości zwiększają lub zmniejszają ograniczenie prędkości.</string>
<string name="android_hide_images">Ukryj obrazy 3DS z systemu Android</string>
<string name="android_hide_images_description">Zapobiega indeksowaniu przez system Android zdjęć wykonanych aparatem 3DS, zrzutów ekranu i niestandardowych tekstur oraz wyświetlaniu ich w galerii. Aby zmiany ustawień zaczęły obowiązywać, może być konieczne ponowne uruchomienie urządzenia.</string>
<string name="turbo_limit">Limit prędkości Turbo</string>
<string name="turbo_limit_description">Limit prędkości emulacji wykorzystywany, gdy aktywny jest klawisz skrótu turbo.</string>
<string name="expand_to_cutout_area">Rozszerz do obszaru wycięcia</string>
@ -257,10 +268,18 @@
<string name="debug_warning">Ostrzeżenie: Zmiana tych ustawień spowolni emulację</string>
<string name="stereoscopy">Sterowanie stereoskopowe</string>
<string name="render3d">Tryb stereoskopowy 3D</string>
<string name="render3d_description">Wybierz tryb stereoskopowego 3D dla renderowania 3D.Tryb ekranów obok siebie jest obecnie najczęściej stosowany. Tryby obrazu Anaglyph i Interlaced będą zawsze stosowane do wyświetlania obrazu na wszystkich podłączonych monitorach.</string>
<string name="factor3d">Zasięg</string>
<string name="factor3d_description">Określa wartość suwaka 3D. Powinien być ustawiony na wartość wyższą niż 0%, gdy włączony jest tryb stereoskopowy 3D.\nUwaga: Wartość przekraczająca 100% nie jest możliwa na rzeczywistym sprzęcie i może powodować problemy graficzne.</string>
<string name="disable_right_eye_render">Wyłącz renderowanie prawego oka</string>
<string name="disable_right_eye_render_description">Znacznie poprawia wydajność w niektórych aplikacjach, ale może powodować migotanie w innych.</string>
<string name="swap_eyes_3d">Zamiana Oczu</string>
<string name="swap_eyes_3d_description">Zamiana oczu jest wyświetlana po obu stronach. W połączeniu z trybem obrazów obok siebie umożliwia oglądanie obrazu 3D poprzez przesunięcie oczu!</string>
<string name="render_3d_which_display">Render stereoskopowego 3D</string>
<string name="render_3d_which_display_description">Czy włączyć stereoskopowe 3D i na jakich wyświetlaczach to włączyć? Opcje dotyczące pojedynczego wyświetlacza mają znaczenie tylko wtedy, gdy podłączonych jest wiele wyświetlaczy.</string>
<string name="render_3d_which_display_both">Włącz (Wszystkie Wyświetlacze)</string>
<string name="render_3d_which_display_primary">Włącz (Tylko Główny Wyświetlacz)</string>
<string name="render_3d_which_display_secondary">Włącz (Tylko na Dodatkowym Wyświetlaczu)</string>
<string name="cardboard_vr">Cardboard VR</string>
<string name="cardboard_screen_size">Rozmiar ekranu Cardboarda</string>
<string name="cardboard_screen_size_description">Skaluje ekran do wartości procentowej jego oryginalnego rozmiaru.</string>
@ -285,7 +304,7 @@
<string name="audio_volume">Głośność</string>
<string name="audio_stretch">Rozciągnij dźwięk</string>
<string name="audio_stretch_description">Rozciąga dźwięk, aby zredukować zacinanie się. Po włączeniu tej opcji zwiększa opóźnienie dźwięku i nieznacznie obniża wydajność.</string>
<string name="realtime_audio">Włącz dźwięk w czasie rzeczywistym</string>
<string name="realtime_audio">Włącz Dźwięk w Czasie Rzeczywistym</string>
<string name="realtime_audio_description">Skaluje prędkość odtwarzania dźwięku, aby uwzględnić spadki liczby klatek na sekundę w emulacji. Oznacza to, że dźwięk będzie odtwarzany z pełną prędkością, nawet jeśli liczba klatek na sekundę w grze jest niska. Może powodować problemy z desynchronizacją dźwięku.</string>
<string name="audio_input_type">Urządzenie wejściowe dźwięku</string>
<string name="sound_output_mode">Tryb wyjścia dźwięku</string>
@ -297,12 +316,12 @@
<string name="hw_shaders_description">Używa sprzętu do emulacji shaderów 3DS. Po włączeniu, wydajność gry zostanie znacznie poprawiona.</string>
<string name="cpu_clock_speed">Prędkość taktowania procesora</string>
<string name="vsync">Włącz V-Sync</string>
<string name="vsync_description">Synchronizuje liczbę klatek na sekundę gry z częstotliwością odświeżania urządzenia.</string>
<string name="vsync_description">Synchronizuje częstotliwość klatek na sekundę w grze z częstotliwością odświeżania urządzenia. Może powodować dodatkowe opóźnienia wejściowe, ale w niektórych przypadkach może ograniczyć występowanie rozdarć obrazu.</string>
<string name="renderer_debug">Render debugowania</string>
<string name="renderer_debug_description">Rejestruje dodatkowe informacje debugowania związane z grafiką. Po włączeniu, wydajność gry zostanie znacznie zmniejszona.</string>
<string name="instant_debug_log">Opróżnia log przy każdej wiadomości</string>
<string name="instant_debug_log">Opróżnij Log Przy Każdej Wiadomości</string>
<string name="instant_debug_log_description">Natychmiast zapisuje log debugowania do pliku. Użyj tego, jeśli azahar ulegnie awarii, a dane wyjściowe logu zostaną przerwane.</string>
<string name="delay_start_lle_modules">Opóźnione uruchamianie z modułami LLE</string>
<string name="delay_start_lle_modules">Opóźnij Uruchamianie z Modułami LLE</string>
<string name="delay_start_lle_modules_description">Opóźnia uruchomienie aplikacji, gdy włączone są moduły LLE.</string>
<string name="deterministic_async_operations">Deterministyczne operacje asynchroniczne</string>
<string name="deterministic_async_operations_description">Sprawia, że operacje asynchroniczne są deterministyczne dla debugowania. Włączenie tej opcji może powodować zawieszanie się gry.</string>
@ -427,6 +446,13 @@
<string name="emulation_portrait_layout_top_full">Domyślny</string>
<string name="emulation_secondary_display_default">Ustawienia domyślne systemu (mirror)</string>
<string name="emulation_screen_layout_custom">Niestandardowy Układ</string>
<string name="bg_color">Kolor tła</string>
<string name="bg_color_description">Kolor wyświetlany za ekranami podczas emulacji, wyświetlany jako wartość RGB.</string>
<string name="bg_red">Czerwony</string>
<string name="bg_green">Zielony</string>
<string name="bg_blue">Niebieski</string>
<string name="second_screen_opacity">Niestandardowy wygląd drugiego ekranu przezroczystości</string>
<string name="second_screen_opacity_description">Przezroczystość drugiego ekranu 3DS podczas korzystania z niestandardowego układu ekranu. Przydatne, jeśli drugi ekran ma być umieszczony nad pierwszym ekranem.</string>
<string name="emulation_small_screen_position">Pozycja małego ekranu</string>
<string name="small_screen_position_description">Gdzie powinien być wyświetlany mały ekran względem dużego w układzie dużego ekranu?</string>
<string name="small_screen_position_top_right">Prawy górny róg</string>
@ -522,6 +548,8 @@
<string name="fatal_error">Krytyczny Błąd</string>
<string name="fatal_error_message">Wystąpił błąd krytyczny. Kontynuowanie emulacji może spowodować awarie i błędy.</string>
<string name="unsupported_encrypted">Nieobsługiwana zaszyfrowana aplikacja</string>
<string name="invalid_system_mode">Nieprawidłowy moduł systemu</string>
<string name="invalid_system_mode_message">Aplikacje dostępne wyłącznie na konsoli New 3DS nie mogą być uruchamiane bez włączenia trybu New 3DS.</string>
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Przygotowanie shaderów</string>
@ -549,34 +577,36 @@
<string name="game_context_id">ID:</string>
<string name="game_context_file">Plik:</string>
<string name="game_context_type">Typ:</string>
<string name="game_context_insert">Włóż Kartridż</string>
<string name="game_context_eject">Wyjmij Kartridż</string>
<!-- Performance Overlay settings -->
<string name="performance_overlay_show">Wyświetl nakładkę wydajności</string>
<string name="performance_overlay_options">Nakładkę wydajności</string>
<string name="performance_overlay_enable">Włącz nakładkę wydajności</string>
<string name="performance_overlay_options_description">Konfiguruje, czy wyświetlana jest nakładka wydajności i jakie informacje są wyświetlane.</string>
<string name="overlay_show_fps">Wyświetl FPS</string>
<string name="overlay_show_fps_description">Wyświetla aktualną liczbę klatek na sekundę.</string>
<string name="overlay_show_frametime">Pokaż czas klatek</string>
<string name="overlay_show_frametime_description">Wyświetla bieżący czas klatek.</string>
<string name="overlay_show_speed">Wyświetl Prędkość</string>
<string name="overlay_show_speed_description">Wyświetla aktualną procentową prędkość emulacji.</string>
<string name="overlay_show_app_ram_usage">Wyświetl użycie pamięci aplikacji</string>
<string name="overlay_show_app_ram_usage_description">Wyświetla ilość pamięci RAM używanej przez emulator.</string>
<string name="overlay_show_available_ram">Wyświetl dostępną pamięć</string>
<string name="overlay_show_available_ram_description">Wyświetla ilość dostępnej pamięci RAM.</string>
<string name="overlay_show_battery_temp">Wyświetl temperaturę baterii</string>
<string name="overlay_show_battery_temp_description">Wyświetla bieżącą temperaturę baterii w stopniach Celcjusza i Fahrenheita.</string>
<string name="overlay_position">Pozycja nakładki</string>
<string name="overlay_position_description">Wybierz miejsce wyświetlania nakładki wydajności na ekranie.</string>
<string name="overlay_position_top_left">Lewy górny róg</string>
<string name="overlay_position_top_right">Prawy górny róg</string>
<string name="overlay_position_bottom_left">Lewy dolny róg</string>
<string name="overlay_position_bottom_right">Prawy dolny róg</string>
<string name="overlay_position_center_top">Środkowy górny</string>
<string name="overlay_position_center_bottom">Środkowy dolny</string>
<string name="overlay_background">Tło nakładki</string>
<string name="overlay_background_description">Dodaje tło z tyłu nakładki w celu łatwego odczytu.</string>
<string name="performance_overlay_show_fps">Wyświetl FPS</string>
<string name="performance_overlay_show_fps_description">Wyświetla aktualną liczbę klatek na sekundę.</string>
<string name="performance_overlay_show_frametime">Wyświetl czas klatek</string>
<string name="performance_overlay_show_frametime_description">Wyświetla bieżący czas klatek.</string>
<string name="performance_overlay_show_speed">Wyświetl Prędkość</string>
<string name="performance_overlay_show_speed_description">Wyświetla aktualną procentową prędkość emulacji.</string>
<string name="performance_overlay_show_app_ram_usage">Wyświetl użycie pamięci aplikacji</string>
<string name="performance_overlay_show_app_ram_usage_description">Wyświetla ilość pamięci RAM używanej przez emulator.</string>
<string name="performance_overlay_show_available_ram">Wyświetl dostępną pamięć</string>
<string name="performance_overlay_show_available_ram_description">Wyświetla ilość dostępnej pamięci RAM.</string>
<string name="performance_overlay_show_battery_temp">Wyświetl temperaturę baterii</string>
<string name="performance_overlay_show_battery_temp_description">Wyświetla bieżącą temperaturę baterii w stopniach Celcjusza i Fahrenheita.</string>
<string name="performance_overlay_position">Pozycja nakładki</string>
<string name="performance_overlay_position_description">Wybierz miejsce wyświetlania nakładki wydajności na ekranie.</string>
<string name="performance_overlay_position_top_left">Lewy górny róg</string>
<string name="performance_overlay_position_top_right">Prawy górny róg</string>
<string name="performance_overlay_position_bottom_left">Lewy dolny róg</string>
<string name="performance_overlay_position_bottom_right">Prawy dolny róg</string>
<string name="performance_overlay_position_center_top">Środkowy górny</string>
<string name="performance_overlay_position_center_bottom">Środkowy dolny</string>
<string name="performance_overlay_background">Tło nakładki</string>
<string name="performance_overlay_background_description">Dodaje tło z tyłu nakładki w celu łatwego odczytu.</string>
<!-- Cheats -->
<string name="cheats">Cheaty</string>
@ -682,7 +712,7 @@
<!-- Render 3D modes -->
<string name="side_by_side">Obok Siebie</string>
<string name="reverse_side_by_side">Odwróć Obok Siebie</string>
<string name="side_by_side_full">Obok Siebie na Pełną Szerokość</string>
<string name="anaglyph">Analogiczny</string>
<string name="interlaced">Naprzemienny</string>
<string name="reverse_interlaced">Odwrócony Obraz</string>
@ -871,4 +901,19 @@
<string name="emulation_occupied_quicksave_slot">Szybkie zapisywanie - %1$tF %1$tR</string>
<string name="quickload_not_found">Funkcja szybkiego zapisu nie jest dostępna.</string>
<!-- File Compression -->
<string name="compress">Kompresuj</string>
<string name="compressing">Kompresowanie…</string>
<string name="decompress">Dekompresuj</string>
<string name="decompressing">Dekompresowanie...</string>
<string name="compress_success">Kompresja została zakończona pomyślnie.</string>
<string name="compress_unsupported">Kompresja nie jest obsługiwana dla tego pliku.</string>
<string name="compress_already">Plik jest już skompresowany.</string>
<string name="compress_failed">Kompresja nie powiodła się.</string>
<string name="decompress_success">Dekompresja została zakończona pomyślnie.</string>
<string name="decompress_unsupported">Dekompresja nie jest obsługiwana dla tego pliku.</string>
<string name="decompress_not_compressed">Plik nie jest skompresowany.</string>
<string name="decompress_failed">Dekompresja nie powiodła się.</string>
<string name="compress_decompress_installed_app">Aplikacje, które są już zainstalowane, nie mogą być kompresowane ani dekompresowane.</string>
</resources>

View File

@ -67,10 +67,14 @@
<string name="give_permission">Conceder permissão</string>
<string name="notification_warning">Ignorar a solicitação de notificação?</string>
<string name="notification_warning_description">O Azahar não poderá te notificar de informações importantes.</string>
<string name="filesystem_permission_warning">Permissões Ausentes</string>
<string name="filesystem_permission_warning_description">O Azahar requer permissão para gerenciar arquivos neste dispositivo a fim de armazenar e gerenciar seus dados.\n\nPor favor, conceda a permissão de \'Sistema de Arquivos\' antes de continuar.</string>
<string name="camera_permission">Câmera</string>
<string name="camera_permission_description">Conceda acesso a câmera abaixo para emular a câmera do 3DS.</string>
<string name="microphone_permission">Microfone</string>
<string name="microphone_permission_description">Conceda a acesso ao microfone abaixo para emular o microfone do 3DS.</string>
<string name="filesystem_permission">Sistema de Arquivos</string>
<string name="filesystem_permission_description">Conceda a permissão de arquivos abaixo para permitir que o Azahar armazene arquivos.</string>
<string name="permission_denied">Permissão negada</string>
<string name="add_games_warning">Pular a seleção da pasta de aplicativos?</string>
<string name="add_games_warning_description">Os softwares não serão exibidos na lista de Aplicativos se uma pasta não for selecionada.</string>
@ -90,6 +94,9 @@
<string name="cannot_skip">Você não pode pular a configuração da pasta do usuário.</string>
<string name="cannot_skip_directory_description">Este passo é necessário para permitir que o Azahar funcione. Selecione um diretório para continuar.</string>
<string name="selecting_user_directory_without_write_permissions">Você perdeu suas permissões de escrita no seu diretório de <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">dados de usuário</a>, onde dados salvos e outras informações são guardadas. Isso pode acontecer depois que algum app ou Android atualiza. Re-selecione o diretório para reobter as permissões para que você possa continuar.</string>
<string name="invalid_selection">Seleção Inválida</string>
<string name="invalid_user_directory">A seleção do diretório de usuário é inválida.\nPor favor, selecione novamente o diretório de usuário, certificando-se de navegar até ele a partir da raiz do armazenamento do seu dispositivo.</string>
<string name="filesystem_permission_lost">O Azahar perdeu a permissão para gerenciar arquivos neste dispositivo. Isso pode acontecer após atualizações do aplicativo ou do Android. Por favor, conceda novamente esta permissão na próxima tela para continuar usando o app.</string>
<string name="set_up_theme_settings">Configurações de Tema</string>
<string name="setup_theme_settings_description">Configure suas preferências de tema para o Azahar.</string>
<string name="setup_set_theme">Definir Tema</string>
@ -122,8 +129,8 @@
<string name="input_dialog_description">Pressione ou mova uma entrada.</string>
<string name="input_binding">Mapeamento de controles</string>
<string name="input_binding_description">Pressione ou mova um botão/alavanca para mapear para %1$s.</string>
<string name="input_binding_description_vertical_axis">Mova o seu joystick para cima ou para baixo.</string>
<string name="input_binding_description_horizontal_axis">Mova o seu joystick para esquerda ou para direita.</string>
<string name="input_binding_description_vertical_axis">Mova o seu joystick para baixo</string>
<string name="input_binding_description_horizontal_axis">Mova o seu joystick para a direita</string>
<string name="button_home">Menu Principal</string>
<string name="button_swap">Trocar telas</string>
<string name="button_turbo">Turbo</string>
@ -162,6 +169,8 @@
<string name="username">Nome de usuário</string>
<string name="new_3ds">Modo do Novo 3DS</string>
<string name="lle_applets">Usar miniaplicativos LLE (se instalados)</string>
<string name="apply_region_free_patch">Aplicar patch de região livre aos aplicativos instalados</string>
<string name="apply_region_free_patch_desc">Aplica um patch de região livre nos aplicativos instalados, para que eles sempre apareçam no menu inicial.</string>
<string name="enable_required_online_lle_modules">Ativa os módulos LLE necessários para os recursos online (se instalado)</string>
<string name="enable_required_online_lle_modules_desc">Ativa os módulos LLE necessários para o multijogador online, acesso à eShop, etc.</string>
<string name="clock">Relógio</string>
@ -193,6 +202,10 @@
<string name="region_mismatch">Aviso de inconsistência de região</string>
<string name="region_mismatch_emulated">O país configurado não é válido para a região emulada selecionada.</string>
<string name="region_mismatch_console">O país configurado não é válido para o console vinculado atual.</string>
<string name="storage">Armazenamento</string>
<string name="compress_cia_installs">Comprimir conteúdo CIA instalado</string>
<string name="compress_cia_installs_description">Comprime o conteúdo dos arquivos CIA ao serem instalados no cartão SD emulado. Afeta apenas o conteúdo CIA instalado enquanto a opção estiver ativada.</string>
<!-- Camera settings strings -->
<string name="inner_camera">Câmera frontal</string>
<string name="outer_left_camera">Câmera traseira esquerda</string>
@ -213,25 +226,27 @@
<string name="spirv_shader_gen_description">Emite o fragment shader usado para emular PICA usando SPIR-V em vez de GLSL</string>
<string name="disable_spirv_optimizer">Desativar otimizador SPIR-V</string>
<string name="disable_spirv_optimizer_description">Desativa a etapa de otimização SPIR-V, reduzindo consideravelmente os travamentos, com impacto mínimo no desempenho.</string>
<string name="async_shaders">Ativar a compilação assíncrona de shaders</string>
<string name="async_shaders">Habilitar Compilação Assíncrona do Shader</string>
<string name="async_shaders_description">Compila shaders em segundo plano para reduzir travamentos durante o jogo. Quando ativado, espere falhas gráficas temporárias</string>
<string name="linear_filtering">Filtragem Linear</string>
<string name="linear_filtering_description">Ativa a filtragem linear, que suaviza o visual do jogo.</string>
<string name="texture_filter_name">Filtro de texturas</string>
<string name="texture_filter_description">Aprimora o visual dos aplicativos ao aplicar filtros às texturas. Os filtros compatíveis são: Anime4K Ultrafast, Bicúbico, ScaleForce, xBRZ Freescale e MMPX.</string>
<string name="delay_render_thread">Atrasar thread de renderização do aplicativo</string>
<string name="delay_render_thread">Atrasar Thread de Renderização do Aplicativo</string>
<string name="delay_render_thread_description">Atrasar thread de renderização do aplicativo quando for enviado dados para a GPU. Ajuda com problemas de desempenho em (muito poucos) aplicativos com taxa de quadros dinâmica.</string>
<string name="advanced">Avançado</string>
<string name="texture_sampling_name">Amostragem de Texturas</string>
<string name="texture_sampling_description">Substitui o filtro de amostragem usado pelos jogos. Isso pode ser útil em certos casos com jogos que se comportem mal durante o upscaling. Em caso de dúvidas, defina como Controlado pelo Jogo.</string>
<string name="shaders_accurate_mul">Multiplicação precisa</string>
<string name="shaders_accurate_mul_description">Utiliza uma multiplicação mais precisa de shaders no hardware, o que pode corrigir problemas visuais. Quando ativada, pode haver redução no desempenho.</string>
<string name="asynchronous_gpu">Ativar emulação de GPU assíncrona</string>
<string name="asynchronous_gpu">Habilitar Emulação de GPU Assíncrona </string>
<string name="asynchronous_gpu_description">Usa uma thread separada para emular a GPU de forma assíncrona. Esta opção aprimora o desempenho quando ativada.</string>
<string name="frame_limit_enable">Limite de velocidade</string>
<string name="frame_limit_enable_description">Quando ativo, a velocidade de emulação será limitada à uma porcentagem especificada da velocidade normal. Se desativado, a velocidade de emulação será destravada e a tecla de atalho do turbo não irá funcionar.</string>
<string name="frame_limit_slider">Limite de velocidade percentual</string>
<string name="frame_limit_slider_description">Especifica a porcentagem para limitar a velocidade. Com o padrão de 100% a emulação será limitada a velocidade normal. Valores maiores ou menores vão aumentar ou reduzir o limite de velocidade.</string>
<string name="android_hide_images">Esconder Imagens do 3DS do Android</string>
<string name="android_hide_images_description">Prevenir câmera do 3DS, screenshots e texturas personalizadas de serem indexadas pelo Android e mostradas na galeria. Seu dispositivo pode precisar ser reiniciado após mudar essa configuração para as mudanças serem efetuadas.</string>
<string name="turbo_limit">Limite da Velocidade Turbo:</string>
<string name="turbo_limit_description">Limite de velocidade da emulação usado enquanto a tecla de atalho turbo está ativa.</string>
<string name="expand_to_cutout_area">Expandir para a área recortada</string>
@ -253,10 +268,18 @@
<string name="debug_warning">Aviso: modificar estas configurações tornará a emulação mais lenta</string>
<string name="stereoscopy">Estereoscopia</string>
<string name="render3d">Modo 3D Estereoscópico</string>
<string name="render3d_description">Escolha o modo 3D estereoscópico para a renderização 3D. Os modos Lado a Lado são os mais comuns atualmente. Os modos Anáglifo e Entrelaçado serão sempre aplicados a todas as telas conectadas.</string>
<string name="factor3d">Profundidade</string>
<string name="factor3d_description">Especifica o valor do controle deslizante 3D. Deve ser definido como superior a 0% quando o 3D Estereoscópico estiver ativado.\nNota: Valores de profundidade acima de 100% não são possíveis no hardware real e podem causar problemas gráficos</string>
<string name="disable_right_eye_render">Desativar a renderização do olho direito</string>
<string name="disable_right_eye_render_description">Melhora muito o desempenho em alguns aplicativos, mas pode causar piscadas em outros.</string>
<string name="swap_eyes_3d">Inverter Olhos</string>
<string name="swap_eyes_3d_description">Inverte qual olho é exibido em cada lado. Combinado com o modo Lado a Lado, torna possível ver em 3D cruzando os olhos!</string>
<string name="render_3d_which_display">Renderizar 3D Estereoscópico</string>
<string name="render_3d_which_display_description">Define se o 3D estereoscópico deve ser ativado e em quais telas. As opções de tela única só são relevantes quando várias telas estão conectadas.</string>
<string name="render_3d_which_display_both">Ativado (Todas as Telas)</string>
<string name="render_3d_which_display_primary">Ativado (Apenas Tela Principal)</string>
<string name="render_3d_which_display_secondary">Ativado (Apenas Tela Secundária)</string>
<string name="cardboard_vr">VR Cardboard </string>
<string name="cardboard_screen_size">Tamanho da Tela do Cardboard</string>
<string name="cardboard_screen_size_description">Dimensiona a tela para uma porcentagem de seu tamanho original.</string>
@ -281,7 +304,7 @@
<string name="audio_volume">Volume</string>
<string name="audio_stretch">Alongamento de Áudio</string>
<string name="audio_stretch_description">Estica o áudio para reduzir engasgos. Quando ativado, aumenta a latência do áudio e reduz levemente o desempenho.</string>
<string name="realtime_audio">Ativar áudio em tempo real</string>
<string name="realtime_audio">Ativar Áudio em Tempo Real</string>
<string name="realtime_audio_description">Dimensiona a velocidade de reprodução de áudio para compensar quedas na taxa de quadros da emulação. Isso significa que o áudio será reproduzido em velocidade máxima mesmo quando a taxa de quadros do jogo estiver baixa. Pode causar problemas de dessincronização de áudio.</string>
<string name="audio_input_type">Dispositivo de entrada de áudio</string>
<string name="sound_output_mode">Modo de Saída de Som</string>
@ -293,12 +316,12 @@
<string name="hw_shaders_description">Utiliza o hardware para emular os shaders do 3DS. Quando ativado, o desempenho do jogo será consideravelmente melhorado.</string>
<string name="cpu_clock_speed">Velocidade do Clock da CPU</string>
<string name="vsync">Ativar sincronização vertical</string>
<string name="vsync_description">Sincroniza a taxa de quadros do jogo com a taxa de atualização da tela do seu dispositivo.</string>
<string name="vsync_description">Sincroniza a taxa de quadros do jogo com a taxa de atualização do seu dispositivo. Pode causar latência de entrada adicional, mas pode reduzir o \"tearing\" (rasgo de tela) em alguns casos.</string>
<string name="renderer_debug">Renderizador de Depuração</string>
<string name="renderer_debug_description">Registre informações adicionais de depuração relacionadas a gráficos. Quando ativado, o desempenho do jogo será significativamente reduzido.</string>
<string name="instant_debug_log">Limpar a saída do log a cada mensagem</string>
<string name="instant_debug_log">Limpar a Saída do Log a Cada Mensagem</string>
<string name="instant_debug_log_description">Grava imediatamente o log de depuração no arquivo. Use isto se o Azahar travar e a saída do log estiver sendo cortada.</string>
<string name="delay_start_lle_modules">Atraso na inicialização com módulos LLE</string>
<string name="delay_start_lle_modules">Atraso na Inicialização com Módulos LLE</string>
<string name="delay_start_lle_modules_description">Atrasa a inicialização do aplicativo quando os módulos LLE estão ativados.</string>
<string name="deterministic_async_operations">Operações Assíncronas Determinísticas</string>
<string name="deterministic_async_operations_description">Torna as operações assíncronas determinísticas para depuração. Ativar essa opção pode causar congelamentos.</string>
@ -396,6 +419,10 @@
<string name="emulation_configure_controls">Configurar controles</string>
<string name="emulation_edit_layout">Editar Disposição</string>
<string name="emulation_done">Pronto</string>
<string name="emulation_button_sliding">Deslizar Botão</string>
<string name="emulation_button_sliding_disabled">Segurar o botão originalmente pressionado</string>
<string name="emulation_button_sliding_enabled">Segurar o botão atualmente pressionado</string>
<string name="emulation_button_sliding_alternative">Segurar o botão original e o atualmente pressionado</string>
<string name="emulation_toggle_controls">Alternar controles</string>
<string name="emulation_control_scale">Ajustar escala</string>
<string name="emulation_control_scale_global">Escala Global</string>
@ -408,6 +435,8 @@
<string name="emulation_aspect_ratio">Proporção da Tela</string>
<string name="emulation_switch_screen_layout">Disposição de tela em paisagem</string>
<string name="emulation_switch_portrait_layout">Disposição da tela em retrato</string>
<string name="emulation_switch_secondary_layout">Layout da Tela de Exibição Secundária</string>
<string name="emulation_switch_secondary_layout_description">O layout usado por uma tela secundária conectada, com ou sem fio (Chromecast, Miracast)</string>
<string name="emulation_screen_layout_largescreen">Tela Grande</string>
<string name="emulation_screen_layout_portrait">Retrato</string>
<string name="emulation_screen_layout_single">Tela única</string>
@ -415,7 +444,15 @@
<string name="emulation_screen_layout_hybrid">Telas Híbridas</string>
<string name="emulation_screen_layout_original">Original</string>
<string name="emulation_portrait_layout_top_full">Padrão</string>
<string name="emulation_secondary_display_default">Padrão do Sistema (espelhamento)</string>
<string name="emulation_screen_layout_custom">Disposição Personalizada</string>
<string name="bg_color">Cor de Fundo</string>
<string name="bg_color_description">A cor que aparece atrás das telas durante a emulação, representada por um valor RGB.</string>
<string name="bg_red">Vermelho</string>
<string name="bg_green">Verde</string>
<string name="bg_blue">Azul</string>
<string name="second_screen_opacity">Opacidade da Segunda Tela no Layout Personalizado</string>
<string name="second_screen_opacity_description">A opacidade da segunda tela do 3DS ao usar um layout de telas personalizado. Útil caso a segunda tela sobreponha a primeira.</string>
<string name="emulation_small_screen_position">Posição da Tela Pequena</string>
<string name="small_screen_position_description">Onde a tela pequena deverá aparecer relativa à grande na Disposição da Tela Grande?</string>
<string name="small_screen_position_top_right">Superior Direita</string>
@ -511,6 +548,8 @@
<string name="fatal_error">Erro Fatal</string>
<string name="fatal_error_message">Ocorreu um erro fatal. Verifique o registro para obter detalhes.\nContinuar a emulação pode resultar em falhas e bugs.</string>
<string name="unsupported_encrypted">Aplicativo criptografado não suportado</string>
<string name="invalid_system_mode">Modo de sistema inválido</string>
<string name="invalid_system_mode_message">Novos aplicativos exclusivos do New 3DS não podem ser carregados sem ativar o modo New 3DS.</string>
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Preparando Shaders</string>
@ -535,33 +574,39 @@
<string name="create_shortcut">Criar Atalho</string>
<string name="shortcut_name_empty">O nome do atalho não pode ficar vazio</string>
<string name="shortcut_image_stretch_toggle">Esticar para ajustar à imagem</string>
<string name="game_context_id">ID:</string>
<string name="game_context_file">Arquivo:</string>
<string name="game_context_type">Tipo:</string>
<string name="game_context_insert">Inserir Cartucho</string>
<string name="game_context_eject">Ejetar Cartucho</string>
<!-- Performance Overlay settings -->
<string name="performance_overlay_show">Mostrar Sobreposição de Desempenho</string>
<string name="performance_overlay_options">Sobreposição de Desempenho</string>
<string name="performance_overlay_enable">Ativa a Sobreposição de Desempenho</string>
<string name="performance_overlay_options_description">Configure se a sobreposição de desempenho será exibida e quais informações serão mostradas.</string>
<string name="overlay_show_fps">Mostrar FPS</string>
<string name="overlay_show_fps_description">Exibe a taxa de quadros atual por segundo.</string>
<string name="overlay_show_frametime">Mostrar Tempo de Quadro</string>
<string name="overlay_show_frametime_description">Exibe o tempo de quadro atual.</string>
<string name="overlay_show_speed">Mostrar Velocidade</string>
<string name="overlay_show_speed_description">Exibe a porcentagem atual da velocidade da emulação.</string>
<string name="overlay_show_app_ram_usage">Mostrar o Uso de Memória do Aplicativo</string>
<string name="overlay_show_app_ram_usage_description">Exibe a quantidade de RAM utilizada pelo emulador.</string>
<string name="overlay_show_available_ram">Mostrar Memória Disponível</string>
<string name="overlay_show_available_ram_description">Exibe a quantidade de RAM disponível.</string>
<string name="overlay_show_battery_temp">Mostrar a Temperatura da Bateria</string>
<string name="overlay_show_battery_temp_description">Exibe a temperatura atual da Bateria em Celsius e Fahrenheit.</string>
<string name="overlay_position">Posição da Sobreposição</string>
<string name="overlay_position_description">Escolha onde a sobreposição de desempenho será exibida na tela.</string>
<string name="overlay_position_top_left">Superior Esquerdo</string>
<string name="overlay_position_top_right">Superior Direito</string>
<string name="overlay_position_bottom_left">Inferior Esquerdo</string>
<string name="overlay_position_bottom_right">Inferior Direito</string>
<string name="overlay_position_center_top">Centro Superior</string>
<string name="overlay_position_center_bottom">Centro Inferior</string>
<string name="overlay_background">Plano de Fundo da Sobreposição</string>
<string name="overlay_background_description">Adiciona um plano de fundo atrás da sobreposição para facilitar a leitura.</string>
<string name="performance_overlay_show_fps">Mostrar FPS</string>
<string name="performance_overlay_show_fps_description">Mostrar frames por segundo atuais.</string>
<string name="performance_overlay_show_frametime">Mostrar tempo de frame</string>
<string name="performance_overlay_show_frametime_description">Mostrar tempo de frame atual.</string>
<string name="performance_overlay_show_speed">Mostrar velocidade</string>
<string name="performance_overlay_show_speed_description">Mostrar atual porcentagem de velocidade da emulação.</string>
<string name="performance_overlay_show_app_ram_usage">Mostrar Uso da Memória pelo App</string>
<string name="performance_overlay_show_app_ram_usage_description">Mostrar o consumo de RAM pelo emulador.</string>
<string name="performance_overlay_show_available_ram">Mostrar Memória Disponível </string>
<string name="performance_overlay_show_available_ram_description">Mostrar a quantidade de RAM livre.</string>
<string name="performance_overlay_show_battery_temp">Mostrar Temperatura da Bateria</string>
<string name="performance_overlay_show_battery_temp_description">Mostrar atual temperatura da Bateria em Celsius e Fahrenheit.</string>
<string name="performance_overlay_position">Posição do Overlay</string>
<string name="performance_overlay_position_description">Escolha onde o overlay de performance é mostrado na tela.</string>
<string name="performance_overlay_position_top_left">Canto Superior Esquerdo</string>
<string name="performance_overlay_position_top_right">Canto Superior Direito</string>
<string name="performance_overlay_position_bottom_left">Canto Inferior Esquerdo</string>
<string name="performance_overlay_position_bottom_right">Canto Inferior Direito</string>
<string name="performance_overlay_position_center_top">Superior Central</string>
<string name="performance_overlay_position_center_bottom">Inferior Central</string>
<string name="performance_overlay_background">Plano de Fundo da Sobreposição</string>
<string name="performance_overlay_background_description">Adiciona um plano de fundo atrás do overlay para uma leitura mais fácil.</string>
<!-- Cheats -->
<string name="cheats">Truques</string>
@ -666,7 +711,7 @@
<!-- Render 3D modes -->
<string name="side_by_side">Lado a Lado</string>
<string name="reverse_side_by_side">Inverter Lado a Lado</string>
<string name="side_by_side_full">Lado a Lado (Largura Total)</string>
<string name="anaglyph">Anáglifo</string>
<string name="interlaced">Entrelaçado</string>
<string name="reverse_interlaced">Entrelaçado Reverso</string>
@ -855,4 +900,19 @@
<string name="emulation_occupied_quicksave_slot">Salvar rápido - %1$tF %1$tR</string>
<string name="quickload_not_found">Nenhum Salvamento Rápido disponível.</string>
<!-- File Compression -->
<string name="compress">Compactar</string>
<string name="compressing">Compactando...</string>
<string name="decompress">Descompactar</string>
<string name="decompressing">Descompactando...</string>
<string name="compress_success">Compactação concluída com sucesso.</string>
<string name="compress_unsupported">Compactação não suportada para este arquivo.</string>
<string name="compress_already">O arquivo já está compactado.</string>
<string name="compress_failed">A compactação falhou.</string>
<string name="decompress_success">Descompactação concluída com sucesso.</string>
<string name="decompress_unsupported">Descompactação não suportada para este arquivo.</string>
<string name="decompress_not_compressed">O arquivo não está compactado.</string>
<string name="decompress_failed">A descompactação falhou.</string>
<string name="compress_decompress_installed_app">Aplicativos já instalados não podem ser compactados ou descompactados.</string>
</resources>

View File

@ -70,8 +70,6 @@
<string name="input_dialog_description">Нажмите или отклоните элемент управления.</string>
<string name="input_binding">Привязки ввода</string>
<string name="input_binding_description">Нажмите или отклоните орган управления для привязки %1$s.</string>
<string name="input_binding_description_vertical_axis">Наклоните джойстик вверх или вниз.</string>
<string name="input_binding_description_horizontal_axis">Наклоните джойстик влево или вправо.</string>
<string name="button_home">HOME</string>
<string name="input_message_analog_only">Данный элемент управления должен быть привязан к аналоговому стику или крестовине геймпада!</string>
<string name="input_message_button_only">Данный элемент управления должен быть привязан к кнопке геймпада!</string>
@ -120,14 +118,12 @@
<string name="graphics_api">Графический API</string>
<string name="spirv_shader_gen">Вкл. генерацию шейдеров на SPIR-V</string>
<string name="spirv_shader_gen_description">Запускать фрагментный шейдер, используемый для эмуляции PICA на SPIR-V вместо GLSL.</string>
<string name="async_shaders">Вкл. асинхронную компиляцию шейдеров</string>
<string name="async_shaders_description">Компилировать шейдеры в фоновом потоке для уменьшения лагов во время игры. При включении возможны временные сбои графики.</string>
<string name="linear_filtering">Линейное сглаживание</string>
<string name="linear_filtering_description">Вкл. линейное сглаживание для смягчения графики в играх.</string>
<string name="texture_filter_name">Сглаживание текстур</string>
<string name="shaders_accurate_mul">Точное умножение</string>
<string name="shaders_accurate_mul_description">Исп. более точное умножение для аппаратных шейдеров. Может исправлять некоторые графические баги, но при включении снижает производительность.</string>
<string name="asynchronous_gpu">Вкл. асинхронную эмуляцию GPU</string>
<string name="asynchronous_gpu_description">Использовать отдельный поток для асинхронной эмуляции GPU. При включении повышает производительность.</string>
<string name="frame_limit_enable">Ограничивать скорость</string>
<string name="frame_limit_slider">Процент ограничения скорости</string>
@ -172,7 +168,6 @@
<string name="hw_shaders_description">Эмулировать шейдеры 3DS аппаратными средствами. При включении существенно повышает производительность в играх.</string>
<string name="cpu_clock_speed">Скорость процессора</string>
<string name="vsync">Вкл. V-Sync</string>
<string name="vsync_description">Синхронизирует кадровую частоту в играх с частотой обновления устройства.</string>
<string name="renderer_debug">Отладка рендера</string>
<string name="renderer_debug_description">Логировать расширенную отладочную информацию по графике. При включении существенно снижает производительность.</string>
<!-- Miscellaneous -->

View File

@ -74,6 +74,9 @@
<string name="permission_denied">İzin reddedildi</string>
<string name="add_games_warning">Uygulama dosyasını seçmeyi atla?</string>
<string name="add_games_warning_description">Eğer bir dosya seçili değilse yazılımlar uygulama listesinde görünmeyecektir.</string>
<string name="permissions">İzinler</string>
<string name="select_emulator_data_folders">Veri Klasörleri</string>
<string name="permissions_description">Emülatörün belirli özelliklerini kullanmak için isteğe bağlı izinler verin</string>
<string name="warning_help">Yardım</string>
<string name="warning_skip">Atla</string>
<string name="warning_cancel">İptal et</string>
@ -83,6 +86,7 @@
<string name="keep_current_azahar_directory">Şimdiki Azahar Dizinini Koru</string>
<string name="use_prior_lime3ds_directory">Eski Lime3DS Dizinini Kullan</string>
<string name="select">Seç</string>
<string name="cannot_skip">Kullanıcı klasörü ayarlamayı atlayamazsınız</string>
<string name="cannot_skip_directory_description">Bu adım Azahar\'ın çalışması için gereklidir. Lütfen devam etmek için bir dizin seçin.</string>
<string name="selecting_user_directory_without_write_permissions">Kayıtların ve diğer bilgilerin depolandığı <a href="https://web.archive.org/web/20240304193549/https://github.com/citra-emu/citra/wiki/Citra-Android-user-data-and-storage">kullanıcı verileri</a>dizininizdeki yazma izinlerini kaybettiniz. Bu durum bazı uygulama veya Android güncellemelerinden sonra meydana gelebilir. Devam edebilmeniz için lütfen izinleri yeniden kazanmak üzere dizini yeniden seçin.</string>
<string name="set_up_theme_settings">Tema Ayarları</string>
@ -117,8 +121,6 @@
<string name="input_dialog_description">Bir girdiye basın veya hareket ettirin.</string>
<string name="input_binding">Girdi Ataması</string>
<string name="input_binding_description">Bir girdiyi %1$s e atamak için basın veya hareket ettirin.</string>
<string name="input_binding_description_vertical_axis">Joystick\'inizi yukarı veya aşağı kaydırın.</string>
<string name="input_binding_description_horizontal_axis">Joystick\'inizi sağa veya sola kaydırın.</string>
<string name="button_home">HOME</string>
<string name="button_swap">Ekranları değiştir</string>
<string name="button_turbo">Turbo</string>
@ -185,6 +187,7 @@
<string name="region_mismatch">Bölge Uyuşmazlık Uyarısı</string>
<string name="region_mismatch_emulated">Ülke ayarı emülasyon bölgesi için geçerli değil.</string>
<string name="region_mismatch_console">Ülke ayarı bağlı olan konsol için geçerli değil.</string>
<string name="storage">Depolama</string>
<!-- Camera settings strings -->
<string name="inner_camera"> 
İç Kamera</string>
@ -196,23 +199,24 @@
<string name="camera_device_description">“Görüntü Kaynağı” ayarı Cihaz Kamerası olarak ayarlanmışsa, bu ayar kullanılacak fiziksel kamerayı ayarlar.</string>
<string name="camera_facing_front">Ön</string>
<string name="camera_facing_back">Geri</string>
<string name="camera_facing_external">Harici</string>
<string name="image_flip">Çevir</string>
<!-- Graphics settings strings -->
<string name="renderer">İşleyici</string>
<string name="graphics_api">Grafik API\'ı</string>
<string name="spirv_shader_gen">SPIR-V gölgelendirici oluşturmayı etkinleştir</string>
<string name="async_shaders">Asenkron gölgeleme derlemesini etkinleştir</string>
<string name="async_shaders_description">Oyun sırasında takılmayı azaltmak için gölgelendiricileri arka planda derler. Etkinleştirildiğinde geçici grafik hataları meydana gelebilir.</string>
<string name="linear_filtering">Doğrusal filtreleme</string>
<string name="linear_filtering_description">Oyun görsellerinin daha pürüzsüz görünmesini sağlayan doğrusal filtrelemeyi etkinleştirir.</string>
<string name="texture_filter_name">Doku Filtresi</string>
<string name="texture_filter_description">Dokulara bir filtre uygulayarak uygulamaların görsellerini geliştirir. Desteklenen filtreler Anime4K Ultrafast, Bicubic, ScaleForce, xBRZ freescale ve MMPX\'tir.</string>
<string name="delay_render_thread">Oyun işleme iş parçacığını geciktir</string>
<string name="delay_render_thread_description">GPU\'ya veri gönderirken oyun işleme iş parçacığını geciktirin. Dinamik kare hızlarına sahip (çok az sayıda) uygulamada performans sorunlarına yardımcı olur.</string>
<string name="advanced">Gelişmiş</string>
<string name="texture_sampling_name">Doku Örnekleme</string>
<string name="texture_sampling_description">Uygulamalar tarafından kullanılan örnekleme filtresini geçersiz kılar. Bu, görüntü yükseltme sırasında hatalı davranan uygulamaların olduğu bazı durumlarda faydalı olabilir. Emin değilseniz, bunu Uygulama Kontrollü olarak ayarlayın.</string>
<string name="shaders_accurate_mul">İsabetli Çoğaltma</string>
<string name="shaders_accurate_mul_description">Donanım gölgelendiricilerinde daha doğru çarpım kullanır, bu da bazı grafik hatalarını düzeltebilir. Etkinleştirildiğinde performans düşecektir.</string>
<string name="asynchronous_gpu">Asenkron GPU emülasyonunu etkinleştir</string>
<string name="asynchronous_gpu_description">GPU emülasyonunu asenkron olarak yapmak için ayrı bir iş parçacığı kullanır. Etkinleştirildiğinde performans artacaktır.</string>
<string name="frame_limit_enable">Hızı Sınırlandır</string>
<string name="frame_limit_enable_description">Etkinleştirildiğinde, emülasyon hızı normal hızın belirli bir yüzdesiyle sınırlandırılır. Devre dışı bırakılırsa, emülasyon hızı sınırlandırılmaz ve turbo hız kısayol tuşu çalışmaz.</string>
@ -220,6 +224,7 @@
<string name="frame_limit_slider_description">Emülasyon hızını sınırlamak için yüzdeyi belirtir. Varsayılan değer olan %100 ile emülasyon normal hız ile sınırlandırılacaktır. Daha yüksek veya daha düşük değerler hız sınırını artıracak veya azaltacaktır Etkinleştirildiğinde, emülasyon hızı normal hızın belirli bir yüzdesiyle sınırlandırılacaktır. Devre dışı bırakılırsa, emülasyon hızı sınırlandırılmaz ve turbo hız kısayol tuşu çalışmaz.</string>
<string name="turbo_limit">Turbo Hız Limiti</string>
<string name="turbo_limit_description">Turbo kısayolu aktfiken kullanılan emülasyon hız limiti.</string>
<string name="expand_to_cutout_area">Kesme Alanına Genişlet</string>
<string name="internal_resolution">İç Çözünürlük</string>
<string name="internal_resolution_description">Render için kullanılan çözünürlüğü belirtir. Yüksek çözünürlük görsel kaliteyi çok artıracaktır ancak performans açısından da oldukça ağırdır ve bazı uygulamalarda aksaklıklara neden olabilir.</string>
<string name="internal_resolution_setting_auto">Otomatik (Ekran Boyutu)</string>
@ -259,7 +264,7 @@
<string name="audio_volume">Ses düzeyi</string>
<string name="audio_stretch">Ses Gerdirme</string>
<string name="audio_stretch_description">Takılmayı azaltmak için sesi esnetir. Etkinleştirildiğinde, ses gecikmesini artırır ve performansı biraz düşürür.</string>
<string name="realtime_audio">Gerçek zamanlı sesi etkinleştir</string>
<string name="realtime_audio">Gerçek Zamanlı Sesi Etkinleştir</string>
<string name="realtime_audio_description">Emülasyon kare hızındaki düşüşleri hesaba katmak için ses çalma hızını ölçeklendirir. Bu, oyun kare hızı düşük olsa bile sesin tam hızda çalınacağı anlamına gelir. Ses senkronizasyon sorunlarına neden olabilir.</string>
<string name="audio_input_type">Ses Giriş Cihazı</string>
<string name="sound_output_mode">Ses Çıkış Modu</string>
@ -271,15 +276,13 @@
<string name="hw_shaders_description">3DS shader\'larının emülasyonu için donanımı kullanır. Etkinleştirildiğinde oyun performansı önemli ölçüde artacaktır.</string>
<string name="cpu_clock_speed">CPU Saat Hızı</string>
<string name="vsync">V-Sync\'i Etkinleştir</string>
<string name="vsync_description">Oyun kare hızını cihazınızın yenileme hızına senkronize eder.</string>
<string name="renderer_debug">Hata Ayıklama İşleyicisi</string>
<string name="renderer_debug_description">Grafiklerle ilgili ek hata ayıklama bilgilerini günlüğe kaydedin. Etkinleştirildiğinde, oyun performansı önemli ölçüde azalacaktır.</string>
<string name="instant_debug_log">Her mesajda günlük çıktısını temizle</string>
<string name="instant_debug_log_description">Hata ayıklama günlüğünü hemen dosyaya işler. Azahar çöküyor ve günlük çıktısı kesiliyorsa bunu kullanın.</string>
<string name="delay_start_lle_modules">LLE modülleriyle başlamayı geciktir</string>
<string name="delay_start_lle_modules_description">LLE modülleri etkinken uygulamanın başlamasını geciktirir</string>
<string name="deterministic_async_operations">Deterministik Asenkron İşlemler</string>
<string name="deterministic_async_operations_description">Hata ayıklama için asenkron işlemleri deterministik hale getirir. Bunu etkinleştirmek donmalara neden olabilir.</string>
<string name="enable_rpc_server">RPC Sunucusunu Etkinleştir</string>
<!-- Layout settings strings -->
<string name="layout_screen_orientation">Ekran Yönelimi</string>
<string name="layout_screen_orientation_auto_sensor">Otomatik</string>
@ -287,6 +290,13 @@
<string name="layout_screen_orientation_landscape_reverse">Ters Yatay</string>
<string name="layout_screen_orientation_portrait">Portre</string>
<string name="layout_screen_orientation_portrait_reverse">Ters Portre</string>
<string name="aspect_ratio_default">Varsayılan</string>
<string name="aspect_ratio_16_9">16:9</string>
<string name="aspect_ratio_4_3">4:3</string>
<string name="aspect_ratio_21_9_fullscreen">21:9</string>
<string name="aspect_ratio_16_10_fullscreen_stretched">16:10</string>
<string name="aspect_ratio_stretch">Gerdir</string>
<!-- Miscellaneous -->
<string name="clear">Temizle</string>
<string name="slider_default">Varsayılan</string>
@ -302,6 +312,7 @@
<string name="reset_to_default">Varsayılanlara Sıfırla</string>
<string name="redump_games"><![CDATA[Lütfen <a href=\"https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/dumping-game-cartridges/\">oyun kartuşlarınızı</a> veya <a href=\"https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/dumping-installed-titles/\">yüklü başlıklarınızı</a>yeniden yüklemek için kılavuzları izleyin.]]></string>
<string name="option_default">Varsayılan</string>
<string name="auto">Otomatik</string>
<string name="off">Kapalı</string>
<string name="install">Yükle</string>
<string name="delete">Sil</string>
@ -320,6 +331,9 @@
<string name="cancelling">İptal ediliyor...</string>
<string name="important">Önemli</string>
<string name="dont_show_again">Tekrar gösterme</string>
<string name="visibility">Görünürlük</string>
<string name="information">Bilgi</string>
<!-- Add Directory Screen-->
<string name="select_game_folder">Oyun Dosyası Seç</string>
@ -357,12 +371,14 @@
<string name="emulation_configure_controls">Kontrolleri Yapılandır</string>
<string name="emulation_edit_layout">Düzeni Değiştir</string>
<string name="emulation_done">Bitti</string>
<string name="emulation_button_sliding">Buton Kayması</string>
<string name="emulation_control_scale">Ölçeği Ayarla</string>
<string name="emulation_control_scale_reset_all">Tümünü Sıfırla</string>
<string name="emulation_control_opacity">Görünürlüğü Ayarla</string>
<string name="emulation_control_dpad_slide_enable">D-Pad kayması</string>
<string name="emulation_open_settings">Ayarları</string>
<string name="emulation_open_cheats">Hileleri Aç</string>
<string name="emulation_aspect_ratio">En Boy Oranı</string>
<string name="emulation_switch_screen_layout">Yatay Ekran Düzeni</string>
<string name="emulation_switch_portrait_layout">Dikey Ekran Düzeni</string>
<string name="emulation_screen_layout_largescreen">Büyük Ekran</string>
@ -372,7 +388,12 @@
<string name="emulation_screen_layout_hybrid">Hibrit Ekranlar</string>
<string name="emulation_screen_layout_original">Orijinal</string>
<string name="emulation_portrait_layout_top_full">Varsayılan</string>
<string name="emulation_secondary_display_default">Sistem Varsayılanı (ayna)</string>
<string name="emulation_screen_layout_custom">Özel Düzen</string>
<string name="bg_color">Arkaplan Rengi</string>
<string name="bg_red">Kırmızı</string>
<string name="bg_green">Yeşil</string>
<string name="bg_blue">Mavi</string>
<string name="emulation_small_screen_position">Küçük Ekran Konumu</string>
<string name="small_screen_position_description">Büyük Ekran Düzeninde küçük ekran büyük ekrana kıyasla nerede olmalı?</string>
<string name="small_screen_position_top_right">Sağ Üst</string>
@ -398,6 +419,7 @@
<string name="emulation_custom_layout_height">Yükseklik</string>
<string name="emulation_swap_screens">Ekranları Değiştir</string>
<string name="emulation_touch_overlay_reset">Yerleşimi Sıfırla</string>
<string name="emulation_show_controller_overlay">Kontrolcü Yerleşimini Göster</string>
<string name="emulation_close_game">Oyunu Kapat</string>
<string name="emulation_toggle_pause">Duraklatmayı Aç / Kapat</string>
<string name="miscellaneous">Çeşitli</string>
@ -462,7 +484,6 @@
<string name="fatal_error">Ölümcül Hata</string>
<string name="fatal_error_message">Ölümcül bir hata oluştu. Ayrıntılar için log\'u kontrol edin.\nEmülasyona devam etmek çökmelere ve hatalara neden olabilir.</string>
<string name="unsupported_encrypted">Desteklenmeyen şifreli uygulama</string>
<!-- Disk Shader Cache -->
<string name="preparing_shaders">Gölgelendiriciler Hazırlanıyor</string>
<string name="building_shaders">Gölgelendiriciler Oluşturuluyor</string>
@ -481,6 +502,22 @@
<string name="game_context_uninstall_dlc">DLC\'leri Sil</string>
<string name="game_context_uninstall_updates">Güncellemeleri Sil</string>
<string name="shortcut">Kısayol</string>
<string name="shortcut_name">Kısayol Adı</string>
<string name="edit_icon">Simgeyi düzenle</string>
<string name="create_shortcut">Kısayol Oluştur</string>
<string name="game_context_id">ID:</string>
<string name="game_context_file">Dosya:</string>
<string name="game_context_type">Tür:</string>
<string name="performance_overlay_show_fps">FPS\'i Göster</string>
<string name="performance_overlay_show_speed">Hızı Göster</string>
<string name="performance_overlay_show_available_ram">Kullanılabilir Belleği Göster</string>
<string name="performance_overlay_show_battery_temp">Pil Sıcaklığını Göster</string>
<string name="performance_overlay_position_top_left">Sol Üst</string>
<string name="performance_overlay_position_top_right">Sağ Üst</string>
<string name="performance_overlay_position_bottom_left">Sol Alt</string>
<string name="performance_overlay_position_bottom_right">Sağ Alt</string>
<string name="performance_overlay_position_center_top">Orta Üst</string>
<string name="performance_overlay_position_center_bottom">Orta Alt</string>
<!-- Cheats -->
<string name="cheats">Hileler</string>
<string name="cheats_add">Hile Ekle</string>
@ -583,7 +620,6 @@
<!-- Render 3D modes -->
<string name="side_by_side">Yan Yana</string>
<string name="reverse_side_by_side">Ters Yan Yana</string>
<string name="anaglyph">Anaglif</string>
<string name="interlaced">Geçmeli</string>
<string name="reverse_interlaced">Ters Geçmeli</string>
@ -601,6 +637,7 @@
<!-- Texture Sampling names -->
<string name="game_controlled">Oyun Kontrollü</string>
<string name="nearest_neighbor">En Yakın Komşu</string>
<string name="linear">Lineer</string>
<!-- Sound output modes -->
@ -771,4 +808,4 @@
<string name="emulation_occupied_quicksave_slot">Hızlı Kayıt - %1$tF %1$tR</string>
<string name="quickload_not_found">Hiçbir Hızlı Kayıt mevcut değil.</string>
</resources>
</resources>

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