mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-10 03:18:55 +02:00
Compare commits
40 commits
00656d6841
...
077b7bf4a5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
077b7bf4a5 | ||
|
|
77702c11b3 | ||
|
|
5a3734cb33 | ||
|
|
8c14f92549 | ||
|
|
4d62b5d409 | ||
|
|
0173baa661 | ||
|
|
ba1362e950 | ||
|
|
fdf970860c | ||
|
|
ac7be8fe9e | ||
|
|
4c36f4cd43 | ||
|
|
3e94e2e646 | ||
|
|
1bd5cbe033 | ||
|
|
c29bb23c05 | ||
|
|
e78edf193a | ||
|
|
c9419110f1 | ||
|
|
07306dd7ee | ||
|
|
d6c0f47b8c | ||
|
|
e0894b4938 | ||
|
|
483d82703b | ||
|
|
faaf66842e | ||
|
|
499d583849 | ||
|
|
ce1449f425 | ||
|
|
6fbc091e7f | ||
|
|
3fd2ff0079 | ||
|
|
37b2a98b02 | ||
|
|
ab80e33ada | ||
|
|
09ac61c781 | ||
|
|
a1b50e9339 | ||
|
|
f5e2b1fb13 | ||
|
|
6693b99ae4 | ||
|
|
f8ea09fa0f | ||
|
|
361e6209b2 | ||
|
|
3d1a67af18 | ||
|
|
c7b23f4a1a | ||
|
|
38aa2bc5e1 | ||
|
|
1864160326 | ||
|
|
0a169dec4d | ||
|
|
80bafc8fe8 | ||
|
|
f2c46eadc1 | ||
|
|
7a17fd8c71 |
116 changed files with 4562 additions and 731 deletions
34
.ci/ios/build.sh
Executable file
34
.ci/ios/build.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/sh -ex
|
||||
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
WORK_DIR="$PWD"
|
||||
export IOS_SDK="$(xcrun --sdk iphoneos --show-sdk-path)"
|
||||
|
||||
[ ! -z "$IOS_SDK" ]
|
||||
|
||||
cmake -G Xcode -B build \
|
||||
-DCMAKE_TOOLCHAIN_FILE="$WORK_DIR/.ci/ios/ios-toolchain.cmake" \
|
||||
-DPLATFORM=OS64 \
|
||||
-DDEPLOYMENT_TARGET=16.0 \
|
||||
-DCOCOA_LIBRARY="$IOS_SDK/System/Library/Frameworks/Cocoa.framework" \
|
||||
-DCMAKE_C_COMPILER="$(xcrun --sdk iphoneos clang -arch arm64)" \
|
||||
-DCMAKE_CXX_COMPILER="$(xcrun --sdk iphoneos clang++ -arch arm64)" \
|
||||
-DENABLE_LIBUSB=OFF \
|
||||
-DENABLE_UPDATE_CHECKER=OFF \
|
||||
-DENABLE_QT=OFF \
|
||||
-DENABLE_OPENSSL=OFF \
|
||||
-DENABLE_WEB_SERVICE=OFF \
|
||||
-DENABLE_CUBEB=OFF \
|
||||
-DYUZU_ROOM=OFF \
|
||||
-DYUZU_ROOM_STANDALONE=OFF \
|
||||
-DYUZU_STATIC_ROOM=OFF \
|
||||
-DYUZU_CMD=OFF \
|
||||
-DUSE_DISCORD_PRESENCE=OFF \
|
||||
-DYUZU_USE_EXTERNAL_FFMPEG=ON \
|
||||
-DYUZU_USE_EXTERNAL_SDL2=ON \
|
||||
-DCPMUTIL_FORCE_BUNDLED=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
cmake --build build
|
||||
1180
.ci/ios/ios-toolchain.cmake
Normal file
1180
.ci/ios/ios-toolchain.cmake
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -115,7 +115,7 @@ for file in $FILES; do
|
|||
*.cmake|*.sh|*CMakeLists.txt)
|
||||
begin="#"
|
||||
;;
|
||||
*.kt*|*.cpp|*.h)
|
||||
*.kt*|*.cpp|*.h|*.swift|*.mm)
|
||||
begin="//"
|
||||
;;
|
||||
*)
|
||||
|
|
@ -193,7 +193,7 @@ if [ "$UPDATE" = "true" ]; then
|
|||
begin="#"
|
||||
shell=true
|
||||
;;
|
||||
*.kt*|*.cpp|*.h)
|
||||
*.kt*|*.cpp|*.h|*.swift|*.mm)
|
||||
begin="//"
|
||||
shell="false"
|
||||
;;
|
||||
|
|
|
|||
31
.patch/boost/0002-ios-fix.patch
Normal file
31
.patch/boost/0002-ios-fix.patch
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
diff --git a/libs/process/src/shell.cpp b/libs/process/src/shell.cpp
|
||||
index bf4bbfd8..bc4aae89 100644
|
||||
--- a/libs/process/src/shell.cpp
|
||||
+++ b/libs/process/src/shell.cpp
|
||||
@@ -19,7 +19,7 @@
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
-#elif !defined(__OpenBSD__) && !defined(__ANDROID__)
|
||||
+#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE)
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@ BOOST_PROCESS_V2_DECL const error_category& get_shell_category()
|
||||
{
|
||||
return system_category();
|
||||
}
|
||||
-#elif !defined(__OpenBSD__) && !defined(__ANDROID__)
|
||||
+#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE)
|
||||
|
||||
struct shell_category_t final : public error_category
|
||||
{
|
||||
@@ -99,7 +99,7 @@ auto shell::args() const-> args_type
|
||||
return input_.c_str();
|
||||
}
|
||||
|
||||
-#elif !defined(__OpenBSD__) && !defined(__ANDROID__)
|
||||
+#elif !defined(__OpenBSD__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IPHONE)
|
||||
|
||||
void shell::parse_()
|
||||
{
|
||||
89
.patch/httplib/0002-fix-zstd.patch
Normal file
89
.patch/httplib/0002-fix-zstd.patch
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
From 509be32bbfa6eb95014860f7c9ea6d45c8ddaa56 Mon Sep 17 00:00:00 2001
|
||||
From: crueter <crueter@eden-emu.dev>
|
||||
Date: Sun, 8 Mar 2026 15:11:12 -0400
|
||||
Subject: [PATCH] [cmake] Simplify zstd find logic, and support pre-existing
|
||||
zstd target
|
||||
|
||||
Some deduplication work on the zstd required/if-available logic. Also
|
||||
adds support for pre-existing `zstd::libzstd` which is useful for
|
||||
projects that bundle their own zstd in a way that doesn't get caught by
|
||||
`CONFIG`
|
||||
|
||||
Signed-off-by: crueter <crueter@eden-emu.dev>
|
||||
---
|
||||
CMakeLists.txt | 46 ++++++++++++++++++++++++++--------------------
|
||||
1 file changed, 26 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 1874e36be0..8d31198006 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -241,28 +241,34 @@ endif()
|
||||
# NOTE:
|
||||
# zstd < 1.5.6 does not provide the CMake imported target `zstd::libzstd`.
|
||||
# Older versions must be consumed via their pkg-config file.
|
||||
-if(HTTPLIB_REQUIRE_ZSTD)
|
||||
- find_package(zstd 1.5.6 CONFIG)
|
||||
- if(NOT zstd_FOUND)
|
||||
- find_package(PkgConfig REQUIRED)
|
||||
- pkg_check_modules(zstd REQUIRED IMPORTED_TARGET libzstd)
|
||||
- add_library(zstd::libzstd ALIAS PkgConfig::zstd)
|
||||
- endif()
|
||||
- set(HTTPLIB_IS_USING_ZSTD TRUE)
|
||||
-elseif(HTTPLIB_USE_ZSTD_IF_AVAILABLE)
|
||||
- find_package(zstd 1.5.6 CONFIG QUIET)
|
||||
- if(NOT zstd_FOUND)
|
||||
- find_package(PkgConfig QUIET)
|
||||
- if(PKG_CONFIG_FOUND)
|
||||
- pkg_check_modules(zstd QUIET IMPORTED_TARGET libzstd)
|
||||
-
|
||||
- if(TARGET PkgConfig::zstd)
|
||||
+if (HTTPLIB_REQUIRE_ZSTD)
|
||||
+ set(HTTPLIB_ZSTD_REQUESTED ON)
|
||||
+ set(HTTPLIB_ZSTD_REQUIRED REQUIRED)
|
||||
+elseif (HTTPLIB_USE_ZSTD_IF_AVAILABLE)
|
||||
+ set(HTTPLIB_ZSTD_REQUESTED ON)
|
||||
+ set(HTTPLIB_ZSTD_REQUIRED QUIET)
|
||||
+endif()
|
||||
+
|
||||
+if (HTTPLIB_ZSTD_REQUESTED)
|
||||
+ if (TARGET zstd::libzstd)
|
||||
+ set(HTTPLIB_IS_USING_ZSTD TRUE)
|
||||
+ else()
|
||||
+ find_package(zstd 1.5.6 CONFIG QUIET)
|
||||
+
|
||||
+ if (NOT zstd_FOUND)
|
||||
+ find_package(PkgConfig ${HTTPLIB_ZSTD_REQUIRED})
|
||||
+ pkg_check_modules(zstd ${HTTPLIB_ZSTD_REQUIRED} IMPORTED_TARGET libzstd)
|
||||
+
|
||||
+ if (TARGET PkgConfig::zstd)
|
||||
add_library(zstd::libzstd ALIAS PkgConfig::zstd)
|
||||
endif()
|
||||
endif()
|
||||
+
|
||||
+ # This will always be true if zstd is required.
|
||||
+ # If zstd *isn't* found when zstd is set to required,
|
||||
+ # CMake will error out earlier in this block.
|
||||
+ set(HTTPLIB_IS_USING_ZSTD ${zstd_FOUND})
|
||||
endif()
|
||||
- # Both find_package and PkgConf set a XXX_FOUND var
|
||||
- set(HTTPLIB_IS_USING_ZSTD ${zstd_FOUND})
|
||||
endif()
|
||||
|
||||
# Used for default, common dirs that the end-user can change (if needed)
|
||||
@@ -317,13 +323,13 @@ if(HTTPLIB_COMPILE)
|
||||
$<BUILD_INTERFACE:${_httplib_build_includedir}/httplib.h>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/httplib.h>
|
||||
)
|
||||
-
|
||||
+
|
||||
# Add C++20 module support if requested
|
||||
# Include from separate file to prevent parse errors on older CMake versions
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28")
|
||||
include(cmake/modules.cmake)
|
||||
endif()
|
||||
-
|
||||
+
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
VERSION ${${PROJECT_NAME}_VERSION}
|
||||
33
.patch/spirv-tools/0003-ios-fix.patch
Normal file
33
.patch/spirv-tools/0003-ios-fix.patch
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
|
||||
index 7ab2319..333e325 100644
|
||||
--- a/source/CMakeLists.txt
|
||||
+++ b/source/CMakeLists.txt
|
||||
@@ -151,9 +151,11 @@ add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC}
|
||||
COMMENT "Update build-version.inc in the SPIRV-Tools build directory (if necessary).")
|
||||
# Convenience target for standalone generation of the build-version.inc file.
|
||||
# This is not required for any dependence chain.
|
||||
-add_custom_target(spirv-tools-build-version
|
||||
- DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC})
|
||||
-set_property(TARGET spirv-tools-build-version PROPERTY FOLDER "SPIRV-Tools build")
|
||||
+if (NOT IOS)
|
||||
+ add_custom_target(spirv-tools-build-version
|
||||
+ DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC})
|
||||
+ set_property(TARGET spirv-tools-build-version PROPERTY FOLDER "SPIRV-Tools build")
|
||||
+endif()
|
||||
|
||||
list(APPEND PCH_DEPENDS
|
||||
${CORE_TABLES_HEADER_INC_FILE}
|
||||
@@ -338,8 +340,11 @@ function(spirv_tools_default_target_options target)
|
||||
)
|
||||
set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools libraries")
|
||||
spvtools_check_symbol_exports(${target})
|
||||
- add_dependencies(${target}
|
||||
- spirv-tools-build-version core_tables extinst_tables)
|
||||
+ if (IOS)
|
||||
+ add_dependencies(${target} core_tables extinst_tables)
|
||||
+ else ()
|
||||
+ add_dependencies(${target} spirv-tools-build-version core_tables extinst_tables)
|
||||
+ endif()
|
||||
endfunction()
|
||||
|
||||
if (SPIRV_TOOLS_BUILD_SHARED)
|
||||
|
|
@ -212,7 +212,7 @@ option(YUZU_LEGACY "Apply patches that improve compatibility with older GPUs (e.
|
|||
|
||||
option(NIGHTLY_BUILD "Use Nightly qualifiers in the update checker and build metadata" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID AND NOT IOS" OFF)
|
||||
cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "NOT ANDROID" OFF)
|
||||
|
|
@ -283,7 +283,7 @@ if (YUZU_ROOM)
|
|||
add_compile_definitions(YUZU_ROOM)
|
||||
endif()
|
||||
|
||||
if ((ANDROID OR APPLE OR UNIX) AND (NOT PLATFORM_LINUX OR ANDROID) AND NOT WIN32)
|
||||
if ((ANDROID OR APPLE OR UNIX OR IOS) AND (NOT PLATFORM_LINUX OR ANDROID) AND NOT WIN32)
|
||||
if(CXX_APPLE OR CXX_CLANG)
|
||||
# libc++ has stop_token and jthread as experimental
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
|
||||
|
|
@ -487,7 +487,12 @@ if (APPLE)
|
|||
# Umbrella framework for everything GUI-related
|
||||
find_library(COCOA_LIBRARY Cocoa REQUIRED)
|
||||
find_library(IOKIT_LIBRARY IOKit REQUIRED)
|
||||
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
|
||||
if (IOS)
|
||||
find_library(OBJC_LIBRARY objc REQUIRED)
|
||||
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY} ${OBJC_LIBRARY})
|
||||
else()
|
||||
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
|
||||
endif()
|
||||
elseif (WIN32)
|
||||
# Target Windows 10
|
||||
add_compile_definitions(_WIN32_WINNT=0x0A00 WINVER=0x0A00)
|
||||
|
|
|
|||
11
cpmfile.json
11
cpmfile.json
|
|
@ -17,7 +17,8 @@
|
|||
"version": "1.57",
|
||||
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
|
||||
"patches": [
|
||||
"0001-clang-cl.patch"
|
||||
"0001-clang-cl.patch",
|
||||
"0002-ios-fix.patch"
|
||||
]
|
||||
},
|
||||
"fmt": {
|
||||
|
|
@ -46,9 +47,9 @@
|
|||
"package": "ZLIB",
|
||||
"repo": "madler/zlib",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "06eaa3a1eaaeb31f461a2283b03a91ed8eb2406e62cd97ea1c69836324909edeecd93edd03ff0bf593d9dde223e3376149134c5b1fe2e8688c258cadf8cd60ff",
|
||||
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
|
||||
"version": "1.2",
|
||||
"git_version": "1.3.1.2",
|
||||
"git_version": "1.3.2",
|
||||
"options": [
|
||||
"ZLIB_BUILD_SHARED OFF",
|
||||
"ZLIB_INSTALL OFF"
|
||||
|
|
@ -98,9 +99,9 @@
|
|||
"package": "VVL",
|
||||
"repo": "KhronosGroup/Vulkan-ValidationLayers",
|
||||
"tag": "vulkan-sdk-%VERSION%",
|
||||
"git_version": "1.4.335.0",
|
||||
"git_version": "1.4.341.0",
|
||||
"artifact": "android-binaries-%VERSION%.zip",
|
||||
"hash": "48167c4a17736301bd08f9290f41830443e1f18cce8ad867fc6f289b49e18b40e93c9850b377951af82f51b5b6d7313aa6a884fc5df79f5ce3df82696c1c1244"
|
||||
"hash": "8812ae84cbe49e6a3418ade9c458d3be6d74a3dffd319d4502007b564d580998056e8190414368ec11b27bc83993c7a0dad713c31bcc3d9553b51243efee3753"
|
||||
},
|
||||
"quazip": {
|
||||
"package": "QuaZip-Qt6",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
- [Arch Linux](#arch-linux)
|
||||
- [Gentoo Linux](#gentoo-linux)
|
||||
- [macOS](#macos)
|
||||
- [iOS](#ios)
|
||||
- [Solaris](#solaris)
|
||||
- [HaikuOS](#haikuos)
|
||||
- [OpenBSD](#openbsd)
|
||||
|
|
@ -31,6 +32,16 @@ If you're having issues with building, always consult that ebuild.
|
|||
|
||||
macOS is largely untested. Expect crashes, significant Vulkan issues, and other fun stuff.
|
||||
|
||||
## iOS
|
||||
|
||||
iOS has a dedicated build script, we **highly** recommend using that instead of doing anything else, we don't support any other configuration than the one present in said build script.
|
||||
|
||||
To build, it's simply as easy as doing
|
||||
```sh
|
||||
chmod +x .ci/ios/build.sh
|
||||
.ci/ios/build.sh
|
||||
```
|
||||
|
||||
## Solaris
|
||||
|
||||
Always consult [the OpenIndiana package list](https://pkg.openindiana.org/hipster/en/index.shtml) to cross-verify availability.
|
||||
|
|
@ -91,7 +102,7 @@ After configuration, you may need to modify `externals/ffmpeg/CMakeFiles/ffmpeg-
|
|||
|
||||
`-lc++-experimental` doesn't exist in OpenBSD but the LLVM driver still tries to link against it, to solve just symlink `ln -s /usr/lib/libc++.a /usr/lib/libc++experimental.a`. Builds are currently not working due to lack of `std::jthread` and such, either compile libc++ manually or wait for ports to catch up.
|
||||
|
||||
If clang has errors, try using `g++-11`.
|
||||
If clang has errors, try using `g++11`.
|
||||
|
||||
## FreeBSD
|
||||
|
||||
|
|
@ -107,6 +118,8 @@ hw.usb.usbhid.enable="0"
|
|||
|
||||
## NetBSD
|
||||
|
||||
2026-02-07: `vulkan-headers` must not be installed, since the version found in `pkgsrc` is older than required. Either wait for binary packages to update or build newer versions from source.
|
||||
|
||||
Install `pkgin` if not already `pkg_add pkgin`, see also the general [pkgsrc guide](https://www.netbsd.org/docs/pkgsrc/using.html). For NetBSD 10.1 provide `echo 'PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/amd64/10.1/All/"' >/etc/pkg_install.conf`. If `pkgin` is taking too much time consider adding the following to `/etc/rc.conf`:
|
||||
|
||||
```sh
|
||||
|
|
@ -116,7 +129,7 @@ ip6addrctl_policy=ipv4_prefer
|
|||
|
||||
System provides a default `g++-10` which doesn't support the current C++ codebase; install `clang-19` with `pkgin install clang-19`. Or install `gcc14` (or `gcc15` with current pkgsrc). Provided that, the following CMake commands may work:
|
||||
|
||||
- `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -Bbuild`
|
||||
- `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -Bbuild` (Recommended)
|
||||
- `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/pkg/gcc14/bin/gcc -DCMAKE_CXX_COMPILER=/usr/pkg/gcc14/bin/g++ -Bbuild`
|
||||
- `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/pkg/gcc15/bin/gcc -DCMAKE_CXX_COMPILER=/usr/pkg/gcc15/bin/g++ -Bbuild`
|
||||
|
||||
|
|
@ -138,8 +151,12 @@ cmake --install build
|
|||
|
||||
However, pkgsrc is highly recommended, see [getting pkgsrc](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/doc/pkgsrc.html#getting). You must get `current` not the `2025Q2` version.
|
||||
|
||||
`QtCore` on NetBSD is included, but due to misconfigurations(!) we MUST include one of the standard headers that include `bits/c++config.h`, since source_location (required by `QtCore`) isn't properly configured to intake `bits/c++config.h` (none of the experimental library is). This is a bug with NetBSD packaging and not our fault, but alas.
|
||||
|
||||
## DragonFlyBSD
|
||||
|
||||
2026-02-07: `vulkan-headers` and `vulkan-utility-libraries` must NOT be uninstalled, since they're too old: `1.3.289`. Either wait for binary packages to update or build newer versions from source.
|
||||
|
||||
If `libstdc++.so.6` is not found (`GLIBCXX_3.4.30`) then attempt:
|
||||
|
||||
```sh
|
||||
|
|
|
|||
19
externals/cmake-modules/DetectArchitecture.cmake
vendored
19
externals/cmake-modules/DetectArchitecture.cmake
vendored
|
|
@ -38,13 +38,18 @@ This file is based off of Yuzu and Dynarmic.
|
|||
if (CMAKE_OSX_ARCHITECTURES)
|
||||
set(MULTIARCH_BUILD 1)
|
||||
set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
|
||||
|
||||
# hope and pray the architecture names match
|
||||
foreach(ARCH IN ${CMAKE_OSX_ARCHITECTURES})
|
||||
set(ARCHITECTURE_${ARCH} 1 PARENT_SCOPE)
|
||||
add_definitions(-DARCHITECTURE_${ARCH}=1)
|
||||
endforeach()
|
||||
|
||||
if (IOS)
|
||||
# TODO: Right... the toolchain file won't properly accomodate OSX_ARCHITECTURE
|
||||
# they aren't defining it as a list properly I assume?
|
||||
set(ARCHITECTURE_arm64 1 PARENT_SCOPE)
|
||||
add_definitions(-DARCHITECTURE_arm64=1)
|
||||
else ()
|
||||
# hope and pray the architecture names match
|
||||
foreach(ARCH IN ${CMAKE_OSX_ARCHITECTURES})
|
||||
set(ARCHITECTURE_${ARCH} 1 PARENT_SCOPE)
|
||||
add_definitions(-DARCHITECTURE_${ARCH}=1)
|
||||
endforeach()
|
||||
endif()
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
|
|
|||
6
externals/cmake-modules/DetectPlatform.cmake
vendored
6
externals/cmake-modules/DetectPlatform.cmake
vendored
|
|
@ -51,6 +51,12 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|||
set(CXX_APPLE ON)
|
||||
endif()
|
||||
|
||||
# This fixes some quirks with xcrun or weird iOS toolchain cmake files
|
||||
if (IOS)
|
||||
unset(CXX_CLANG)
|
||||
set(CXX_APPLE ON)
|
||||
endif()
|
||||
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/merge_requests/11112
|
||||
# This works totally fine on MinGW64, but not CLANG{,ARM}64
|
||||
if(MINGW AND CXX_CLANG)
|
||||
|
|
|
|||
28
externals/cpmfile.json
vendored
28
externals/cpmfile.json
vendored
|
|
@ -9,7 +9,7 @@
|
|||
},
|
||||
"sirit": {
|
||||
"repo": "eden-emulator/sirit",
|
||||
"git_version": "1.0.3",
|
||||
"git_version": "1.0.4",
|
||||
"tag": "v%VERSION%",
|
||||
"artifact": "sirit-source-%VERSION%.tar.zst",
|
||||
"hash_suffix": "sha512sum",
|
||||
|
|
@ -28,11 +28,12 @@
|
|||
"httplib": {
|
||||
"repo": "yhirose/cpp-httplib",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "a229e24cca4afe78e5c0aa2e482f15108ac34101fd8dbd927365f15e8c37dec4de38c5277d635017d692a5b320e1b929f8bfcc076f52b8e4dcdab8fe53bfdf2e",
|
||||
"git_version": "0.30.1",
|
||||
"hash": "5efa8140aadffe105dcf39935b732476e95755f6c7473ada3d0b64df2bc02c557633ae3948a25b45e1cf67e89a3ff6329fb30362e4ac033b9a1d1e453aa2eded",
|
||||
"git_version": "0.37.0",
|
||||
"find_args": "MODULE GLOBAL",
|
||||
"patches": [
|
||||
"0001-mingw.patch"
|
||||
"0001-mingw.patch",
|
||||
"0002-fix-zstd.patch"
|
||||
],
|
||||
"options": [
|
||||
"HTTPLIB_REQUIRE_OPENSSL ON"
|
||||
|
|
@ -55,8 +56,8 @@
|
|||
"package": "xbyak",
|
||||
"repo": "herumi/xbyak",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "ac333d7bea1d61865bebebb116201a58db431946aa2f11aa042ef5795c390ff30af4d6c90ed3b3d24443a1d430703b08f14fc13b2fa405c155a241456ed78a47",
|
||||
"git_version": "7.33.2"
|
||||
"hash": "b6475276b2faaeb315734ea8f4f8bd87ededcee768961b39679bee547e7f3e98884d8b7851e176d861dab30a80a76e6ea302f8c111483607dde969b4797ea95a",
|
||||
"git_version": "7.35.2"
|
||||
},
|
||||
"oaknut": {
|
||||
"repo": "eden-emulator/oaknut",
|
||||
|
|
@ -110,7 +111,8 @@
|
|||
],
|
||||
"patches": [
|
||||
"0001-netbsd-fix.patch",
|
||||
"0002-allow-static-only.patch"
|
||||
"0002-allow-static-only.patch",
|
||||
"0003-ios-fix.patch"
|
||||
]
|
||||
},
|
||||
"spirv-headers": {
|
||||
|
|
@ -146,9 +148,9 @@
|
|||
"package": "Catch2",
|
||||
"repo": "catchorg/Catch2",
|
||||
"tag": "v%VERSION%",
|
||||
"hash": "acb3f463a7404d6a3bce52e474075cdadf9bb241d93feaf147c182d756e5a2f8bd412f4658ca186d15ab8fed36fc587d79ec311f55642d8e4ded16df9e213656",
|
||||
"hash": "7eea385d79d88a5690cde131fe7ccda97d5c54ea09d6f515000d7bf07c828809d61c1ac99912c1ee507cf933f61c1c47ecdcc45df7850ffa82714034b0fccf35",
|
||||
"version": "3.0.1",
|
||||
"git_version": "3.12.0",
|
||||
"git_version": "3.13.0",
|
||||
"patches": [
|
||||
"0001-solaris-isnan-fix.patch"
|
||||
]
|
||||
|
|
@ -256,15 +258,15 @@
|
|||
"repo": "KhronosGroup/Vulkan-Headers",
|
||||
"package": "VulkanHeaders",
|
||||
"version": "1.4.317",
|
||||
"hash": "26e0ad8fa34ab65a91ca62ddc54cc4410d209a94f64f2817dcdb8061dc621539a4262eab6387e9b9aa421db3dbf2cf8e2a4b041b696d0d03746bae1f25191272",
|
||||
"git_version": "1.4.342",
|
||||
"hash": "d2846ea228415772645eea4b52a9efd33e6a563043dd3de059e798be6391a8f0ca089f455ae420ff22574939ed0f48ed7c6ff3d5a9987d5231dbf3b3f89b484b",
|
||||
"git_version": "1.4.345",
|
||||
"tag": "v%VERSION%"
|
||||
},
|
||||
"vulkan-utility-libraries": {
|
||||
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"hash": "8147370f964fd82c315d6bb89adeda30186098427bf3efaa641d36282d42a263f31e96e4586bfd7ae0410ff015379c19aa4512ba160630444d3d8553afd1ec14",
|
||||
"git_version": "1.4.342",
|
||||
"hash": "114f6b237a6dcba923ccc576befb5dea3f1c9b3a30de7dc741f234a831d1c2d52d8a224afb37dd57dffca67ac0df461eaaab6a5ab5e503b393f91c166680c3e1",
|
||||
"git_version": "1.4.345",
|
||||
"tag": "v%VERSION%"
|
||||
},
|
||||
"frozen": {
|
||||
|
|
|
|||
28
externals/ffmpeg/CMakeLists.txt
vendored
28
externals/ffmpeg/CMakeLists.txt
vendored
|
|
@ -1,4 +1,4 @@
|
|||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
||||
|
|
@ -11,9 +11,9 @@ set(FFmpeg_HWACCEL_FLAGS)
|
|||
set(FFmpeg_HWACCEL_INCLUDE_DIRS)
|
||||
set(FFmpeg_HWACCEL_LDFLAGS)
|
||||
|
||||
if (UNIX AND NOT ANDROID)
|
||||
if (UNIX AND NOT ANDROID AND NOT IOS)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
if (NOT ANDROID)
|
||||
if (NOT ANDROID AND NOT IOS)
|
||||
pkg_check_modules(LIBVA libva)
|
||||
pkg_check_modules(CUDA cuda)
|
||||
pkg_check_modules(FFNVCODEC ffnvcodec)
|
||||
|
|
@ -182,6 +182,10 @@ else()
|
|||
find_program(BASH_PROGRAM bash REQUIRED)
|
||||
|
||||
set(FFmpeg_CROSS_COMPILE_FLAGS "")
|
||||
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
|
||||
# `--disable-vdpau` is needed to avoid linking issues
|
||||
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
|
||||
set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER})
|
||||
if (ANDROID)
|
||||
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME)
|
||||
set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||
|
|
@ -197,12 +201,22 @@ else()
|
|||
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
|
||||
--extra-ldflags="-nostdlib"
|
||||
)
|
||||
elseif(IOS)
|
||||
execute_process(COMMAND xcrun --sdk iphoneos --show-sdk-path OUTPUT_VARIABLE SYSROOT)
|
||||
# Lovely extra newline apple adds that **we** must remove... thank you apple!
|
||||
string(STRIP "${SYSROOT}" SYSROOT)
|
||||
set(FFmpeg_CC xcrun --sdk iphoneos clang -arch arm64)
|
||||
set(FFmpeg_CXX xcrun --sdk iphoneos clang++ -arch arm64)
|
||||
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
|
||||
--arch=arm64
|
||||
--enable-cross-compile
|
||||
--sysroot="${SYSROOT}"
|
||||
--extra-ldflags="-miphoneos-version-min=16.0"
|
||||
--install-name-dir='@rpath'
|
||||
--disable-audiotoolbox
|
||||
)
|
||||
endif()
|
||||
|
||||
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
|
||||
# `--disable-vdpau` is needed to avoid linking issues
|
||||
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
|
||||
set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER})
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${FFmpeg_MAKEFILE}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -255,4 +256,8 @@ if (ANDROID)
|
|||
target_include_directories(yuzu-android PRIVATE android/app/src/main)
|
||||
endif()
|
||||
|
||||
if (IOS)
|
||||
add_subdirectory(ios)
|
||||
endif()
|
||||
|
||||
include(GenerateDepHashes)
|
||||
|
|
|
|||
|
|
@ -40,11 +40,21 @@ class AddonAdapter(val addonViewModel: AddonViewModel) :
|
|||
}
|
||||
}
|
||||
|
||||
val deleteAction = {
|
||||
addonViewModel.setAddonToDelete(model)
|
||||
val canDelete = model.isRemovable
|
||||
binding.deleteCard.isEnabled = canDelete
|
||||
binding.buttonDelete.isEnabled = canDelete
|
||||
binding.deleteCard.alpha = if (canDelete) 1f else 0.38f
|
||||
|
||||
if (canDelete) {
|
||||
val deleteAction = {
|
||||
addonViewModel.setAddonToDelete(model)
|
||||
}
|
||||
binding.deleteCard.setOnClickListener { deleteAction() }
|
||||
binding.buttonDelete.setOnClickListener { deleteAction() }
|
||||
} else {
|
||||
binding.deleteCard.setOnClickListener(null)
|
||||
binding.buttonDelete.setOnClickListener(null)
|
||||
}
|
||||
binding.deleteCard.setOnClickListener { deleteAction() }
|
||||
binding.buttonDelete.setOnClickListener { deleteAction() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
|
|
@ -10,6 +10,8 @@ import android.view.LayoutInflater
|
|||
import android.view.ViewGroup
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
|
||||
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
|
||||
import org.yuzu.yuzu_emu.model.GameProperty
|
||||
|
|
@ -89,29 +91,33 @@ class GamePropertiesAdapter(
|
|||
|
||||
|
||||
val hasVisibleActions = submenuProperty.secondaryActions?.any { it.isShown } == true
|
||||
binding.layoutSecondaryActions.removeAllViews()
|
||||
binding.dividerSecondaryActions.setVisible(false)
|
||||
|
||||
if (hasVisibleActions) {
|
||||
binding.dividerSecondaryActions.setVisible(true)
|
||||
binding.layoutSecondaryActions.setVisible(true)
|
||||
|
||||
submenuProperty.secondaryActions!!.forEach { secondaryAction ->
|
||||
if (secondaryAction.isShown) {
|
||||
val button = com.google.android.material.button.MaterialButton(
|
||||
binding.root.context,
|
||||
null,
|
||||
com.google.android.material.R.attr.materialButtonOutlinedStyle
|
||||
).apply {
|
||||
setIconResource(secondaryAction.iconId)
|
||||
iconSize = (18 * binding.root.context.resources.displayMetrics.density).toInt()
|
||||
text = binding.root.context.getString(secondaryAction.descriptionId)
|
||||
contentDescription = binding.root.context.getString(secondaryAction.descriptionId)
|
||||
setOnClickListener { secondaryAction.action.invoke() }
|
||||
}
|
||||
binding.layoutSecondaryActions.addView(button)
|
||||
val visibleActions = submenuProperty.secondaryActions!!.filter { it.isShown }
|
||||
val inflater = LayoutInflater.from(binding.root.context)
|
||||
visibleActions.forEachIndexed { index, secondaryAction ->
|
||||
val button = inflater.inflate(
|
||||
R.layout.item_secondary_action_button,
|
||||
binding.layoutSecondaryActions,
|
||||
false
|
||||
) as MaterialButton
|
||||
button.setIconResource(secondaryAction.iconId)
|
||||
button.text = ""
|
||||
button.contentDescription = binding.root.context
|
||||
.getString(secondaryAction.descriptionId)
|
||||
button.tooltipText = binding.root.context
|
||||
.getString(secondaryAction.descriptionId)
|
||||
if (index == visibleActions.lastIndex) {
|
||||
(button.layoutParams as ViewGroup.MarginLayoutParams).marginEnd = 0
|
||||
}
|
||||
button.setOnClickListener { secondaryAction.action.invoke() }
|
||||
binding.layoutSecondaryActions.addView(button)
|
||||
}
|
||||
} else {
|
||||
binding.dividerSecondaryActions.setVisible(false)
|
||||
binding.layoutSecondaryActions.setVisible(false)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.dialogs
|
||||
|
|
@ -14,6 +14,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
|
|
@ -58,6 +59,30 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) {
|
|||
setupSearchBar()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
window?.setLayout(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
|
||||
val bottomSheet =
|
||||
findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
|
||||
if (bottomSheet != null) {
|
||||
bottomSheet.layoutParams = bottomSheet.layoutParams.apply {
|
||||
width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
bottomSheet.requestLayout()
|
||||
}
|
||||
|
||||
behavior.isFitToContents = false
|
||||
behavior.expandedOffset = 0
|
||||
behavior.skipCollapsed = true
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
adapter = LobbyRoomAdapter { room -> handleRoomSelection(room) }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model
|
||||
|
|
@ -27,7 +27,7 @@ object Settings {
|
|||
SECTION_APP_SETTINGS(R.string.app_settings),
|
||||
SECTION_CUSTOM_PATHS(R.string.preferences_custom_paths),
|
||||
SECTION_DEBUG(R.string.preferences_debug),
|
||||
SECTION_FREEDRENO(R.string.gpu_driver_settings),
|
||||
SECTION_FREEDRENO(R.string.freedreno_settings_title),
|
||||
SECTION_APPLETS(R.string.applets_menu);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
|
|
@ -111,10 +111,18 @@ class SettingsActivity : AppCompatActivity() {
|
|||
if (navHostFragment.childFragmentManager.backStackEntryCount > 0) {
|
||||
navHostFragment.navController.popBackStack()
|
||||
} else {
|
||||
finish()
|
||||
finishWithFragmentLikeAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishWithFragmentLikeAnimation() {
|
||||
finish()
|
||||
overridePendingTransition(
|
||||
androidx.navigation.ui.R.anim.nav_default_pop_enter_anim,
|
||||
androidx.navigation.ui.R.anim.nav_default_pop_exit_anim
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (!DirectoryInitialization.areDirectoriesReady) {
|
||||
|
|
@ -170,7 +178,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||
getString(R.string.settings_reset),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
finish()
|
||||
finishWithFragmentLikeAnimation()
|
||||
}
|
||||
|
||||
private fun setInsets() {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
|
|
@ -98,23 +98,8 @@ class SettingsFragment : Fragment() {
|
|||
activity
|
||||
)
|
||||
|
||||
binding.toolbarSettingsLayout.title = if (args.menuTag == Settings.MenuTag.SECTION_ROOT &&
|
||||
args.game != null
|
||||
) {
|
||||
args.game!!.title
|
||||
} else {
|
||||
when (args.menuTag) {
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8)
|
||||
else -> getString(args.menuTag.titleId)
|
||||
}
|
||||
}
|
||||
val toolbarTitle = resolveToolbarTitle()
|
||||
configureToolbar(toolbarTitle)
|
||||
|
||||
binding.listSettings.apply {
|
||||
adapter = settingsAdapter
|
||||
|
|
@ -193,11 +178,9 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
|
||||
presenter.onViewCreated()
|
||||
|
||||
setInsets()
|
||||
}
|
||||
|
||||
private fun getPlayerIndex(): Int =
|
||||
private fun getPlayerIndex(): Int =
|
||||
when (args.menuTag) {
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> 0
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> 1
|
||||
|
|
@ -210,6 +193,27 @@ class SettingsFragment : Fragment() {
|
|||
else -> -1
|
||||
}
|
||||
|
||||
private fun resolveToolbarTitle(): String {
|
||||
if (args.menuTag == Settings.MenuTag.SECTION_ROOT && args.game != null) {
|
||||
return args.game!!.title
|
||||
}
|
||||
return when (args.menuTag) {
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7)
|
||||
Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8)
|
||||
else -> getString(args.menuTag.titleId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureToolbar(title: String) {
|
||||
binding.toolbarSettings.title = title
|
||||
}
|
||||
|
||||
private fun setInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(
|
||||
binding.root
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.features.settings.ui
|
|||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
|
|
@ -27,11 +26,9 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
|
|||
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.*
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import androidx.core.content.edit
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||
|
||||
|
|
@ -183,16 +180,6 @@ class SettingsFragmentPresenter(
|
|||
menuKey = MenuTag.SECTION_DEBUG
|
||||
)
|
||||
)
|
||||
if (GpuDriverHelper.isAdrenoGpu() && !NativeConfig.isPerGameConfigLoaded()) {
|
||||
add(
|
||||
SubmenuSetting(
|
||||
titleId = R.string.gpu_driver_settings,
|
||||
descriptionId = R.string.freedreno_settings_title,
|
||||
iconId = R.drawable.ic_graphics,
|
||||
menuKey = MenuTag.SECTION_FREEDRENO
|
||||
)
|
||||
)
|
||||
}
|
||||
add(
|
||||
SubmenuSetting(
|
||||
titleId = R.string.applets_menu,
|
||||
|
|
@ -1084,27 +1071,6 @@ class SettingsFragmentPresenter(
|
|||
|
||||
add(HeaderSetting(R.string.theme_and_color))
|
||||
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
theme,
|
||||
titleId = R.string.change_app_theme,
|
||||
choicesId = R.array.themeEntriesA12,
|
||||
valuesId = R.array.themeValuesA12
|
||||
)
|
||||
)
|
||||
} else {
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
theme,
|
||||
titleId = R.string.change_app_theme,
|
||||
choicesId = R.array.themeEntries,
|
||||
valuesId = R.array.themeValues
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val themeMode: AbstractIntSetting = object : AbstractIntSetting {
|
||||
override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt()
|
||||
override fun setInt(value: Int) {
|
||||
|
|
@ -1126,6 +1092,35 @@ class SettingsFragmentPresenter(
|
|||
}
|
||||
}
|
||||
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
themeMode,
|
||||
titleId = R.string.change_theme_mode,
|
||||
choicesId = R.array.themeModeEntries,
|
||||
valuesId = R.array.themeModeValues
|
||||
)
|
||||
)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
theme,
|
||||
titleId = R.string.change_app_theme,
|
||||
choicesId = R.array.themeEntriesA12,
|
||||
valuesId = R.array.themeValuesA12
|
||||
)
|
||||
)
|
||||
} else {
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
theme,
|
||||
titleId = R.string.change_app_theme,
|
||||
choicesId = R.array.themeEntries,
|
||||
valuesId = R.array.themeValues
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting {
|
||||
override fun getInt(needsGlobal: Boolean): Int =
|
||||
IntSetting.STATIC_THEME_COLOR.getInt(needsGlobal)
|
||||
|
|
@ -1149,15 +1144,6 @@ class SettingsFragmentPresenter(
|
|||
}
|
||||
}
|
||||
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
themeMode,
|
||||
titleId = R.string.change_theme_mode,
|
||||
choicesId = R.array.themeModeEntries,
|
||||
valuesId = R.array.themeModeValues
|
||||
)
|
||||
)
|
||||
|
||||
if (IntSetting.THEME.getInt() != 1) {
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
|
@ -54,8 +51,8 @@ class AboutFragment : Fragment() {
|
|||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
homeViewModel.setStatusBarShadeVisibility(visible = false)
|
||||
|
||||
binding.toolbarAbout.setNavigationOnClickListener {
|
||||
binding.root.findNavController().popBackStack()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.yuzu.yuzu_emu.R
|
|||
import org.yuzu.yuzu_emu.databinding.FragmentDriverFetcherBinding
|
||||
import org.yuzu.yuzu_emu.features.fetcher.DriverGroupAdapter
|
||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||
import java.io.IOException
|
||||
|
|
@ -87,6 +88,7 @@ class DriverFetcherFragment : Fragment() {
|
|||
|
||||
private lateinit var driverGroupAdapter: DriverGroupAdapter
|
||||
private val driverViewModel: DriverViewModel by activityViewModels()
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
|
||||
private fun parseAdrenoModel(): Int {
|
||||
if (gpuModel == null) {
|
||||
|
|
@ -138,7 +140,7 @@ class DriverFetcherFragment : Fragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
homeViewModel.setStatusBarShadeVisibility(visible = false)
|
||||
binding.toolbarDrivers.setNavigationOnClickListener {
|
||||
binding.root.findNavController().popBackStack()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentFreedrenoSettingsBinding
|
|||
import org.yuzu.yuzu_emu.model.Game
|
||||
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
||||
import org.yuzu.yuzu_emu.utils.FreedrenoPresets
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||
|
||||
|
||||
class FreedrenoSettingsFragment : Fragment() {
|
||||
|
|
@ -74,10 +75,15 @@ class FreedrenoSettingsFragment : Fragment() {
|
|||
binding.toolbarFreedreno.setNavigationOnClickListener {
|
||||
requireActivity().onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
if (isPerGameConfig) {
|
||||
binding.toolbarFreedreno.title = getString(R.string.freedreno_per_game_title)
|
||||
binding.toolbarFreedreno.subtitle = game!!.title
|
||||
}
|
||||
|
||||
binding.toolbarFreedreno.title = getString(
|
||||
if (isPerGameConfig) {
|
||||
R.string.freedreno_per_game_title
|
||||
} else {
|
||||
R.string.freedreno_settings_title
|
||||
}
|
||||
)
|
||||
binding.toolbarFreedreno.subtitle = null
|
||||
}
|
||||
|
||||
private fun setupAdapters() {
|
||||
|
|
@ -175,17 +181,19 @@ class FreedrenoSettingsFragment : Fragment() {
|
|||
|
||||
private fun setupWindowInsets() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
|
||||
val systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
binding.root.updatePadding(
|
||||
left = systemInsets.left,
|
||||
right = systemInsets.right,
|
||||
bottom = systemInsets.bottom
|
||||
)
|
||||
val barInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
val cutoutInsets = insets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||
|
||||
val leftInsets = barInsets.left + cutoutInsets.left
|
||||
val rightInsets = barInsets.right + cutoutInsets.right
|
||||
|
||||
binding.appbarFreedreno.updateMargins(left = leftInsets, right = rightInsets)
|
||||
binding.scrollFreedreno.updateMargins(left = leftInsets, right = rightInsets)
|
||||
binding.scrollFreedreno.updatePadding(bottom = barInsets.bottom)
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSnackbar(message: String) {
|
||||
private fun showSnackbar(message: String) {
|
||||
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
|
@ -310,6 +310,21 @@ class GamePropertiesFragment : Fragment() {
|
|||
)
|
||||
)
|
||||
|
||||
if (!args.game.isHomebrew) {
|
||||
add(
|
||||
SubmenuProperty(
|
||||
R.string.add_ons,
|
||||
R.string.add_ons_description,
|
||||
R.drawable.ic_edit,
|
||||
action = {
|
||||
val action = GamePropertiesFragmentDirections
|
||||
.actionPerGamePropertiesFragmentToAddonsFragment(args.game)
|
||||
binding.root.findNavController().navigate(action)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (GpuDriverHelper.supportsCustomDriverLoading()) {
|
||||
add(
|
||||
SubmenuProperty(
|
||||
|
|
@ -341,18 +356,6 @@ class GamePropertiesFragment : Fragment() {
|
|||
}
|
||||
|
||||
if (!args.game.isHomebrew) {
|
||||
add(
|
||||
SubmenuProperty(
|
||||
R.string.add_ons,
|
||||
R.string.add_ons_description,
|
||||
R.drawable.ic_edit,
|
||||
action = {
|
||||
val action = GamePropertiesFragmentDirections
|
||||
.actionPerGamePropertiesFragmentToAddonsFragment(args.game)
|
||||
binding.root.findNavController().navigate(action)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
InstallableProperty(
|
||||
R.string.save_data,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.Manifest
|
||||
|
|
@ -44,7 +41,9 @@ import org.yuzu.yuzu_emu.model.HomeSetting
|
|||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||
|
||||
class HomeSettingsFragment : Fragment() {
|
||||
private var _binding: FragmentHomeSettingsBinding? = null
|
||||
|
|
@ -71,8 +70,12 @@ class HomeSettingsFragment : Fragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
homeViewModel.setStatusBarShadeVisibility(visible = true)
|
||||
homeViewModel.setStatusBarShadeVisibility(visible = false)
|
||||
mainActivity = requireActivity() as MainActivity
|
||||
binding.toolbarHomeSettings.setNavigationOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
binding.toolbarHomeSettings.title = getString(R.string.preferences_settings)
|
||||
|
||||
val optionsList: MutableList<HomeSetting> = mutableListOf<HomeSetting>().apply {
|
||||
add(
|
||||
|
|
@ -144,6 +147,18 @@ class HomeSettingsFragment : Fragment() {
|
|||
driverViewModel.selectedDriverTitle
|
||||
)
|
||||
)
|
||||
if (GpuDriverHelper.isAdrenoGpu()) {
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.freedreno_settings_title,
|
||||
R.string.gpu_driver_settings,
|
||||
R.drawable.ic_graphics,
|
||||
{
|
||||
binding.root.findNavController().navigate(R.id.freedrenoSettingsFragment)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
add(
|
||||
HomeSetting(
|
||||
R.string.multiplayer,
|
||||
|
|
@ -465,19 +480,22 @@ class HomeSettingsFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun setInsets() =
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
|
||||
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||
|
||||
binding.appbarHomeSettings.updateMargins(
|
||||
left = barInsets.left + cutoutInsets.left,
|
||||
right = barInsets.right + cutoutInsets.right
|
||||
)
|
||||
|
||||
binding.scrollViewSettings.updatePadding(
|
||||
top = barInsets.top
|
||||
bottom = barInsets.bottom
|
||||
)
|
||||
|
||||
binding.homeSettingsList.updatePadding(
|
||||
left = barInsets.left + cutoutInsets.left,
|
||||
top = cutoutInsets.top,
|
||||
right = barInsets.right + cutoutInsets.right,
|
||||
bottom = barInsets.bottom
|
||||
right = barInsets.right + cutoutInsets.right
|
||||
)
|
||||
|
||||
windowInsets
|
||||
|
|
|
|||
|
|
@ -16,5 +16,17 @@ data class Patch(
|
|||
val type: Int,
|
||||
val programId: String,
|
||||
val titleId: String,
|
||||
val numericVersion: Long = 0
|
||||
)
|
||||
val numericVersion: Long = 0,
|
||||
val source: Int = 0
|
||||
) {
|
||||
companion object {
|
||||
const val SOURCE_UNKNOWN = 0
|
||||
const val SOURCE_NAND = 1
|
||||
const val SOURCE_SDMC = 2
|
||||
const val SOURCE_EXTERNAL = 3
|
||||
const val SOURCE_PACKED = 4
|
||||
}
|
||||
|
||||
val isRemovable: Boolean
|
||||
get() = source != SOURCE_EXTERNAL && source != SOURCE_PACKED
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1407,7 +1407,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env
|
|||
Common::Android::ToJString(env, patch.version), static_cast<jint>(patch.type),
|
||||
Common::Android::ToJString(env, std::to_string(patch.program_id)),
|
||||
Common::Android::ToJString(env, std::to_string(patch.title_id)),
|
||||
static_cast<jlong>(patch.numeric_version));
|
||||
static_cast<jlong>(patch.numeric_version), static_cast<jint>(patch.source));
|
||||
env->SetObjectArrayElement(jpatchArray, i, jpatch);
|
||||
++i;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?attr/colorSurface" />
|
||||
<solid android:color="@android:color/transparent" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="?attr/colorOutline" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,237 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingHorizontal="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:text="@string/multiplayer_room_browser"
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/search_background"
|
||||
style="?attr/materialCardViewFilledStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_weight="1"
|
||||
app:cardBackgroundColor="?attr/colorSurfaceVariant"
|
||||
app:cardCornerRadius="24dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/search_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:contentDescription="@string/home_search"
|
||||
android:src="@drawable/ic_search"
|
||||
app:tint="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/search_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:autofillHints=""
|
||||
android:background="@android:color/transparent"
|
||||
android:hint="@string/multiplayer_search_public_lobbies"
|
||||
android:imeOptions="flagNoFullscreen"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/clear_button"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginEnd="48dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:contentDescription="@string/clear"
|
||||
android:src="@drawable/ic_clear"
|
||||
android:visibility="invisible"
|
||||
app:tint="?attr/colorOnSurfaceVariant"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_submit"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:contentDescription="@string/submit"
|
||||
android:src="@drawable/ic_send"
|
||||
app:tint="?attr/colorOnSurfaceVariant"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/refresh_button"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/refresh"
|
||||
app:icon="@drawable/ic_refresh" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
style="?android:attr/progressBarStyleSmall"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/horizontalScrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:fadingEdge="horizontal"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/chips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_hide_empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:checkable="true"
|
||||
android:checked="false"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:text="@string/multiplayer_hide_empty_rooms"
|
||||
app:chipCornerRadius="16dp"
|
||||
app:chipIconSize="18dp"
|
||||
app:chipIconTint="?attr/colorOnSurface" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip_hide_full"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:checkable="true"
|
||||
android:checked="false"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:text="@string/multiplayer_hide_full_rooms"
|
||||
app:chipCornerRadius="16dp"
|
||||
app:chipIconSize="18dp"
|
||||
app:chipIconTint="?attr/colorOnSurface" />
|
||||
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/room_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:contentDescription="@string/room_list"
|
||||
android:paddingBottom="16dp"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/empty_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="32dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="72dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:alpha="0.5"
|
||||
android:contentDescription="@string/refresh"
|
||||
android:src="@drawable/ic_refresh"
|
||||
app:tint="?attr/colorOnSurface" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/multiplayer_no_rooms_found"
|
||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/multiplayer_tap_refresh_to_check_again"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/empty_refresh_button"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/refresh"
|
||||
app:icon="@drawable/ic_refresh" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/theme_dialog_background"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||
android:id="@+id/drag_handle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_weight="0.75">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/multiplayer"
|
||||
android:src="@drawable/ic_network"
|
||||
app:tint="?attr/colorPrimary" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.25"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/multiplayer"
|
||||
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_lobby_browser"
|
||||
style="@style/Widget.Material3.Button.TonalButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:minHeight="56dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/multiplayer_public_room"
|
||||
android:textColor="?attr/colorOnPrimary"
|
||||
app:backgroundTint="?attr/colorPrimary"
|
||||
app:cornerRadius="16dp"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:iconPadding="12dp"
|
||||
app:iconTint="?attr/colorOnPrimary" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_join"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minHeight="56dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/multiplayer_join_room"
|
||||
app:cornerRadius="16dp"
|
||||
app:icon="@drawable/ic_install"
|
||||
app:iconPadding="12dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_create"
|
||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minHeight="56dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:text="@string/multiplayer_create_room"
|
||||
app:cornerRadius="16dp"
|
||||
app:icon="@drawable/ic_add"
|
||||
app:iconPadding="12dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -44,7 +44,12 @@
|
|||
style="@style/EdenCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardCornerRadius="24dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:padding="4dp"
|
||||
>
|
||||
|
||||
|
|
@ -103,7 +108,12 @@
|
|||
style="@style/EdenCard"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardCornerRadius="21dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:padding="8dp"
|
||||
>
|
||||
|
||||
|
|
@ -127,7 +137,12 @@
|
|||
style="@style/EdenCard"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardCornerRadius="21dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:padding="8dp"
|
||||
>
|
||||
|
||||
|
|
@ -151,7 +166,12 @@
|
|||
style="@style/EdenCard"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardCornerRadius="21dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:padding="8dp"
|
||||
>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,70 +12,83 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:tint="?attr/colorOnSurface"
|
||||
tools:src="@drawable/ic_settings" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/user_data"
|
||||
android:textAlignment="viewStart" />
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:tint="?attr/colorOnSurface"
|
||||
tools:src="@drawable/ic_settings" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/description"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/user_data_description"
|
||||
android:textAlignment="viewStart" />
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/user_data"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/description"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/user_data_description"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_export"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:contentDescription="@string/export"
|
||||
android:tooltipText="@string/export"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_export"
|
||||
tools:visibility="visible" />
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="end|center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_install"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="12dp"
|
||||
android:contentDescription="@string/string_import"
|
||||
android:tooltipText="@string/string_import"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_import"
|
||||
tools:visibility="visible" />
|
||||
<Button
|
||||
android:id="@+id/button_install"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/string_import"
|
||||
android:tooltipText="@string/string_import"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_import"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_export"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:contentDescription="@string/export"
|
||||
android:tooltipText="@string/export"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_export"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
android:id="@+id/coordinator_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface"
|
||||
>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
|
|
|
|||
|
|
@ -7,9 +7,13 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:background="@android:color/transparent"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
android:focusable="true"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="?attr/materialCardViewOutlinedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="12dp">
|
||||
android:layout_marginVertical="12dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="14dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingBottom="6dp">
|
||||
android:paddingTop="4dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:paddingBottom="2dp">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/image_game_screen"
|
||||
|
|
@ -48,11 +48,14 @@
|
|||
style="@style/SynthwaveText.Body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:gravity="center"
|
||||
android:requiresFadingEdge="horizontal"
|
||||
android:textAlignment="center"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintEnd_toEndOf="@+id/image_game_screen"
|
||||
app:layout_constraintStart_toStartOf="@+id/image_game_screen"
|
||||
app:layout_constraintTop_toBottomOf="@+id/image_game_screen"
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="14dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingBottom="6dp">
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:paddingBottom="3dp">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/image_container"
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
android:transitionName="card_game"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:cardBackgroundColor="@color/eden_card_background"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:strokeWidth="0dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
@ -27,6 +27,8 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium"
|
||||
app:strokeColor="@color/eden_card_background"
|
||||
app:strokeWidth="4dp"
|
||||
tools:src="@drawable/default_icon" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
|
|
|
|||
|
|
@ -8,9 +8,14 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardCornerRadius="16dp">
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/option_layout"
|
||||
|
|
@ -60,6 +65,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold"
|
||||
android:singleLine="true"
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/EdenCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="12dp">
|
||||
android:layout_marginVertical="12dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -42,30 +46,37 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_export"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:contentDescription="@string/export"
|
||||
android:tooltipText="@string/export"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_export"
|
||||
tools:visibility="visible" />
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_install"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="12dp"
|
||||
android:contentDescription="@string/string_import"
|
||||
android:tooltipText="@string/string_import"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_import"
|
||||
tools:visibility="visible" />
|
||||
<Button
|
||||
android:id="@+id/button_export"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/export"
|
||||
android:tooltipText="@string/export"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_export"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_install"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:contentDescription="@string/string_import"
|
||||
android:tooltipText="@string/string_import"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_import"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,63 +6,75 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="12dp">
|
||||
android:layout_marginVertical="12dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:tint="?attr/colorOnSurface"
|
||||
tools:src="@drawable/ic_settings" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/user_data"
|
||||
android:textAlignment="viewStart" />
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:tint="?attr/colorOnSurface"
|
||||
tools:src="@drawable/ic_settings" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/description"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/user_data_description"
|
||||
android:textAlignment="viewStart" />
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.Material3.TitleMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/user_data"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/description"
|
||||
style="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/user_data_description"
|
||||
android:textAlignment="viewStart" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="end|center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_install"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:contentDescription="@string/string_import"
|
||||
android:tooltipText="@string/string_import"
|
||||
android:visibility="gone"
|
||||
|
|
@ -71,11 +83,10 @@
|
|||
|
||||
<Button
|
||||
android:id="@+id/button_export"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:contentDescription="@string/export"
|
||||
android:tooltipText="@string/export"
|
||||
android:visibility="gone"
|
||||
|
|
|
|||
|
|
@ -7,9 +7,13 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginVertical="12dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:background="@android:color/transparent"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
android:focusable="true"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -81,14 +85,15 @@
|
|||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutSecondaryActions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end|center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="8dp"
|
||||
android:visibility="gone"
|
||||
app:singleLine="false"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
|||
|
|
@ -8,16 +8,14 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
android:elevation="0dp">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap">
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -59,8 +59,11 @@
|
|||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/multiplayer_public_room"
|
||||
app:cornerRadius="16dp"
|
||||
app:backgroundTint="?attr/colorPrimary"
|
||||
app:icon="@drawable/ic_search"
|
||||
app:iconPadding="12dp" />
|
||||
app:iconPadding="12dp"
|
||||
app:iconTint="?attr/colorOnPrimary"
|
||||
android:textColor="?attr/colorOnPrimary" />
|
||||
|
||||
<Space
|
||||
android:layout_width="20dp"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
android:id="@+id/coordinator_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface"
|
||||
>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
|
|
@ -51,12 +52,15 @@
|
|||
android:src="@drawable/ic_yuzu" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/EdenCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:cardCornerRadius="16dp">
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -84,14 +88,17 @@
|
|||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/button_contributors"
|
||||
style="@style/EdenCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardCornerRadius="16dp">
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -119,14 +126,17 @@
|
|||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/button_licenses"
|
||||
style="@style/EdenCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardCornerRadius="16dp">
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -161,7 +171,7 @@
|
|||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardBackgroundColor="?attr/colorSurface"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
app:cardElevation="0dp">
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_addons"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_addons"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_applets"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
|
|
@ -15,6 +16,7 @@
|
|||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_applets"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
|
|
|
|||
|
|
@ -7,19 +7,22 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_drivers"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
||||
app:liftOnScrollTargetViewId="@id/list_drivers">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_drivers"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
|
|
|
|||
|
|
@ -13,14 +13,15 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_drivers"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:liftOnScrollTargetViewId="@id/list_drivers">
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_drivers"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
|
|
|
|||
|
|
@ -12,14 +12,15 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_folders"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:liftOnScrollTargetViewId="@id/list_folders">
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_folders"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
|
|
|
|||
|
|
@ -8,35 +8,24 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_freedreno"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:elevation="0dp">
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/toolbar_freedreno_layout"
|
||||
style="?attr/collapsingToolbarLayoutMediumStyle"
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_freedreno"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||
app:contentScrim="?attr/colorSurface"
|
||||
app:scrimVisibleHeightTrigger="100dp">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_freedreno"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:layout_collapseMode="pin"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
app:title="@string/gpu_driver_settings" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scroll_freedreno"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
|
@ -63,8 +52,12 @@
|
|||
android:id="@+id/list_freedreno_presets"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="8dp"
|
||||
android:scrollbars="horizontal"
|
||||
android:scrollbarStyle="outsideInset"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
<!-- Current Settings Section -->
|
||||
|
|
@ -135,22 +128,23 @@
|
|||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:spacing="8dp">
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_clear_all"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/freedreno_clear_all"
|
||||
style="?attr/materialButtonOutlinedStyle" />
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:text="@string/freedreno_clear_all" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_save"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/save" />
|
||||
|
||||
|
|
@ -161,6 +155,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeWidth="1dp"
|
||||
app:strokeColor="?attr/colorOutline">
|
||||
|
|
|
|||
|
|
@ -33,9 +33,12 @@
|
|||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:icon="@drawable/ic_back"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
|
@ -44,9 +47,12 @@
|
|||
style="?attr/materialIconButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@android:color/transparent"
|
||||
app:icon="@drawable/ic_shortcut"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorOnSurface"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,12 @@
|
|||
style="@style/EdenCard"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardCornerRadius="21dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:padding="8dp"
|
||||
>
|
||||
|
||||
|
|
@ -61,7 +66,12 @@
|
|||
style="@style/EdenCard"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardCornerRadius="21dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:padding="8dp"
|
||||
>
|
||||
|
||||
|
|
@ -85,7 +95,12 @@
|
|||
style="@style/EdenCard"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardCornerRadius="21dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:padding="8dp"
|
||||
>
|
||||
|
||||
|
|
@ -117,7 +132,12 @@
|
|||
style="@style/EdenCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@android:color/transparent"
|
||||
app:cardCornerRadius="24dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:padding="4dp"
|
||||
>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +1,64 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/scroll_view_settings"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:fadeScrollbars="false"
|
||||
android:clipToPadding="false"
|
||||
android:background="?attr/colorSurface"
|
||||
android:defaultFocusHighlightEnabled="false">
|
||||
android:background="?attr/colorSurface">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/linear_layout_settings"
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_home_settings"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp">
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/logo_image"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/ic_yuzu" />
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_home_settings"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back"
|
||||
app:title="@string/preferences_settings" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/home_settings_list"
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scroll_view_settings"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:clipToPadding="false"
|
||||
android:defaultFocusHighlightEnabled="false"
|
||||
android:fadeScrollbars="false"
|
||||
android:scrollbars="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appbar_home_settings">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/linear_layout_settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false" />
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/home_settings_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:nestedScrollingEnabled="false" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_installables"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
|
|
@ -15,6 +16,7 @@
|
|||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_installables"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
|
|
|
|||
|
|
@ -10,12 +10,14 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_profiles"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:title="@string/profile_manager"
|
||||
|
|
|
|||
|
|
@ -8,30 +8,19 @@
|
|||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appbar_settings"
|
||||
style="@style/Widget.Eden.TransparentTopAppBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:elevation="0dp">
|
||||
android:touchscreenBlocksFocus="false">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/toolbar_settings_layout"
|
||||
style="?attr/collapsingToolbarLayoutMediumStyle"
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_settings"
|
||||
style="@style/Widget.Eden.TransparentTopToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||
app:contentScrim="?attr/colorSurface"
|
||||
app:scrimVisibleHeightTrigger="100dp">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar_settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:layout_collapseMode="pin"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:touchscreenBlocksFocus="false"
|
||||
app:navigationIcon="@drawable/ic_back" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.button.MaterialButton xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp" />
|
||||
|
|
@ -11,8 +11,11 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="2dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
|
|
@ -78,8 +81,11 @@
|
|||
android:layout_width="48dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:cardBackgroundColor="@android:color/transparent"
|
||||
app:cardCornerRadius="10dp"
|
||||
app:cardElevation="2dp"
|
||||
app:cardElevation="0dp"
|
||||
app:strokeColor="?attr/colorOutline"
|
||||
app:strokeWidth="1dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
|
|
@ -100,7 +106,7 @@
|
|||
android:layout_gravity="center"
|
||||
android:background="@null"
|
||||
android:src="@drawable/ic_delete"
|
||||
app:tint="@color/eden_border_gradient_end"
|
||||
app:tint="?attr/colorPrimary"
|
||||
android:contentDescription="@string/delete" />
|
||||
|
||||
</FrameLayout>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@
|
|||
|
||||
<action
|
||||
android:id="@+id/action_global_settingsActivity"
|
||||
app:destination="@id/settingsActivity" />
|
||||
app:destination="@id/settingsActivity"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
|
||||
</navigation>
|
||||
|
|
|
|||
|
|
@ -101,7 +101,11 @@
|
|||
|
||||
<action
|
||||
android:id="@+id/action_global_settingsActivity"
|
||||
app:destination="@id/settingsActivity" />
|
||||
app:destination="@id/settingsActivity"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
<fragment
|
||||
android:id="@+id/installableFragment"
|
||||
android:name="org.yuzu.yuzu_emu.fragments.InstallableFragment"
|
||||
|
|
|
|||
|
|
@ -191,6 +191,22 @@
|
|||
<item name="android:textColor">@color/eden_primary</item>
|
||||
<item name="rippleColor">@color/eden_glow_pink</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Eden.TransparentTopAppBarLayout" parent="">
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
<item name="android:elevation">0dp</item>
|
||||
<item name="android:stateListAnimator">@null</item>
|
||||
<item name="elevation">0dp</item>
|
||||
<item name="liftOnScroll">false</item>
|
||||
<item name="statusBarForeground">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Eden.TransparentTopToolbar" parent="">
|
||||
<item name="android:background">@android:color/transparent</item>
|
||||
<item name="android:elevation">0dp</item>
|
||||
<item name="backgroundTint">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="EdenPopupMenu" parent="Widget.Material3.PopupMenu">
|
||||
<item name="android:popupBackground">@drawable/popup_menu_background</item>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ namespace Common::Android {
|
|||
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
||||
s_patch_constructor = env->GetMethodID(
|
||||
patch_class, "<init>",
|
||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;J)V");
|
||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
|
||||
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
||||
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
||||
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "device_power_state.h"
|
||||
|
|
@ -14,11 +14,14 @@ extern std::atomic<bool> g_has_battery;
|
|||
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_MAC
|
||||
#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
|
||||
#if TARGET_OS_IPHONE
|
||||
// ios doesnt have this
|
||||
#else
|
||||
#include <IOKit/ps/IOPSKeys.h>
|
||||
#include <IOKit/ps/IOPowerSources.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
|
@ -48,7 +51,9 @@ namespace Common {
|
|||
info.percentage = g_battery_percentage.load(std::memory_order_relaxed);
|
||||
info.charging = g_is_charging.load(std::memory_order_relaxed);
|
||||
info.has_battery = g_has_battery.load(std::memory_order_relaxed);
|
||||
|
||||
#elif defined(__APPLE__) && TARGET_OS_IPHONE
|
||||
// Not implemented
|
||||
info.has_battery = false;
|
||||
#elif defined(__APPLE__) && TARGET_OS_MAC
|
||||
CFTypeRef info_ref = IOPSCopyPowerSourcesInfo();
|
||||
CFArrayRef sources = IOPSCopyPowerSourcesList(info_ref);
|
||||
|
|
@ -96,7 +101,6 @@ namespace Common {
|
|||
#else
|
||||
info.has_battery = false;
|
||||
#endif
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,11 @@
|
|||
#include <sys/random.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
||||
// Not available on iOS for some fucking stupid reason...
|
||||
#else
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -777,6 +777,7 @@ struct Values {
|
|||
Setting<bool> reporting_services{
|
||||
linkage, false, "reporting_services", Category::Debugging, Specialization::Default, false};
|
||||
Setting<bool> quest_flag{linkage, false, "quest_flag", Category::Debugging};
|
||||
Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Debugging};
|
||||
Setting<bool> disable_macro_jit{linkage, false, "disable_macro_jit",
|
||||
Category::DebuggingGraphics};
|
||||
Setting<bool> disable_macro_hle{linkage, false, "disable_macro_hle",
|
||||
|
|
|
|||
|
|
@ -19,10 +19,12 @@
|
|||
#include <windows.h>
|
||||
#include "common/string_util.h"
|
||||
#else
|
||||
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/_cpuset.h>
|
||||
#include <pthread_np.h>
|
||||
#elif defined(__DragonFly__) || defined(__OpenBSD__) || defined(__Bitrig__)
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
|
|
|
|||
|
|
@ -1220,7 +1220,7 @@ target_link_libraries(core PRIVATE
|
|||
RenderDoc::API
|
||||
ZLIB::ZLIB)
|
||||
|
||||
target_link_libraries(core PRIVATE httplib::httplib)
|
||||
target_link_libraries(core PUBLIC httplib::httplib zstd::zstd)
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(core PUBLIC ENABLE_WEB_SERVICE)
|
||||
|
|
@ -1264,6 +1264,10 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
|||
hle/service/jit/jit.cpp
|
||||
hle/service/jit/jit.h)
|
||||
target_link_libraries(core PRIVATE dynarmic::dynarmic)
|
||||
# Quick hack for XCode generator...
|
||||
if (IOS)
|
||||
target_include_directories(core PRIVATE "${CMAKE_SOURCE_DIR}/dynarmic/src")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <dynarmic/interface/halt_reason.h>
|
||||
#include "dynarmic/interface/halt_reason.h"
|
||||
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <dynarmic/interface/A32/a32.h>
|
||||
#include <dynarmic/interface/code_page.h>
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/interface/code_page.h"
|
||||
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
#include <memory>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
#include <dynarmic/interface/A64/a64.h>
|
||||
#include <dynarmic/interface/code_page.h>
|
||||
#include "dynarmic/interface/A64/a64.h"
|
||||
#include "dynarmic/interface/code_page.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/hash.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include <optional>
|
||||
|
||||
#include <dynarmic/interface/A32/coprocessor.h>
|
||||
#include "dynarmic/interface/A32/coprocessor.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <dynarmic/interface/exclusive_monitor.h>
|
||||
#include "dynarmic/interface/exclusive_monitor.h"
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/exclusive_monitor.h"
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
|
||||
#include <dynarmic/frontend/A64/a64_types.h>
|
||||
#include <dynarmic/frontend/A64/decoder/a64.h>
|
||||
#include <dynarmic/frontend/imm.h>
|
||||
#include "dynarmic/frontend/A64/a64_types.h"
|
||||
#include "dynarmic/frontend/A64/decoder/a64.h"
|
||||
#include "dynarmic/frontend/imm.h"
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "common/fs/path_util.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
|
|
@ -642,8 +643,15 @@ void KeyManager::ReloadKeys() {
|
|||
const auto keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
|
||||
if (!Common::FS::CreateDir(keys_dir))
|
||||
LOG_ERROR(Core, "Failed to create the keys directory.");
|
||||
LoadFromFile(keys_dir / "prod.keys_autogenerated", false);
|
||||
LoadFromFile(keys_dir / "prod.keys", false);
|
||||
if (Settings::values.use_dev_keys.GetValue()) {
|
||||
dev_mode = true;
|
||||
LoadFromFile(keys_dir / "dev.keys_autogenerated", false);
|
||||
LoadFromFile(keys_dir / "dev.keys", false);
|
||||
} else {
|
||||
dev_mode = false;
|
||||
LoadFromFile(keys_dir / "prod.keys_autogenerated", false);
|
||||
LoadFromFile(keys_dir / "prod.keys", false);
|
||||
}
|
||||
LoadFromFile(keys_dir / "title.keys_autogenerated", true);
|
||||
LoadFromFile(keys_dir / "title.keys", true);
|
||||
LoadFromFile(keys_dir / "console.keys_autogenerated", false);
|
||||
|
|
@ -838,7 +846,7 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
|
|||
|
||||
std::string filename = "title.keys_autogenerated";
|
||||
if (category == KeyCategory::Standard) {
|
||||
filename = "prod.keys_autogenerated";
|
||||
filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated";
|
||||
} else if (category == KeyCategory::Console) {
|
||||
filename = "console.keys_autogenerated";
|
||||
}
|
||||
|
|
@ -936,6 +944,8 @@ bool KeyManager::KeyFileExists(bool title) {
|
|||
const auto keys_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::KeysDir);
|
||||
if (title)
|
||||
return Common::FS::Exists(keys_dir / "title.keys");
|
||||
if (Settings::values.use_dev_keys.GetValue())
|
||||
return Common::FS::Exists(keys_dir / "dev.keys");
|
||||
return Common::FS::Exists(keys_dir / "prod.keys");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
|
|
@ -314,6 +314,7 @@ private:
|
|||
std::array<u8, 576> eticket_extended_kek{};
|
||||
RSAKeyPair<2048> eticket_rsa_keypair{};
|
||||
|
||||
bool dev_mode;
|
||||
void LoadFromFile(const std::filesystem::path& file_path, bool is_title_keys);
|
||||
|
||||
template <size_t Size>
|
||||
|
|
|
|||
|
|
@ -76,16 +76,16 @@ public:
|
|||
|
||||
template <typename Func>
|
||||
void ApplyOpOnPAddr(PAddr address, Common::ScratchBuffer<u32>& buffer, Func&& operation) {
|
||||
DAddr subbits = static_cast<DAddr>(address & page_mask);
|
||||
DAddr subbits = DAddr(address & page_mask);
|
||||
const u32 base = compressed_device_addr[(address >> page_bits)];
|
||||
if ((base >> MULTI_FLAG_BITS) == 0) [[likely]] {
|
||||
const DAddr d_address = (static_cast<DAddr>(base) << page_bits) + subbits;
|
||||
const DAddr d_address = (DAddr(base) << page_bits) + subbits;
|
||||
operation(d_address);
|
||||
return;
|
||||
}
|
||||
InnerGatherDeviceAddresses(buffer, address);
|
||||
for (u32 value : buffer) {
|
||||
operation((static_cast<DAddr>(value) << page_bits) + subbits);
|
||||
operation((DAddr(value) << page_bits) + subbits);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,12 +96,12 @@ public:
|
|||
}
|
||||
|
||||
PAddr GetPhysicalRawAddressFromDAddr(DAddr address) const {
|
||||
PAddr subbits = static_cast<PAddr>(address & page_mask);
|
||||
auto paddr = compressed_physical_ptr[(address >> page_bits)];
|
||||
PAddr subbits = PAddr(address & page_mask);
|
||||
auto paddr = tracked_entries[(address >> page_bits)].compressed_physical_ptr;
|
||||
if (paddr == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (static_cast<PAddr>(paddr - 1) << page_bits) + subbits;
|
||||
return (PAddr(paddr - 1) << page_bits) + subbits;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -172,9 +172,14 @@ private:
|
|||
|
||||
const uintptr_t physical_base;
|
||||
DeviceInterface* device_inter;
|
||||
Common::VirtualBuffer<u32> compressed_physical_ptr;
|
||||
|
||||
struct TrackedEntry {
|
||||
VAddr cpu_backing_address;
|
||||
u32 continuity_tracker;
|
||||
u32 compressed_physical_ptr;
|
||||
};
|
||||
Common::VirtualBuffer<u32> compressed_device_addr;
|
||||
Common::VirtualBuffer<u32> continuity_tracker;
|
||||
Common::VirtualBuffer<TrackedEntry> tracked_entries;
|
||||
|
||||
// Process memory interfaces
|
||||
|
||||
|
|
@ -189,17 +194,16 @@ private:
|
|||
static constexpr size_t asid_start_bit = guest_max_as_bits;
|
||||
|
||||
std::pair<Asid, VAddr> ExtractCPUBacking(size_t page_index) {
|
||||
auto content = cpu_backing_address[page_index];
|
||||
auto content = tracked_entries[page_index].cpu_backing_address;
|
||||
const VAddr address = content & guest_mask;
|
||||
const Asid asid{static_cast<size_t>(content >> asid_start_bit)};
|
||||
return std::make_pair(asid, address);
|
||||
}
|
||||
|
||||
void InsertCPUBacking(size_t page_index, VAddr address, Asid asid) {
|
||||
cpu_backing_address[page_index] = address | (asid.id << asid_start_bit);
|
||||
tracked_entries[page_index].cpu_backing_address = address | (asid.id << asid_start_bit);
|
||||
}
|
||||
|
||||
Common::VirtualBuffer<VAddr> cpu_backing_address;
|
||||
std::array<TranslationEntry, 4> t_slot{};
|
||||
u32 cache_cursor = 0;
|
||||
using CounterType = u8;
|
||||
|
|
|
|||
|
|
@ -166,29 +166,21 @@ struct DeviceMemoryManagerAllocator {
|
|||
|
||||
template <typename Traits>
|
||||
DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
|
||||
: physical_base{reinterpret_cast<const uintptr_t>(device_memory_.buffer.BackingBasePointer())},
|
||||
device_inter{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS),
|
||||
compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() ==
|
||||
Settings::MemoryLayout::Memory_4Gb
|
||||
? physical_min_bits
|
||||
: physical_max_bits) -
|
||||
Memory::YUZU_PAGEBITS)),
|
||||
continuity_tracker(device_as_size >> Memory::YUZU_PAGEBITS),
|
||||
cpu_backing_address(device_as_size >> Memory::YUZU_PAGEBITS) {
|
||||
: physical_base{uintptr_t(device_memory_.buffer.BackingBasePointer())}
|
||||
, device_inter{nullptr}
|
||||
, compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() == Settings::MemoryLayout::Memory_4Gb ? physical_min_bits : physical_max_bits) - Memory::YUZU_PAGEBITS))
|
||||
, tracked_entries(device_as_size >> Memory::YUZU_PAGEBITS)
|
||||
{
|
||||
impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
|
||||
cached_pages = std::make_unique<CachedPages>();
|
||||
|
||||
const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS;
|
||||
for (size_t i = 0; i < total_virtual; i++) {
|
||||
compressed_physical_ptr[i] = 0;
|
||||
continuity_tracker[i] = 1;
|
||||
cpu_backing_address[i] = 0;
|
||||
tracked_entries[i].compressed_physical_ptr = 0;
|
||||
tracked_entries[i].continuity_tracker = 1;
|
||||
tracked_entries[i].cpu_backing_address = 0;
|
||||
}
|
||||
const size_t total_phys = 1ULL << ((Settings::values.memory_layout_mode.GetValue() ==
|
||||
Settings::MemoryLayout::Memory_4Gb
|
||||
? physical_min_bits
|
||||
: physical_max_bits) -
|
||||
Memory::YUZU_PAGEBITS);
|
||||
const size_t total_phys = 1ULL << ((Settings::values.memory_layout_mode.GetValue() == Settings::MemoryLayout::Memory_4Gb ? physical_min_bits : physical_max_bits) - Memory::YUZU_PAGEBITS);
|
||||
for (size_t i = 0; i < total_phys; i++) {
|
||||
compressed_device_addr[i] = 0;
|
||||
}
|
||||
|
|
@ -228,11 +220,11 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size
|
|||
const VAddr new_vaddress = virtual_address + i * Memory::YUZU_PAGESIZE;
|
||||
auto* ptr = process_memory->GetPointerSilent(Common::ProcessAddress(new_vaddress));
|
||||
if (ptr == nullptr) [[unlikely]] {
|
||||
compressed_physical_ptr[start_page_d + i] = 0;
|
||||
tracked_entries[start_page_d + i].compressed_physical_ptr = 0;
|
||||
continue;
|
||||
}
|
||||
auto phys_addr = static_cast<u32>(GetRawPhysicalAddr(ptr) >> Memory::YUZU_PAGEBITS) + 1U;
|
||||
compressed_physical_ptr[start_page_d + i] = phys_addr;
|
||||
tracked_entries[start_page_d + i].compressed_physical_ptr = phys_addr;
|
||||
InsertCPUBacking(start_page_d + i, new_vaddress, asid);
|
||||
const u32 base_dev = compressed_device_addr[phys_addr - 1U];
|
||||
const u32 new_dev = static_cast<u32>(start_page_d + i);
|
||||
|
|
@ -260,9 +252,9 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
|
|||
device_inter->InvalidateRegion(address, size);
|
||||
std::scoped_lock lk(mapping_guard);
|
||||
for (size_t i = 0; i < num_pages; i++) {
|
||||
auto phys_addr = compressed_physical_ptr[start_page_d + i];
|
||||
compressed_physical_ptr[start_page_d + i] = 0;
|
||||
cpu_backing_address[start_page_d + i] = 0;
|
||||
auto phys_addr = tracked_entries[start_page_d + i].compressed_physical_ptr;
|
||||
tracked_entries[start_page_d + i].compressed_physical_ptr = 0;
|
||||
tracked_entries[start_page_d + i].cpu_backing_address = 0;
|
||||
if (phys_addr != 0) [[likely]] {
|
||||
const u32 base_dev = compressed_device_addr[phys_addr - 1U];
|
||||
if ((base_dev >> MULTI_FLAG_BITS) == 0) [[likely]] {
|
||||
|
|
@ -300,14 +292,14 @@ void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtu
|
|||
page_count = 1;
|
||||
}
|
||||
last_ptr = new_ptr;
|
||||
continuity_tracker[start_page_d + index] = static_cast<u32>(page_count);
|
||||
tracked_entries[start_page_d + index].continuity_tracker = static_cast<u32>(page_count);
|
||||
}
|
||||
}
|
||||
template <typename Traits>
|
||||
u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::size_t size) {
|
||||
size_t page_index = src_addr >> page_bits;
|
||||
size_t subbits = src_addr & page_mask;
|
||||
if ((static_cast<size_t>(continuity_tracker[page_index]) << page_bits) >= size + subbits) {
|
||||
if ((static_cast<size_t>(tracked_entries[page_index].continuity_tracker) << page_bits) >= size + subbits) {
|
||||
return GetPointer<u8>(src_addr);
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -317,7 +309,7 @@ template <typename Traits>
|
|||
const u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::size_t size) const {
|
||||
size_t page_index = src_addr >> page_bits;
|
||||
size_t subbits = src_addr & page_mask;
|
||||
if ((static_cast<size_t>(continuity_tracker[page_index]) << page_bits) >= size + subbits) {
|
||||
if ((static_cast<size_t>(tracked_entries[page_index].continuity_tracker) << page_bits) >= size + subbits) {
|
||||
return GetPointer<u8>(src_addr);
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -342,12 +334,10 @@ template <typename T>
|
|||
T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) {
|
||||
const size_t index = address >> Memory::YUZU_PAGEBITS;
|
||||
const size_t offset = address & Memory::YUZU_PAGEMASK;
|
||||
auto phys_addr = compressed_physical_ptr[index];
|
||||
if (phys_addr == 0) [[unlikely]] {
|
||||
auto phys_addr = tracked_entries[index].compressed_physical_ptr;
|
||||
if (phys_addr == 0) [[unlikely]]
|
||||
return nullptr;
|
||||
}
|
||||
return GetPointerFromRaw<T>((static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) +
|
||||
offset);
|
||||
return GetPointerFromRaw<T>((PAddr(phys_addr - 1) << Memory::YUZU_PAGEBITS) + offset);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
|
|
@ -355,12 +345,10 @@ template <typename T>
|
|||
const T* DeviceMemoryManager<Traits>::GetPointer(DAddr address) const {
|
||||
const size_t index = address >> Memory::YUZU_PAGEBITS;
|
||||
const size_t offset = address & Memory::YUZU_PAGEMASK;
|
||||
auto phys_addr = compressed_physical_ptr[index];
|
||||
if (phys_addr == 0) [[unlikely]] {
|
||||
auto phys_addr = tracked_entries[index].compressed_physical_ptr;
|
||||
if (phys_addr == 0)
|
||||
return nullptr;
|
||||
}
|
||||
return GetPointerFromRaw<T>((static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) +
|
||||
offset);
|
||||
return GetPointerFromRaw<T>((PAddr(phys_addr - 1) << Memory::YUZU_PAGEBITS) + offset);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
|
|
@ -386,18 +374,14 @@ T DeviceMemoryManager<Traits>::Read(DAddr address) const {
|
|||
}
|
||||
|
||||
template <typename Traits>
|
||||
void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto on_unmapped,
|
||||
auto on_memory, auto increment) {
|
||||
void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto on_unmapped, auto on_memory, auto increment) {
|
||||
std::size_t remaining_size = size;
|
||||
std::size_t page_index = addr >> Memory::YUZU_PAGEBITS;
|
||||
std::size_t page_offset = addr & Memory::YUZU_PAGEMASK;
|
||||
|
||||
while (remaining_size) {
|
||||
const size_t next_pages = static_cast<std::size_t>(continuity_tracker[page_index]);
|
||||
const std::size_t copy_amount =
|
||||
(std::min)((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
|
||||
const auto current_vaddr =
|
||||
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
|
||||
const size_t next_pages = std::size_t(tracked_entries[page_index].continuity_tracker);
|
||||
const std::size_t copy_amount = (std::min)((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
|
||||
const auto current_vaddr = u64((page_index << Memory::YUZU_PAGEBITS) + page_offset);
|
||||
SCOPE_EXIT{
|
||||
page_index += next_pages;
|
||||
page_offset = 0;
|
||||
|
|
@ -405,13 +389,12 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o
|
|||
remaining_size -= copy_amount;
|
||||
};
|
||||
|
||||
auto phys_addr = compressed_physical_ptr[page_index];
|
||||
auto phys_addr = tracked_entries[page_index].compressed_physical_ptr;
|
||||
if (phys_addr == 0) {
|
||||
on_unmapped(copy_amount, current_vaddr);
|
||||
continue;
|
||||
}
|
||||
auto* mem_ptr = GetPointerFromRaw<u8>(
|
||||
(static_cast<PAddr>(phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset);
|
||||
auto* mem_ptr = GetPointerFromRaw<u8>((PAddr(phys_addr - 1) << Memory::YUZU_PAGEBITS) + page_offset);
|
||||
on_memory(copy_amount, mem_ptr);
|
||||
}
|
||||
}
|
||||
|
|
@ -430,7 +413,7 @@ void DeviceMemoryManager<Traits>::ReadBlock(DAddr address, void* dest_pointer, s
|
|||
}
|
||||
|
||||
const std::size_t page_index = address >> Memory::YUZU_PAGEBITS;
|
||||
const auto phys_addr = compressed_physical_ptr[page_index];
|
||||
const auto phys_addr = tracked_entries[page_index].compressed_physical_ptr;
|
||||
if (phys_addr != 0) {
|
||||
auto* const mem_ptr = GetPointerFromRaw<u8>((PAddr(phys_addr - 1) << Memory::YUZU_PAGEBITS));
|
||||
t_slot[cache_cursor % t_slot.size()] = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
|
||||
|
|
@ -488,7 +471,7 @@ void DeviceMemoryManager<Traits>::ReadBlockUnsafe(DAddr address, void* dest_poin
|
|||
}
|
||||
|
||||
const std::size_t page_index = address >> Memory::YUZU_PAGEBITS;
|
||||
const auto phys_addr = compressed_physical_ptr[page_index];
|
||||
const auto phys_addr = tracked_entries[page_index].compressed_physical_ptr;
|
||||
if (phys_addr != 0) {
|
||||
auto* const mem_ptr = GetPointerFromRaw<u8>((PAddr(phys_addr - 1) << Memory::YUZU_PAGEBITS));
|
||||
t_slot[cache_cursor % t_slot.size()] = TranslationEntry{.guest_page = guest_page, .host_ptr = mem_ptr};
|
||||
|
|
|
|||
|
|
@ -123,6 +123,39 @@ bool IsVersionedExternalUpdateDisabled(const std::vector<std::string>& disabled,
|
|||
return std::find(disabled.cbegin(), disabled.cend(), disabled_key) != disabled.cend() ||
|
||||
std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
|
||||
}
|
||||
|
||||
std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64 update_tid) {
|
||||
if (provider == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto control_nca = provider->GetEntry(update_tid, ContentRecordType::Control);
|
||||
if (control_nca == nullptr ||
|
||||
control_nca->GetStatus() != Loader::ResultStatus::Success) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto romfs = control_nca->GetRomFS();
|
||||
if (romfs == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto extracted = ExtractRomFS(romfs);
|
||||
if (extracted == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto nacp_file = extracted->GetFile("control.nacp");
|
||||
if (nacp_file == nullptr) {
|
||||
nacp_file = extracted->GetFile("Control.nacp");
|
||||
}
|
||||
if (nacp_file == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
NACP nacp{nacp_file};
|
||||
return nacp.GetVersionString();
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
PatchManager::PatchManager(u64 title_id_,
|
||||
|
|
@ -771,6 +804,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||
std::nullopt, std::nullopt, ContentRecordType::Program, update_tid);
|
||||
|
||||
for (const auto& [slot, entry] : all_updates) {
|
||||
(void)entry;
|
||||
if (slot == ContentProviderUnionSlot::External ||
|
||||
slot == ContentProviderUnionSlot::FrontendManual) {
|
||||
continue;
|
||||
|
|
@ -786,7 +820,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||
source_suffix = " (NAND)";
|
||||
break;
|
||||
case ContentProviderUnionSlot::SDMC:
|
||||
source_type = PatchSource::NAND;
|
||||
source_type = PatchSource::SDMC;
|
||||
source_suffix = " (SDMC)";
|
||||
break;
|
||||
default:
|
||||
|
|
@ -795,19 +829,16 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||
|
||||
std::string version_str;
|
||||
u32 numeric_ver = 0;
|
||||
PatchManager update{update_tid, fs_controller, content_provider};
|
||||
const auto metadata = update.GetControlMetadata();
|
||||
const auto& nacp = metadata.first;
|
||||
const auto* slot_provider = content_union->GetSlotProvider(slot);
|
||||
version_str = GetUpdateVersionStringFromSlot(slot_provider, update_tid);
|
||||
|
||||
if (nacp != nullptr) {
|
||||
version_str = nacp->GetVersionString();
|
||||
}
|
||||
|
||||
const auto meta_ver = content_provider.GetEntryVersion(update_tid);
|
||||
if (meta_ver.has_value()) {
|
||||
numeric_ver = *meta_ver;
|
||||
if (version_str.empty() && numeric_ver != 0) {
|
||||
version_str = FormatTitleVersion(numeric_ver);
|
||||
if (slot_provider != nullptr) {
|
||||
const auto slot_ver = slot_provider->GetEntryVersion(update_tid);
|
||||
if (slot_ver.has_value()) {
|
||||
numeric_ver = *slot_ver;
|
||||
if (version_str.empty() && numeric_ver != 0) {
|
||||
version_str = FormatTitleVersion(numeric_ver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -956,37 +987,60 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||
}
|
||||
|
||||
// DLC
|
||||
const auto dlc_entries =
|
||||
content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
|
||||
|
||||
std::vector<ContentProviderEntry> dlc_match;
|
||||
dlc_match.reserve(dlc_entries.size());
|
||||
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
|
||||
[this](const ContentProviderEntry& entry) {
|
||||
const auto base_tid = GetBaseTitleID(entry.title_id);
|
||||
const bool matches_base = base_tid == title_id;
|
||||
bool has_external_dlc = false;
|
||||
bool has_nand_dlc = false;
|
||||
bool has_sdmc_dlc = false;
|
||||
bool has_other_dlc = false;
|
||||
const auto dlc_entries_with_origin =
|
||||
content_union->ListEntriesFilterOrigin(std::nullopt, TitleType::AOC, ContentRecordType::Data);
|
||||
|
||||
if (!matches_base) {
|
||||
LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}",
|
||||
entry.title_id, base_tid, title_id);
|
||||
return false;
|
||||
}
|
||||
dlc_match.reserve(dlc_entries_with_origin.size());
|
||||
for (const auto& [slot, entry] : dlc_entries_with_origin) {
|
||||
const auto base_tid = GetBaseTitleID(entry.title_id);
|
||||
const bool matches_base = base_tid == title_id;
|
||||
if (!matches_base) {
|
||||
LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}",
|
||||
entry.title_id, base_tid, title_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto nca = content_provider.GetEntry(entry);
|
||||
if (!nca) {
|
||||
LOG_DEBUG(Loader, "Failed to get NCA for DLC {:016X}", entry.title_id);
|
||||
return false;
|
||||
}
|
||||
const auto* slot_provider = content_union->GetSlotProvider(slot);
|
||||
if (slot_provider == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto status = nca->GetStatus();
|
||||
if (status != Loader::ResultStatus::Success) {
|
||||
LOG_DEBUG(Loader, "DLC {:016X} NCA has status {}",
|
||||
entry.title_id, static_cast<int>(status));
|
||||
return false;
|
||||
}
|
||||
auto nca = slot_provider->GetEntry(entry);
|
||||
if (!nca) {
|
||||
LOG_DEBUG(Loader, "Failed to get NCA for DLC {:016X}", entry.title_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
const auto status = nca->GetStatus();
|
||||
if (status != Loader::ResultStatus::Success) {
|
||||
LOG_DEBUG(Loader, "DLC {:016X} NCA has status {}", entry.title_id,
|
||||
static_cast<int>(status));
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (slot) {
|
||||
case ContentProviderUnionSlot::External:
|
||||
case ContentProviderUnionSlot::FrontendManual:
|
||||
has_external_dlc = true;
|
||||
break;
|
||||
case ContentProviderUnionSlot::UserNAND:
|
||||
case ContentProviderUnionSlot::SysNAND:
|
||||
has_nand_dlc = true;
|
||||
break;
|
||||
case ContentProviderUnionSlot::SDMC:
|
||||
has_sdmc_dlc = true;
|
||||
break;
|
||||
default:
|
||||
has_other_dlc = true;
|
||||
break;
|
||||
}
|
||||
dlc_match.push_back(entry);
|
||||
}
|
||||
|
||||
if (!dlc_match.empty()) {
|
||||
// Ensure sorted so DLC IDs show in order.
|
||||
|
|
@ -1000,13 +1054,22 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
|||
|
||||
const auto dlc_disabled =
|
||||
std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end();
|
||||
PatchSource dlc_source = PatchSource::Unknown;
|
||||
if (has_external_dlc && !has_nand_dlc && !has_sdmc_dlc && !has_other_dlc) {
|
||||
dlc_source = PatchSource::External;
|
||||
} else if (has_nand_dlc && !has_external_dlc && !has_sdmc_dlc && !has_other_dlc) {
|
||||
dlc_source = PatchSource::NAND;
|
||||
} else if (has_sdmc_dlc && !has_external_dlc && !has_nand_dlc && !has_other_dlc) {
|
||||
dlc_source = PatchSource::SDMC;
|
||||
}
|
||||
|
||||
out.push_back({.enabled = !dlc_disabled,
|
||||
.name = "DLC",
|
||||
.version = std::move(list),
|
||||
.type = PatchType::DLC,
|
||||
.program_id = title_id,
|
||||
.title_id = dlc_match.back().title_id,
|
||||
.source = PatchSource::Unknown});
|
||||
.source = dlc_source});
|
||||
}
|
||||
|
||||
return out;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ enum class PatchType { Update, DLC, Mod };
|
|||
enum class PatchSource {
|
||||
Unknown,
|
||||
NAND,
|
||||
SDMC,
|
||||
External,
|
||||
Packed,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -104,7 +107,8 @@ Result TimeZoneService::LoadLocationNameList(
|
|||
OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) {
|
||||
SCOPE_EXIT {
|
||||
LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}",
|
||||
index, *out_count, out_names[0], out_names[1]);
|
||||
index, *out_count, out_names.size() > 0 ? out_names[0] : Service::PSC::Time::LocationName{},
|
||||
out_names.size() > 1 ? out_names[1] : Service::PSC::Time::LocationName{});
|
||||
};
|
||||
|
||||
std::scoped_lock l{m_mutex};
|
||||
|
|
@ -208,7 +212,8 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
|
|||
SCOPE_EXIT {
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
|
||||
calendar_time, *out_count, out_times[0], out_times[1]);
|
||||
calendar_time, *out_count, out_times.size() > 0 ? out_times[0] : s64{0},
|
||||
out_times.size() > 1 ? out_times[1] : s64{0});
|
||||
};
|
||||
|
||||
R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule));
|
||||
|
|
@ -220,7 +225,8 @@ Result TimeZoneService::ToPosixTimeWithMyRule(
|
|||
SCOPE_EXIT {
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
|
||||
calendar_time, *out_count, out_times[0], out_times[1]);
|
||||
calendar_time, *out_count, out_times.size() > 0 ? out_times[0] : s64{0},
|
||||
out_times.size() > 1 ? out_times[1] : s64{0});
|
||||
};
|
||||
|
||||
R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time));
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
#include <map>
|
||||
#include <span>
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
#include <dynarmic/interface/A64/a64.h>
|
||||
#include <dynarmic/interface/A64/config.h>
|
||||
#include <dynarmic/interface/code_page.h>
|
||||
#include "dynarmic/interface/A64/a64.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
#include "dynarmic/interface/code_page.h"
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -148,7 +151,8 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
|
|||
SCOPE_EXIT {
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
|
||||
calendar_time, *out_count, out_times[0], out_times[1]);
|
||||
calendar_time, *out_count, out_times.size() > 0 ? out_times[0] : s64{0},
|
||||
out_times.size() > 1 ? out_times[1] : s64{0});
|
||||
};
|
||||
|
||||
R_RETURN(
|
||||
|
|
@ -161,7 +165,8 @@ Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count,
|
|||
SCOPE_EXIT {
|
||||
LOG_DEBUG(Service_Time,
|
||||
"called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
|
||||
calendar_time, *out_count, out_times[0], out_times[1]);
|
||||
calendar_time, *out_count, out_times.size() > 0 ? out_times[0] : s64{0},
|
||||
out_times.size() > 1 ? out_times[1] : s64{0});
|
||||
};
|
||||
|
||||
R_RETURN(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
|
|
@ -29,10 +29,13 @@ namespace Service {
|
|||
return function_string;
|
||||
}
|
||||
|
||||
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
|
||||
u32 max_sessions_, InvokerFn* handler_invoker_)
|
||||
: SessionRequestHandler(system_.Kernel(), service_name_), system{system_},
|
||||
service_name{service_name_}, handler_invoker{handler_invoker_}, max_sessions{max_sessions_} {}
|
||||
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_, u32 max_sessions_, InvokerFn* handler_invoker_)
|
||||
: SessionRequestHandler(system_.Kernel(), service_name_)
|
||||
, system{system_}
|
||||
, service_name{service_name_}
|
||||
, handler_invoker{handler_invoker_}
|
||||
, max_sessions{max_sessions_}
|
||||
{}
|
||||
|
||||
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||
// Wait for other threads to release access before destroying
|
||||
|
|
@ -50,8 +53,7 @@ void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* func
|
|||
// Usually this array is sorted by id already, so hint to insert at the end
|
||||
handlers_tipc.reserve(handlers_tipc.size() + n);
|
||||
for (std::size_t i = 0; i < n; ++i)
|
||||
handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header,
|
||||
functions[i]);
|
||||
handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header, functions[i]);
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
|
||||
|
|
@ -78,13 +77,6 @@ protected:
|
|||
[[nodiscard]] virtual std::unique_lock<std::mutex> LockService() noexcept {
|
||||
return std::unique_lock{lock_service};
|
||||
}
|
||||
|
||||
/// System context that the service operates under.
|
||||
Core::System& system;
|
||||
|
||||
/// Identifier string used to connect to the service.
|
||||
std::string service_name;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
friend class ServiceFramework;
|
||||
|
|
@ -106,16 +98,19 @@ private:
|
|||
void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
|
||||
void ReportUnimplementedFunction(HLERequestContext& ctx, const FunctionInfoBase* info);
|
||||
|
||||
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
||||
boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
|
||||
protected:
|
||||
ankerl::unordered_dense::map<u32, FunctionInfoBase> handlers;
|
||||
ankerl::unordered_dense::map<u32, FunctionInfoBase> handlers_tipc;
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
std::mutex lock_service;
|
||||
/// System context that the service operates under.
|
||||
Core::System& system;
|
||||
/// Identifier string used to connect to the service.
|
||||
const char* service_name;
|
||||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||
InvokerFn* handler_invoker;
|
||||
|
||||
/// Maximum number of concurrent sessions that this service can handle.
|
||||
u32 max_sessions;
|
||||
|
||||
/// Flag to store if a port was already create/installed to detect multiple install attempts,
|
||||
/// which is not supported.
|
||||
bool service_registered = false;
|
||||
|
|
@ -159,8 +154,7 @@ protected:
|
|||
* @param max_sessions_ Maximum number of sessions that can be connected to this service at the
|
||||
* same time.
|
||||
*/
|
||||
explicit ServiceFramework(Core::System& system_, const char* service_name_,
|
||||
u32 max_sessions_ = ServerSessionCountMax)
|
||||
explicit ServiceFramework(Core::System& system_, const char* service_name_, u32 max_sessions_ = ServerSessionCountMax)
|
||||
: ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
|
||||
|
||||
/// Registers handlers in the service.
|
||||
|
|
@ -219,7 +213,7 @@ private:
|
|||
static void Invoker(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
|
||||
HLERequestContext& ctx) {
|
||||
// Cast back up to our original types and call the member function
|
||||
(static_cast<Self*>(object)->*static_cast<HandlerFnP<Self>>(member))(ctx);
|
||||
(static_cast<Self*>(object)->*HandlerFnP<Self>(member))(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
Copyright (C) 2017 merryhime <git@mary.rs>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
|
@ -69,6 +69,7 @@ add_library(dynarmic STATIC
|
|||
frontend/decoder/matcher.h
|
||||
frontend/imm.cpp
|
||||
frontend/imm.h
|
||||
interface/halt_reason.h
|
||||
interface/exclusive_monitor.h
|
||||
interface/optimization_flags.h
|
||||
ir/acc_type.h
|
||||
|
|
|
|||
|
|
@ -687,7 +687,7 @@ void A32EmitX64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
|
|||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
auto& arg = args[0];
|
||||
|
||||
const u32 upper_without_t = (ctx.EndLocation().SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE;
|
||||
const u64 upper_without_t = (ctx.EndLocation().SetSingleStepping(false).UniqueHash() >> 32) & 0xFFFFFFFE;
|
||||
|
||||
// Pseudocode:
|
||||
// if (new_pc & 1) {
|
||||
|
|
|
|||
|
|
@ -947,7 +947,7 @@ static void EmitAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, size_t
|
|||
const Xbyak::Reg8 overflow = overflow_inst ? ctx.reg_alloc.ScratchGpr(code).cvt8() : Xbyak::Reg8{-1};
|
||||
|
||||
if (args[1].IsImmediate() && args[1].GetType() == IR::Type::U32) {
|
||||
const u32 op_arg = args[1].GetImmediateU32();
|
||||
const u64 op_arg = args[1].GetImmediateU64();
|
||||
if (carry_in.IsImmediate()) {
|
||||
if (carry_in.GetImmediateU1()) {
|
||||
// In range for a valid LEA materialisation
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -135,7 +135,7 @@ void EmitX64::EmitSignedSaturation(EmitContext& ctx, IR::Inst* inst) {
|
|||
|
||||
const u32 mask = (1u << N) - 1;
|
||||
const u32 positive_saturated_value = (1u << (N - 1)) - 1;
|
||||
const u32 negative_saturated_value = 1u << (N - 1);
|
||||
const u64 negative_saturated_value = 1u << (N - 1);
|
||||
|
||||
const Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr(code).cvt32();
|
||||
const Xbyak::Reg32 reg_a = ctx.reg_alloc.UseGpr(code, args[0]).cvt32();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
#include <cstring>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
|
||||
#include <dynarmic/common/spin_lock.h>
|
||||
#include "dynarmic/common/spin_lock.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
|
||||
|
|
|
|||
14
src/ios/AppUI-Bridging-Header.h
Normal file
14
src/ios/AppUI-Bridging-Header.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
//
|
||||
// AppUI-Bridging-Header.h - Sudachi
|
||||
// Created by Jarrod Norwell on 4/3/2024.
|
||||
//
|
||||
|
||||
#ifndef AppUI_Bridging_Header_h
|
||||
#define AppUI_Bridging_Header_h
|
||||
|
||||
#import "Wrapper/AppUIObjC.h"
|
||||
|
||||
#endif /* AppUI_Bridging_Header_h */
|
||||
107
src/ios/AppUI.swift
Normal file
107
src/ios/AppUI.swift
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
//
|
||||
// AppUI.swift - Sudachi
|
||||
// Created by Jarrod Norwell on 4/3/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import QuartzCore.CAMetalLayer
|
||||
|
||||
public struct AppUI {
|
||||
|
||||
public static let shared = AppUI()
|
||||
|
||||
fileprivate let appUIObjC = AppUIObjC.shared()
|
||||
|
||||
public func configure(layer: CAMetalLayer, with size: CGSize) {
|
||||
appUIObjC.configure(layer: layer, with: size)
|
||||
}
|
||||
|
||||
public func information(for url: URL) -> AppUIInformation {
|
||||
appUIObjC.gameInformation.information(for: url)
|
||||
}
|
||||
|
||||
public func insert(game url: URL) {
|
||||
appUIObjC.insert(game: url)
|
||||
}
|
||||
|
||||
public func insert(games urls: [URL]) {
|
||||
appUIObjC.insert(games: urls)
|
||||
}
|
||||
|
||||
public func bootOS() {
|
||||
appUIObjC.bootOS()
|
||||
}
|
||||
|
||||
public func pause() {
|
||||
appUIObjC.pause()
|
||||
}
|
||||
|
||||
public func play() {
|
||||
appUIObjC.play()
|
||||
}
|
||||
|
||||
public func ispaused() -> Bool {
|
||||
return appUIObjC.ispaused()
|
||||
}
|
||||
|
||||
public func FirstFrameShowed() -> Bool {
|
||||
return appUIObjC.hasfirstfame()
|
||||
}
|
||||
|
||||
public func canGetFullPath() -> Bool {
|
||||
return appUIObjC.canGetFullPath()
|
||||
}
|
||||
|
||||
|
||||
public func exit() {
|
||||
appUIObjC.quit()
|
||||
}
|
||||
|
||||
public func step() {
|
||||
appUIObjC.step()
|
||||
}
|
||||
|
||||
public func orientationChanged(orientation: UIInterfaceOrientation, with layer: CAMetalLayer, size: CGSize) {
|
||||
appUIObjC.orientationChanged(orientation: orientation, with: layer, size: size)
|
||||
}
|
||||
|
||||
public func touchBegan(at point: CGPoint, for index: UInt) {
|
||||
appUIObjC.touchBegan(at: point, for: index)
|
||||
}
|
||||
|
||||
public func touchEnded(for index: UInt) {
|
||||
appUIObjC.touchEnded(for: index)
|
||||
}
|
||||
|
||||
public func touchMoved(at point: CGPoint, for index: UInt) {
|
||||
appUIObjC.touchMoved(at: point, for: index)
|
||||
}
|
||||
|
||||
public func gyroMoved(x: Float, y: Float, z: Float, accelX: Float, accelY: Float, accelZ: Float, controllerId: Int32, deltaTimestamp: Int32) {
|
||||
// Calling the Objective-C function with both gyroscope and accelerometer data
|
||||
appUIObjC.virtualControllerGyro(controllerId,
|
||||
deltaTimestamp: deltaTimestamp,
|
||||
gyroX: x, gyroY: y, gyroZ: z,
|
||||
accelX: accelX, accelY: accelY, accelZ: accelZ)
|
||||
}
|
||||
|
||||
|
||||
public func thumbstickMoved(analog: VirtualControllerAnalogType, x: Float, y: Float, controllerid: Int) {
|
||||
appUIObjC.thumbstickMoved(analog, x: CGFloat(x), y: CGFloat(y), controllerId: Int32(controllerid))
|
||||
}
|
||||
|
||||
public func virtualControllerButtonDown(button: VirtualControllerButtonType, controllerid: Int) {
|
||||
appUIObjC.virtualControllerButtonDown(button, controllerId: Int32(controllerid))
|
||||
}
|
||||
|
||||
public func virtualControllerButtonUp(button: VirtualControllerButtonType, controllerid: Int) {
|
||||
appUIObjC.virtualControllerButtonUp(button, controllerId: Int32(controllerid))
|
||||
}
|
||||
|
||||
public func settingsSaved() {
|
||||
appUIObjC.settingsChanged()
|
||||
}
|
||||
}
|
||||
29
src/ios/AppUIGameInformation.h
Normal file
29
src/ios/AppUIGameInformation.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
//
|
||||
// AppUIGameInformation.h - Sudachi
|
||||
// Created by Jarrod Norwell on 1/20/24.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AppUIInformation : NSObject
|
||||
@property (nonatomic, strong) NSString *developer;
|
||||
@property (nonatomic, strong) NSData *iconData;
|
||||
@property (nonatomic) BOOL isHomebrew;
|
||||
@property (nonatomic) uint64_t programID;
|
||||
@property (nonatomic, strong) NSString *title, *version;
|
||||
|
||||
-(AppUIInformation *) initWithDeveloper:(NSString *)developer iconData:(NSData *)iconData isHomebrew:(BOOL)isHomebrew programID:(uint64_t)programID title:(NSString *)title version:(NSString *)version;
|
||||
@end
|
||||
|
||||
@interface AppUIGameInformation : NSObject
|
||||
+(AppUIGameInformation *) sharedInstance NS_SWIFT_NAME(shared());
|
||||
|
||||
-(AppUIInformation *) informationForGame:(NSURL *)url NS_SWIFT_NAME(information(for:));
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
442
src/ios/AppUIGameInformation.mm
Normal file
442
src/ios/AppUIGameInformation.mm
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
//
|
||||
// AppUIGameInformation.mm - Sudachi
|
||||
// Created by Jarrod Norwell on 1/20/24.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AppUIGameInformation.h"
|
||||
#import "EmulationSession/EmulationSession.h"
|
||||
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/loader/nro.h"
|
||||
#include "frontend_common/yuzu_config.h"
|
||||
|
||||
struct GameMetadata {
|
||||
std::string title;
|
||||
u64 programId;
|
||||
std::string developer;
|
||||
std::string version;
|
||||
std::vector<u8> icon;
|
||||
bool isHomebrew;
|
||||
};
|
||||
|
||||
|
||||
class SdlConfig final : public Config {
|
||||
public:
|
||||
explicit SdlConfig(std::optional<std::string> config_path);
|
||||
~SdlConfig() override;
|
||||
|
||||
void ReloadAllValues() override;
|
||||
void SaveAllValues() override;
|
||||
|
||||
protected:
|
||||
void ReadSdlValues();
|
||||
void ReadSdlPlayerValues(std::size_t player_index);
|
||||
void ReadSdlControlValues();
|
||||
void ReadHidbusValues() override;
|
||||
void ReadDebugControlValues() override;
|
||||
void ReadPathValues() override {}
|
||||
void ReadShortcutValues() override {}
|
||||
void ReadUIValues() override {}
|
||||
void ReadUIGamelistValues() override {}
|
||||
void ReadUILayoutValues() override {}
|
||||
void ReadMultiplayerValues() override {}
|
||||
|
||||
void SaveSdlValues();
|
||||
void SaveSdlPlayerValues(std::size_t player_index);
|
||||
void SaveSdlControlValues();
|
||||
void SaveHidbusValues() override;
|
||||
void SaveDebugControlValues() override;
|
||||
void SavePathValues() override {}
|
||||
void SaveShortcutValues() override {}
|
||||
void SaveUIValues() override {}
|
||||
void SaveUIGamelistValues() override {}
|
||||
void SaveUILayoutValues() override {}
|
||||
void SaveMultiplayerValues() override {}
|
||||
|
||||
std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
|
||||
|
||||
public:
|
||||
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
|
||||
static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
|
||||
static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
|
||||
static const std::array<int, 2> default_stick_mod;
|
||||
static const std::array<int, 2> default_ringcon_analogs;
|
||||
};
|
||||
|
||||
|
||||
#define SDL_MAIN_HANDLED
|
||||
#include <SDL.h>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "input_common/main.h"
|
||||
|
||||
const std::array<int, Settings::NativeButton::NumButtons> SdlConfig::default_buttons = {
|
||||
SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T,
|
||||
SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W,
|
||||
SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B,
|
||||
};
|
||||
|
||||
const std::array<int, Settings::NativeMotion::NumMotions> SdlConfig::default_motions = {
|
||||
SDL_SCANCODE_7,
|
||||
SDL_SCANCODE_8,
|
||||
};
|
||||
|
||||
const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> SdlConfig::default_analogs{
|
||||
{
|
||||
{
|
||||
SDL_SCANCODE_UP,
|
||||
SDL_SCANCODE_DOWN,
|
||||
SDL_SCANCODE_LEFT,
|
||||
SDL_SCANCODE_RIGHT,
|
||||
},
|
||||
{
|
||||
SDL_SCANCODE_I,
|
||||
SDL_SCANCODE_K,
|
||||
SDL_SCANCODE_J,
|
||||
SDL_SCANCODE_L,
|
||||
},
|
||||
}};
|
||||
|
||||
const std::array<int, 2> SdlConfig::default_stick_mod = {
|
||||
SDL_SCANCODE_D,
|
||||
0,
|
||||
};
|
||||
|
||||
const std::array<int, 2> SdlConfig::default_ringcon_analogs{{
|
||||
0,
|
||||
0,
|
||||
}};
|
||||
|
||||
SdlConfig::SdlConfig(const std::optional<std::string> config_path) {
|
||||
Initialize(config_path);
|
||||
ReadSdlValues();
|
||||
SaveSdlValues();
|
||||
}
|
||||
|
||||
SdlConfig::~SdlConfig() {
|
||||
if (global) {
|
||||
SdlConfig::SaveAllValues();
|
||||
}
|
||||
}
|
||||
|
||||
void SdlConfig::ReloadAllValues() {
|
||||
Reload();
|
||||
ReadSdlValues();
|
||||
SaveSdlValues();
|
||||
}
|
||||
|
||||
void SdlConfig::SaveAllValues() {
|
||||
SaveValues();
|
||||
SaveSdlValues();
|
||||
}
|
||||
|
||||
void SdlConfig::ReadSdlValues() {
|
||||
ReadSdlControlValues();
|
||||
}
|
||||
|
||||
void SdlConfig::ReadSdlControlValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||
|
||||
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||
ReadSdlPlayerValues(p);
|
||||
}
|
||||
if (IsCustomConfig()) {
|
||||
EndGroup();
|
||||
return;
|
||||
}
|
||||
ReadDebugControlValues();
|
||||
ReadHidbusValues();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) {
|
||||
std::string player_prefix;
|
||||
if (type != ConfigType::InputProfile) {
|
||||
player_prefix.append("player_").append(ToString(player_index)).append("_");
|
||||
}
|
||||
|
||||
auto& player = Settings::values.players.GetValue()[player_index];
|
||||
if (IsCustomConfig()) {
|
||||
const auto profile_name =
|
||||
ReadStringSetting(std::string(player_prefix).append("profile_name"));
|
||||
if (profile_name.empty()) {
|
||||
// Use the global input config
|
||||
player = Settings::values.players.GetValue(true)[player_index];
|
||||
player.profile_name = "";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
auto& player_buttons = player.buttons[i];
|
||||
|
||||
player_buttons = ReadStringSetting(
|
||||
std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param);
|
||||
if (player_buttons.empty()) {
|
||||
player_buttons = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||
auto& player_analogs = player.analogs[i];
|
||||
|
||||
player_analogs = ReadStringSetting(
|
||||
std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param);
|
||||
if (player_analogs.empty()) {
|
||||
player_analogs = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||
auto& player_motions = player.motions[i];
|
||||
|
||||
player_motions = ReadStringSetting(
|
||||
std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param);
|
||||
if (player_motions.empty()) {
|
||||
player_motions = default_param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SdlConfig::ReadDebugControlValues() {
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i];
|
||||
debug_pad_buttons = ReadStringSetting(
|
||||
std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param);
|
||||
if (debug_pad_buttons.empty()) {
|
||||
debug_pad_buttons = default_param;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||
auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
|
||||
debug_pad_analogs = ReadStringSetting(
|
||||
std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param);
|
||||
if (debug_pad_analogs.empty()) {
|
||||
debug_pad_analogs = default_param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SdlConfig::ReadHidbusValues() {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
|
||||
auto& ringcon_analogs = Settings::values.ringcon_analogs;
|
||||
|
||||
ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param);
|
||||
if (ringcon_analogs.empty()) {
|
||||
ringcon_analogs = default_param;
|
||||
}
|
||||
}
|
||||
|
||||
void SdlConfig::SaveSdlValues() {
|
||||
LOG_DEBUG(Config, "Saving SDL configuration values");
|
||||
SaveSdlControlValues();
|
||||
|
||||
WriteToIni();
|
||||
}
|
||||
|
||||
void SdlConfig::SaveSdlControlValues() {
|
||||
BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
|
||||
|
||||
Settings::values.players.SetGlobal(!IsCustomConfig());
|
||||
for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
|
||||
SaveSdlPlayerValues(p);
|
||||
}
|
||||
if (IsCustomConfig()) {
|
||||
EndGroup();
|
||||
return;
|
||||
}
|
||||
SaveDebugControlValues();
|
||||
SaveHidbusValues();
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) {
|
||||
std::string player_prefix;
|
||||
if (type != ConfigType::InputProfile) {
|
||||
player_prefix = std::string("player_").append(ToString(player_index)).append("_");
|
||||
}
|
||||
|
||||
const auto& player = Settings::values.players.GetValue()[player_index];
|
||||
if (IsCustomConfig() && player.profile_name.empty()) {
|
||||
// No custom profile selected
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
WriteStringSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]),
|
||||
player.buttons[i], std::make_optional(default_param));
|
||||
}
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||
WriteStringSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]),
|
||||
player.analogs[i], std::make_optional(default_param));
|
||||
}
|
||||
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
|
||||
WriteStringSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]),
|
||||
player.motions[i], std::make_optional(default_param));
|
||||
}
|
||||
}
|
||||
|
||||
void SdlConfig::SaveDebugControlValues() {
|
||||
for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
|
||||
WriteStringSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]),
|
||||
Settings::values.debug_pad_buttons[i],
|
||||
std::make_optional(default_param));
|
||||
}
|
||||
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
|
||||
default_analogs[i][3], default_stick_mod[i], 0.5f);
|
||||
WriteStringSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]),
|
||||
Settings::values.debug_pad_analogs[i],
|
||||
std::make_optional(default_param));
|
||||
}
|
||||
}
|
||||
|
||||
void SdlConfig::SaveHidbusValues() {
|
||||
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
|
||||
0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
|
||||
WriteStringSetting(std::string("ring_controller"), Settings::values.ringcon_analogs,
|
||||
std::make_optional(default_param));
|
||||
}
|
||||
|
||||
std::vector<Settings::BasicSetting*>& SdlConfig::FindRelevantList(Settings::Category category) {
|
||||
return Settings::values.linkage.by_category[category];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::unordered_map<std::string, GameMetadata> m_game_metadata_cache;
|
||||
|
||||
GameMetadata CacheGameMetadata(const std::string& path) {
|
||||
const auto file =
|
||||
Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path);
|
||||
auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
|
||||
|
||||
GameMetadata entry;
|
||||
loader->ReadTitle(entry.title);
|
||||
loader->ReadProgramId(entry.programId);
|
||||
loader->ReadIcon(entry.icon);
|
||||
|
||||
const FileSys::PatchManager pm{
|
||||
entry.programId, EmulationSession::GetInstance().System().GetFileSystemController(),
|
||||
EmulationSession::GetInstance().System().GetContentProvider()};
|
||||
const auto control = pm.GetControlMetadata();
|
||||
|
||||
if (control.first != nullptr) {
|
||||
entry.developer = control.first->GetDeveloperName();
|
||||
entry.version = control.first->GetVersionString();
|
||||
} else {
|
||||
FileSys::NACP nacp;
|
||||
if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
|
||||
entry.developer = nacp.GetDeveloperName();
|
||||
} else {
|
||||
entry.developer = "";
|
||||
}
|
||||
|
||||
entry.version = "1.0.0";
|
||||
}
|
||||
|
||||
if (loader->GetFileType() == Loader::FileType::NRO) {
|
||||
auto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
|
||||
entry.isHomebrew = loader_nro->IsHomebrew();
|
||||
} else {
|
||||
entry.isHomebrew = false;
|
||||
}
|
||||
|
||||
m_game_metadata_cache[path] = entry;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
GameMetadata GameMetadata(const std::string& path, bool reload = false) {
|
||||
if (!EmulationSession::GetInstance().IsInitialized()) {
|
||||
NSURL *dir_url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
|
||||
const char *directory_cstr = [[dir_url path] UTF8String];
|
||||
Common::FS::SetAppDirectory(directory_cstr);
|
||||
|
||||
EmulationSession::GetInstance().System().Initialize();
|
||||
EmulationSession::GetInstance().InitializeSystem(false);
|
||||
}
|
||||
|
||||
if (reload) {
|
||||
return CacheGameMetadata(path);
|
||||
}
|
||||
|
||||
if (auto search = m_game_metadata_cache.find(path); search != m_game_metadata_cache.end()) {
|
||||
return search->second;
|
||||
}
|
||||
|
||||
return CacheGameMetadata(path);
|
||||
}
|
||||
|
||||
|
||||
@implementation AppUIInformation
|
||||
-(AppUIInformation *) initWithDeveloper:(NSString *)developer iconData:(NSData *)iconData isHomebrew:(BOOL)isHomebrew programID:(uint64_t)programID
|
||||
title:(NSString *)title version:(NSString *)version {
|
||||
if (self = [super init]) {
|
||||
self.developer = developer;
|
||||
self.iconData = iconData;
|
||||
self.isHomebrew = isHomebrew;
|
||||
self.programID = programID;
|
||||
self.title = title;
|
||||
self.version = version;
|
||||
} return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation AppUIGameInformation
|
||||
+(AppUIGameInformation *) sharedInstance {
|
||||
static AppUIGameInformation *sharedInstance = NULL;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] init];
|
||||
});
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
|
||||
-(AppUIInformation *) informationForGame:(NSURL *)url {
|
||||
auto gameMetadata = GameMetadata([url.path UTF8String]);
|
||||
|
||||
return [[AppUIInformation alloc] initWithDeveloper:[NSString stringWithCString:gameMetadata.developer.c_str() encoding:NSUTF8StringEncoding]
|
||||
iconData:[NSData dataWithBytes:gameMetadata.icon.data() length:gameMetadata.icon.size()]
|
||||
isHomebrew:gameMetadata.isHomebrew programID:gameMetadata.programId
|
||||
title:[NSString stringWithCString:gameMetadata.title.c_str() encoding:NSUTF8StringEncoding]
|
||||
version:[NSString stringWithCString:gameMetadata.version.c_str() encoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
@end
|
||||
95
src/ios/AppUIObjC.h
Normal file
95
src/ios/AppUIObjC.h
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
//
|
||||
// AppUIObjC.h - Sudachi
|
||||
// Created by Jarrod Norwell on 1/8/24.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <MetalKit/MetalKit.h>
|
||||
|
||||
#import "AppUIGameInformation/AppUIGameInformation.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, VirtualControllerAnalogType) {
|
||||
VirtualControllerAnalogTypeLeft = 0,
|
||||
VirtualControllerAnalogTypeRight = 1
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, VirtualControllerButtonType) {
|
||||
VirtualControllerButtonTypeA = 0,
|
||||
VirtualControllerButtonTypeB = 1,
|
||||
VirtualControllerButtonTypeX = 2,
|
||||
VirtualControllerButtonTypeY = 3,
|
||||
VirtualControllerButtonTypeL = 4,
|
||||
VirtualControllerButtonTypeR = 5,
|
||||
VirtualControllerButtonTypeTriggerL = 6,
|
||||
VirtualControllerButtonTypeTriggerR = 7,
|
||||
VirtualControllerButtonTypeTriggerZL = 8,
|
||||
VirtualControllerButtonTypeTriggerZR = 9,
|
||||
VirtualControllerButtonTypePlus = 10,
|
||||
VirtualControllerButtonTypeMinus = 11,
|
||||
VirtualControllerButtonTypeDirectionalPadLeft = 12,
|
||||
VirtualControllerButtonTypeDirectionalPadUp = 13,
|
||||
VirtualControllerButtonTypeDirectionalPadRight = 14,
|
||||
VirtualControllerButtonTypeDirectionalPadDown = 15,
|
||||
VirtualControllerButtonTypeSL = 16,
|
||||
VirtualControllerButtonTypeSR = 17,
|
||||
VirtualControllerButtonTypeHome = 18,
|
||||
VirtualControllerButtonTypeCapture = 19
|
||||
};
|
||||
|
||||
@interface AppUIObjC : NSObject {
|
||||
CAMetalLayer *_layer;
|
||||
CGSize _size;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) AppUIGameInformation *gameInformation;
|
||||
|
||||
+(AppUIObjC *) sharedInstance NS_SWIFT_NAME(shared());
|
||||
-(void) configureLayer:(CAMetalLayer *)layer withSize:(CGSize)size NS_SWIFT_NAME(configure(layer:with:));
|
||||
-(void) bootOS;
|
||||
-(void) pause;
|
||||
-(void) play;
|
||||
-(BOOL) ispaused;
|
||||
-(BOOL) canGetFullPath;
|
||||
-(void) quit;
|
||||
-(void) insertGame:(NSURL *)url NS_SWIFT_NAME(insert(game:));
|
||||
-(void) insertGames:(NSArray<NSURL *> *)games NS_SWIFT_NAME(insert(games:));
|
||||
-(void) step;
|
||||
-(BOOL) hasfirstfame;
|
||||
|
||||
-(void) touchBeganAtPoint:(CGPoint)point index:(NSUInteger)index NS_SWIFT_NAME(touchBegan(at:for:));
|
||||
-(void) touchEndedForIndex:(NSUInteger)index;
|
||||
-(void) touchMovedAtPoint:(CGPoint)point index:(NSUInteger)index NS_SWIFT_NAME(touchMoved(at:for:));
|
||||
|
||||
-(void) thumbstickMoved:(VirtualControllerAnalogType)analog
|
||||
x:(CGFloat)x
|
||||
y:(CGFloat)y
|
||||
controllerId:(int)controllerId;
|
||||
|
||||
-(void) virtualControllerGyro:(int)controllerId
|
||||
deltaTimestamp:(int)delta_timestamp
|
||||
gyroX:(float)gyro_x
|
||||
gyroY:(float)gyro_y
|
||||
gyroZ:(float)gyro_z
|
||||
accelX:(float)accel_x
|
||||
accelY:(float)accel_y
|
||||
accelZ:(float)accel_z;
|
||||
|
||||
-(void) virtualControllerButtonDown:(VirtualControllerButtonType)button
|
||||
controllerId:(int)controllerId;
|
||||
|
||||
-(void) virtualControllerButtonUp:(VirtualControllerButtonType)button
|
||||
controllerId:(int)controllerId;
|
||||
|
||||
|
||||
-(void) orientationChanged:(UIInterfaceOrientation)orientation with:(CAMetalLayer *)layer size:(CGSize)size NS_SWIFT_NAME(orientationChanged(orientation:with:size:));
|
||||
|
||||
-(void) settingsChanged;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
263
src/ios/AppUIObjC.mm
Normal file
263
src/ios/AppUIObjC.mm
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
//
|
||||
// AppUIObjC.mm - Sudachi
|
||||
// Created by Jarrod Norwell on 1/8/24.
|
||||
//
|
||||
|
||||
#import "AppUIObjC.h"
|
||||
|
||||
#import "Config/Config.h"
|
||||
#import "EmulationSession/EmulationSession.h"
|
||||
#import "DirectoryManager/DirectoryManager.h"
|
||||
|
||||
#include "common/fs/fs.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/fs/fs.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/loader/nro.h"
|
||||
#include "frontend_common/content_manager.h"
|
||||
#include "common/settings_enums.h"
|
||||
#include "network/announce_multiplayer_session.h"
|
||||
#include "common/announce_multiplayer_room.h"
|
||||
#include "network/network.h"
|
||||
|
||||
#include "common/detached_tasks.h"
|
||||
#include "common/dynamic_library.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/cpu_manager.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/fs_filesystem.h"
|
||||
#include "core/file_sys/submission_package.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs_real.h"
|
||||
#include "core/frontend/applets/cabinet.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/frontend/applets/general.h"
|
||||
#include "core/frontend/applets/mii_edit.h"
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/frontend/applets/software_keyboard.h"
|
||||
#include "core/frontend/applets/web_browser.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "frontend_common/yuzu_config.h"
|
||||
#include "hid_core/frontend/emulated_controller.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
#include "video_core/vulkan_common/vulkan_instance.h"
|
||||
#include "video_core/vulkan_common/vulkan_surface.h"
|
||||
|
||||
|
||||
#import <mach/mach.h>
|
||||
|
||||
@implementation AppUIObjC
|
||||
-(AppUIObjC *) init {
|
||||
if (self = [super init]) {
|
||||
_gameInformation = [AppUIGameInformation sharedInstance];
|
||||
|
||||
NSURL *dir_url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
|
||||
const char *directory_cstr = [[dir_url path] UTF8String];
|
||||
|
||||
Common::FS::SetAppDirectory(directory_cstr);
|
||||
Config{"config", Config::ConfigType::GlobalConfig};
|
||||
|
||||
EmulationSession::GetInstance().System().Initialize();
|
||||
EmulationSession::GetInstance().InitializeSystem(false);
|
||||
EmulationSession::GetInstance().InitializeGpuDriver();
|
||||
|
||||
|
||||
Settings::values.dump_shaders.SetValue(true);
|
||||
Settings::values.use_asynchronous_shaders.SetValue(true);
|
||||
// Settings::values.astc_recompression.SetValue(Settings::AstcRecompression::Bc3);
|
||||
Settings::values.shader_backend.SetValue(Settings::ShaderBackend::SpirV);
|
||||
// Settings::values.resolution_setup.SetValue(Settings::ResolutionSetup::Res1X);
|
||||
// Settings::values.scaling_filter.SetValue(Settings::ScalingFilter::Bilinear);
|
||||
} return self;
|
||||
}
|
||||
|
||||
|
||||
+(AppUIObjC *) sharedInstance {
|
||||
static AppUIObjC *sharedInstance = NULL;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[self alloc] init];
|
||||
});
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (BOOL)ispaused {
|
||||
return EmulationSession::GetInstance().IsPaused();
|
||||
}
|
||||
|
||||
-(void) pause {
|
||||
EmulationSession::GetInstance().System().Pause();
|
||||
EmulationSession::GetInstance().HaltEmulation();
|
||||
EmulationSession::GetInstance().PauseEmulation();
|
||||
}
|
||||
|
||||
-(void) play {
|
||||
|
||||
EmulationSession::GetInstance().System().Run();
|
||||
EmulationSession::GetInstance().RunEmulation();
|
||||
EmulationSession::GetInstance().UnPauseEmulation();
|
||||
}
|
||||
|
||||
-(BOOL)hasfirstfame {
|
||||
@try {
|
||||
auto* window = &EmulationSession::GetInstance().Window();
|
||||
if (window && window->HasFirstFrame()) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
NSLog(@"Exception occurred: %@", exception);
|
||||
// Handle the exception, maybe return a default value
|
||||
return NO;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)canGetFullPath {
|
||||
@try {
|
||||
Core::System& system = EmulationSession::GetInstance().System();
|
||||
auto bis_system = system.GetFileSystemController().GetSystemNANDContents();
|
||||
|
||||
if (bis_system == nullptr) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::QLaunch);
|
||||
auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
|
||||
|
||||
if (qlaunch_applet_nca == nullptr) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
const auto filename = qlaunch_applet_nca->GetFullPath();
|
||||
|
||||
// If GetFullPath() is successful
|
||||
return YES;
|
||||
} @catch (NSException *exception) {
|
||||
// Handle the exception if needed
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
-(void) quit {
|
||||
EmulationSession::GetInstance().ShutdownEmulation();
|
||||
}
|
||||
|
||||
-(void) configureLayer:(CAMetalLayer *)layer withSize:(CGSize)size {
|
||||
_layer = layer;
|
||||
_size = size;
|
||||
EmulationSession::GetInstance().SetNativeWindow((__bridge CA::MetalLayer*)layer, size);
|
||||
}
|
||||
|
||||
-(void) bootOS {
|
||||
EmulationSession::GetInstance().BootOS();
|
||||
}
|
||||
|
||||
-(void) insertGame:(NSURL *)url {
|
||||
EmulationSession::GetInstance().InitializeEmulation([url.path UTF8String], [_gameInformation informationForGame:url].programID, true);
|
||||
}
|
||||
|
||||
-(void) insertGames:(NSArray<NSURL *> *)games {
|
||||
for (NSURL *url in games) {
|
||||
EmulationSession::GetInstance().ConfigureFilesystemProvider([url.path UTF8String]);
|
||||
}
|
||||
}
|
||||
|
||||
-(void) step {
|
||||
void(EmulationSession::GetInstance().System().Run());
|
||||
}
|
||||
|
||||
-(void) touchBeganAtPoint:(CGPoint)point index:(NSUInteger)index {
|
||||
float h_ratio, w_ratio;
|
||||
h_ratio = EmulationSession::GetInstance().Window().GetFramebufferLayout().height / (_size.height * [[UIScreen mainScreen] nativeScale]);
|
||||
w_ratio = EmulationSession::GetInstance().Window().GetFramebufferLayout().width / (_size.width * [[UIScreen mainScreen] nativeScale]);
|
||||
|
||||
EmulationSession::GetInstance().Window().OnTouchPressed([[NSNumber numberWithUnsignedInteger:index] intValue],
|
||||
(point.x) * [[UIScreen mainScreen] nativeScale] * w_ratio,
|
||||
((point.y) * [[UIScreen mainScreen] nativeScale] * h_ratio));
|
||||
}
|
||||
|
||||
-(void) touchEndedForIndex:(NSUInteger)index {
|
||||
EmulationSession::GetInstance().Window().OnTouchReleased([[NSNumber numberWithUnsignedInteger:index] intValue]);
|
||||
}
|
||||
|
||||
-(void) touchMovedAtPoint:(CGPoint)point index:(NSUInteger)index {
|
||||
float h_ratio, w_ratio;
|
||||
h_ratio = EmulationSession::GetInstance().Window().GetFramebufferLayout().height / (_size.height * [[UIScreen mainScreen] nativeScale]);
|
||||
w_ratio = EmulationSession::GetInstance().Window().GetFramebufferLayout().width / (_size.width * [[UIScreen mainScreen] nativeScale]);
|
||||
|
||||
EmulationSession::GetInstance().Window().OnTouchMoved([[NSNumber numberWithUnsignedInteger:index] intValue],
|
||||
(point.x) * [[UIScreen mainScreen] nativeScale] * w_ratio,
|
||||
((point.y) * [[UIScreen mainScreen] nativeScale] * h_ratio));
|
||||
}
|
||||
|
||||
-(void) thumbstickMoved:(VirtualControllerAnalogType)analog
|
||||
x:(CGFloat)x
|
||||
y:(CGFloat)y
|
||||
controllerId:(int)controllerId {
|
||||
EmulationSession::GetInstance().OnGamepadConnectEvent(controllerId);
|
||||
EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(controllerId, [[NSNumber numberWithUnsignedInteger:analog] intValue], CGFloat(x), CGFloat(y));
|
||||
}
|
||||
|
||||
-(void) virtualControllerButtonDown:(VirtualControllerButtonType)button
|
||||
controllerId:(int)controllerId {
|
||||
EmulationSession::GetInstance().OnGamepadConnectEvent(controllerId);
|
||||
EmulationSession::GetInstance().Window().OnGamepadButtonEvent(controllerId, [[NSNumber numberWithUnsignedInteger:button] intValue], true);
|
||||
}
|
||||
|
||||
-(void) virtualControllerGyro:(int)controllerId
|
||||
deltaTimestamp:(int)delta_timestamp
|
||||
gyroX:(float)gyro_x
|
||||
gyroY:(float)gyro_y
|
||||
gyroZ:(float)gyro_z
|
||||
accelX:(float)accel_x
|
||||
accelY:(float)accel_y
|
||||
accelZ:(float)accel_z
|
||||
{
|
||||
EmulationSession::GetInstance().OnGamepadConnectEvent(controllerId);
|
||||
EmulationSession::GetInstance().Window().OnGamepadMotionEvent(controllerId, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
|
||||
}
|
||||
|
||||
|
||||
-(void) virtualControllerButtonUp:(VirtualControllerButtonType)button
|
||||
controllerId:(int)controllerId {
|
||||
EmulationSession::GetInstance().OnGamepadConnectEvent(controllerId);
|
||||
EmulationSession::GetInstance().Window().OnGamepadButtonEvent(controllerId, [[NSNumber numberWithUnsignedInteger:button] intValue], false);
|
||||
}
|
||||
|
||||
|
||||
-(void) orientationChanged:(UIInterfaceOrientation)orientation with:(CAMetalLayer *)layer size:(CGSize)size {
|
||||
_layer = layer;
|
||||
_size = size;
|
||||
EmulationSession::GetInstance().Window().OnSurfaceChanged((__bridge CA::MetalLayer*)layer, size);
|
||||
}
|
||||
|
||||
-(void) settingsChanged {
|
||||
Config{"config", Config::ConfigType::GlobalConfig};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
29
src/ios/CMakeLists.txt
Normal file
29
src/ios/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
enable_language(Swift OBJCXX)
|
||||
|
||||
add_executable(eden-ios
|
||||
AppUI-Bridging-Header.h
|
||||
AppUI.swift
|
||||
AppUIGameInformation.h
|
||||
AppUIGameInformation.mm
|
||||
AppUIObjC.h
|
||||
AppUIObjC.mm
|
||||
Config.h
|
||||
Config.mm
|
||||
EmulationSession.h
|
||||
EmulationSession.mm
|
||||
EmulationWindow.h
|
||||
EmulationWindow.mm
|
||||
)
|
||||
|
||||
target_link_libraries(eden-ios PRIVATE common core input_common frontend_common video_core glad)
|
||||
target_link_libraries(eden-ios PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||
target_link_libraries(eden-ios PRIVATE SDL2::SDL2)
|
||||
create_target_directory_groups(eden-ios)
|
||||
target_compile_options(eden-ios PRIVATE
|
||||
-Wno-conversion
|
||||
-Wno-unused-variable
|
||||
-Wno-unused-parameter
|
||||
-Wno-missing-field-initializers)
|
||||
19
src/ios/Config.h
Normal file
19
src/ios/Config.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/settings_common.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings_setting.h"
|
||||
#include "common/settings_enums.h"
|
||||
|
||||
namespace IOSSettings {
|
||||
struct Values {
|
||||
Settings::Linkage linkage;
|
||||
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
|
||||
};
|
||||
|
||||
extern Values values;
|
||||
|
||||
} // namespace IOSSettings
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue