Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ae680fc96 | |||
| 792ea02969 |
@@ -13,7 +13,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Find Unused Strings
|
||||
run: ./tools/unused-strings.sh
|
||||
run: ./tools/find-unused-strings.sh
|
||||
|
||||
- name: Find Stale Translations
|
||||
run: ./tools/stale-translations.sh
|
||||
|
||||
@@ -13,7 +13,7 @@ index 50f2a29..c60d9dc 100644
|
||||
#define MBEDTLS_HAVE_NEON_INTRINSICS
|
||||
-#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
|
||||
-#include <arm64_neon.h>
|
||||
+#elif (defined(__ANDROID__) && defined(__ARM_FP)) || defined(__ARM_NEON)
|
||||
+#elif defined(__ANDROID__) || defined(__ARM_NEON)
|
||||
+#include <arm_neon.h>
|
||||
#define MBEDTLS_HAVE_NEON_INTRINSICS
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 crueter
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
set(CPM_SOURCE_CACHE "${PROJECT_SOURCE_DIR}/.cache/cpm" CACHE STRING "" FORCE)
|
||||
|
||||
if(MSVC OR ANDROID)
|
||||
if (MSVC OR ANDROID)
|
||||
set(BUNDLED_DEFAULT ON)
|
||||
else()
|
||||
set(BUNDLED_DEFAULT OFF)
|
||||
@@ -21,7 +19,7 @@ include(CPM)
|
||||
# cpmfile parsing
|
||||
set(CPMUTIL_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cpmfile.json")
|
||||
|
||||
if(EXISTS ${CPMUTIL_JSON_FILE})
|
||||
if (EXISTS ${CPMUTIL_JSON_FILE})
|
||||
file(READ ${CPMUTIL_JSON_FILE} CPMFILE_CONTENT)
|
||||
else()
|
||||
message(WARNING "[CPMUtil] cpmfile ${CPMUTIL_JSON_FILE} does not exist, AddJsonPackage will be a no-op")
|
||||
@@ -47,14 +45,14 @@ endfunction()
|
||||
function(get_json_element object out member default)
|
||||
string(JSON out_type ERROR_VARIABLE err TYPE "${object}" ${member})
|
||||
|
||||
if(err)
|
||||
if (err)
|
||||
set("${out}" "${default}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
string(JSON outvar GET "${object}" ${member})
|
||||
|
||||
if(out_type STREQUAL "ARRAY")
|
||||
if (out_type STREQUAL "ARRAY")
|
||||
string(JSON _len LENGTH "${object}" ${member})
|
||||
# array_to_list("${outvar}" ${_len} outvar)
|
||||
set("${out}_LENGTH" "${_len}" PARENT_SCOPE)
|
||||
@@ -76,7 +74,7 @@ function(AddJsonPackage)
|
||||
set(multiValueArgs OPTIONS)
|
||||
|
||||
cmake_parse_arguments(JSON "" "${oneValueArgs}" "${multiValueArgs}"
|
||||
"${ARGN}")
|
||||
"${ARGN}")
|
||||
|
||||
list(LENGTH ARGN argnLength)
|
||||
|
||||
@@ -85,18 +83,18 @@ function(AddJsonPackage)
|
||||
set(JSON_NAME "${ARGV0}")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CPMFILE_CONTENT)
|
||||
if (NOT DEFINED CPMFILE_CONTENT)
|
||||
cpm_utils_message(WARNING ${name} "No cpmfile, AddJsonPackage is a no-op")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED JSON_NAME)
|
||||
if (NOT DEFINED JSON_NAME)
|
||||
cpm_utils_message(FATAL_ERROR "json package" "No name specified")
|
||||
endif()
|
||||
|
||||
string(JSON object ERROR_VARIABLE err GET "${CPMFILE_CONTENT}" "${JSON_NAME}")
|
||||
|
||||
if(err)
|
||||
if (err)
|
||||
cpm_utils_message(FATAL_ERROR ${JSON_NAME} "Not found in cpmfile")
|
||||
endif()
|
||||
|
||||
@@ -105,13 +103,13 @@ function(AddJsonPackage)
|
||||
get_json_element("${object}" ci ci OFF)
|
||||
get_json_element("${object}" version version "")
|
||||
|
||||
if(ci)
|
||||
if (ci)
|
||||
get_json_element("${object}" name name "${JSON_NAME}")
|
||||
get_json_element("${object}" extension extension "tar.zst")
|
||||
get_json_element("${object}" min_version min_version "")
|
||||
get_json_element("${object}" raw_disabled disabled_platforms "")
|
||||
|
||||
if(raw_disabled)
|
||||
if (raw_disabled)
|
||||
array_to_list("${raw_disabled}" ${raw_disabled_LENGTH} disabled_platforms)
|
||||
else()
|
||||
set(disabled_platforms "")
|
||||
@@ -156,31 +154,31 @@ function(AddJsonPackage)
|
||||
# first: tag gets %VERSION% replaced if applicable, with either git_version (preferred) or version
|
||||
# second: artifact gets %VERSION% and %TAG% replaced accordingly (same rules for VERSION)
|
||||
|
||||
if(git_version)
|
||||
if (git_version)
|
||||
set(version_replace ${git_version})
|
||||
else()
|
||||
set(version_replace ${version})
|
||||
endif()
|
||||
|
||||
# TODO(crueter): fmt module for cmake
|
||||
if(tag)
|
||||
if (tag)
|
||||
string(REPLACE "%VERSION%" "${version_replace}" tag ${tag})
|
||||
endif()
|
||||
|
||||
if(artifact)
|
||||
if (artifact)
|
||||
string(REPLACE "%VERSION%" "${version_replace}" artifact ${artifact})
|
||||
string(REPLACE "%TAG%" "${tag}" artifact ${artifact})
|
||||
endif()
|
||||
|
||||
# format patchdir
|
||||
if(raw_patches)
|
||||
if (raw_patches)
|
||||
math(EXPR range "${raw_patches_LENGTH} - 1")
|
||||
|
||||
foreach(IDX RANGE ${range})
|
||||
string(JSON _patch GET "${raw_patches}" "${IDX}")
|
||||
|
||||
set(full_patch "${CMAKE_SOURCE_DIR}/.patch/${JSON_NAME}/${_patch}")
|
||||
if(NOT EXISTS ${full_patch})
|
||||
if (NOT EXISTS ${full_patch})
|
||||
cpm_utils_message(FATAL_ERROR ${JSON_NAME} "specifies patch ${full_patch} which does not exist")
|
||||
endif()
|
||||
|
||||
@@ -192,7 +190,7 @@ function(AddJsonPackage)
|
||||
# options
|
||||
get_json_element("${object}" raw_options options "")
|
||||
|
||||
if(raw_options)
|
||||
if (raw_options)
|
||||
array_to_list("${raw_options}" ${raw_options_LENGTH} options)
|
||||
endif()
|
||||
|
||||
@@ -200,7 +198,7 @@ function(AddJsonPackage)
|
||||
# end options
|
||||
|
||||
# system/bundled
|
||||
if(bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
|
||||
if (bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
|
||||
set(bundled ${JSON_BUNDLED_PACKAGE})
|
||||
endif()
|
||||
|
||||
@@ -286,37 +284,37 @@ function(AddPackage)
|
||||
set(multiValueArgs OPTIONS PATCHES)
|
||||
|
||||
cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "${multiValueArgs}"
|
||||
"${ARGN}")
|
||||
"${ARGN}")
|
||||
|
||||
if(NOT DEFINED PKG_ARGS_NAME)
|
||||
if (NOT DEFINED PKG_ARGS_NAME)
|
||||
cpm_utils_message(FATAL_ERROR "package" "No package name defined")
|
||||
endif()
|
||||
|
||||
option(${PKG_ARGS_NAME}_FORCE_SYSTEM "Force the system package for ${PKG_ARGS_NAME}")
|
||||
option(${PKG_ARGS_NAME}_FORCE_BUNDLED "Force the bundled package for ${PKG_ARGS_NAME}")
|
||||
|
||||
if(NOT DEFINED PKG_ARGS_GIT_HOST)
|
||||
if (NOT DEFINED PKG_ARGS_GIT_HOST)
|
||||
set(git_host github.com)
|
||||
else()
|
||||
set(git_host ${PKG_ARGS_GIT_HOST})
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_URL)
|
||||
if (DEFINED PKG_ARGS_URL)
|
||||
set(pkg_url ${PKG_ARGS_URL})
|
||||
|
||||
if(DEFINED PKG_ARGS_REPO)
|
||||
if (DEFINED PKG_ARGS_REPO)
|
||||
set(pkg_git_url https://${git_host}/${PKG_ARGS_REPO})
|
||||
else()
|
||||
if(DEFINED PKG_ARGS_GIT_URL)
|
||||
if (DEFINED PKG_ARGS_GIT_URL)
|
||||
set(pkg_git_url ${PKG_ARGS_GIT_URL})
|
||||
else()
|
||||
set(pkg_git_url ${pkg_url})
|
||||
endif()
|
||||
endif()
|
||||
elseif(DEFINED PKG_ARGS_REPO)
|
||||
elseif (DEFINED PKG_ARGS_REPO)
|
||||
set(pkg_git_url https://${git_host}/${PKG_ARGS_REPO})
|
||||
|
||||
if(DEFINED PKG_ARGS_TAG)
|
||||
if (DEFINED PKG_ARGS_TAG)
|
||||
set(pkg_key ${PKG_ARGS_TAG})
|
||||
|
||||
if(DEFINED PKG_ARGS_ARTIFACT)
|
||||
@@ -326,14 +324,14 @@ function(AddPackage)
|
||||
set(pkg_url
|
||||
${pkg_git_url}/archive/refs/tags/${PKG_ARGS_TAG}.tar.gz)
|
||||
endif()
|
||||
elseif(DEFINED PKG_ARGS_SHA)
|
||||
elseif (DEFINED PKG_ARGS_SHA)
|
||||
set(pkg_url "${pkg_git_url}/archive/${PKG_ARGS_SHA}.tar.gz")
|
||||
else()
|
||||
if(DEFINED PKG_ARGS_BRANCH)
|
||||
if (DEFINED PKG_ARGS_BRANCH)
|
||||
set(PKG_BRANCH ${PKG_ARGS_BRANCH})
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"REPO defined but no TAG, SHA, BRANCH, or URL specified, defaulting to master")
|
||||
"REPO defined but no TAG, SHA, BRANCH, or URL specified, defaulting to master")
|
||||
set(PKG_BRANCH master)
|
||||
endif()
|
||||
|
||||
@@ -345,72 +343,72 @@ function(AddPackage)
|
||||
|
||||
cpm_utils_message(STATUS ${PKG_ARGS_NAME} "Download URL is ${pkg_url}")
|
||||
|
||||
if(NOT DEFINED PKG_ARGS_KEY)
|
||||
if(DEFINED PKG_ARGS_SHA)
|
||||
if (NOT DEFINED PKG_ARGS_KEY)
|
||||
if (DEFINED PKG_ARGS_SHA)
|
||||
string(SUBSTRING ${PKG_ARGS_SHA} 0 4 pkg_key)
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
|
||||
"No custom key defined, using ${pkg_key} from sha")
|
||||
"No custom key defined, using ${pkg_key} from sha")
|
||||
elseif(DEFINED PKG_ARGS_GIT_VERSION)
|
||||
set(pkg_key ${PKG_ARGS_GIT_VERSION})
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
elseif(DEFINED PKG_ARGS_TAG)
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
elseif (DEFINED PKG_ARGS_TAG)
|
||||
set(pkg_key ${PKG_ARGS_TAG})
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
elseif(DEFINED PKG_ARGS_VERSION)
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
elseif (DEFINED PKG_ARGS_VERSION)
|
||||
set(pkg_key ${PKG_ARGS_VERSION})
|
||||
cpm_utils_message(DEBUG ${PKG_ARGS_NAME}
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
"No custom key defined, using ${pkg_key}")
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"Could not determine cache key, using CPM defaults")
|
||||
"Could not determine cache key, using CPM defaults")
|
||||
endif()
|
||||
else()
|
||||
set(pkg_key ${PKG_ARGS_KEY})
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_HASH_ALGO)
|
||||
if (DEFINED PKG_ARGS_HASH_ALGO)
|
||||
set(hash_algo ${PKG_ARGS_HASH_ALGO})
|
||||
else()
|
||||
set(hash_algo SHA512)
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_HASH)
|
||||
if (DEFINED PKG_ARGS_HASH)
|
||||
set(pkg_hash "${hash_algo}=${PKG_ARGS_HASH}")
|
||||
elseif(DEFINED PKG_ARGS_HASH_SUFFIX)
|
||||
elseif (DEFINED PKG_ARGS_HASH_SUFFIX)
|
||||
# funny sanity check
|
||||
string(TOLOWER ${hash_algo} hash_algo_lower)
|
||||
string(TOLOWER ${PKG_ARGS_HASH_SUFFIX} suffix_lower)
|
||||
if(NOT ${suffix_lower} MATCHES ${hash_algo_lower})
|
||||
if (NOT ${suffix_lower} MATCHES ${hash_algo_lower})
|
||||
cpm_utils_message(WARNING
|
||||
"Hash algorithm and hash suffix do not match, errors may occur")
|
||||
"Hash algorithm and hash suffix do not match, errors may occur")
|
||||
endif()
|
||||
|
||||
set(hash_url ${pkg_url}.${PKG_ARGS_HASH_SUFFIX})
|
||||
elseif(DEFINED PKG_ARGS_HASH_URL)
|
||||
elseif (DEFINED PKG_ARGS_HASH_URL)
|
||||
set(hash_url ${PKG_ARGS_HASH_URL})
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"No hash or hash URL found")
|
||||
"No hash or hash URL found")
|
||||
endif()
|
||||
|
||||
if(DEFINED hash_url)
|
||||
if (DEFINED hash_url)
|
||||
set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${PKG_ARGS_NAME}.hash)
|
||||
|
||||
# TODO(crueter): This is kind of a bad solution
|
||||
# because "technically" the hash is invalidated each week
|
||||
# but it works for now kjsdnfkjdnfjksdn
|
||||
string(TOLOWER ${PKG_ARGS_NAME} lowername)
|
||||
if(NOT EXISTS ${outfile} AND NOT EXISTS ${CPM_SOURCE_CACHE}/${lowername}/${pkg_key})
|
||||
if (NOT EXISTS ${outfile} AND NOT EXISTS ${CPM_SOURCE_CACHE}/${lowername}/${pkg_key})
|
||||
file(DOWNLOAD ${hash_url} ${outfile})
|
||||
endif()
|
||||
|
||||
if(EXISTS ${outfile})
|
||||
if (EXISTS ${outfile})
|
||||
file(READ ${outfile} pkg_hash_tmp)
|
||||
endif()
|
||||
|
||||
if(DEFINED ${pkg_hash_tmp})
|
||||
if (DEFINED ${pkg_hash_tmp})
|
||||
set(pkg_hash "${hash_algo}=${pkg_hash_tmp}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -428,19 +426,19 @@ function(AddPackage)
|
||||
- CPMUTIL_FORCE_BUNDLED
|
||||
- BUNDLED_PACKAGE
|
||||
- default to allow local
|
||||
]] #
|
||||
if(PKG_ARGS_FORCE_BUNDLED_PACKAGE)
|
||||
]]#
|
||||
if (PKG_ARGS_FORCE_BUNDLED_PACKAGE)
|
||||
set_precedence(OFF OFF)
|
||||
elseif(${PKG_ARGS_NAME}_FORCE_SYSTEM)
|
||||
elseif (${PKG_ARGS_NAME}_FORCE_SYSTEM)
|
||||
set_precedence(ON ON)
|
||||
elseif(${PKG_ARGS_NAME}_FORCE_BUNDLED)
|
||||
elseif (${PKG_ARGS_NAME}_FORCE_BUNDLED)
|
||||
set_precedence(OFF OFF)
|
||||
elseif(CPMUTIL_FORCE_SYSTEM)
|
||||
elseif (CPMUTIL_FORCE_SYSTEM)
|
||||
set_precedence(ON ON)
|
||||
elseif(CPMUTIL_FORCE_BUNDLED)
|
||||
set_precedence(OFF OFF)
|
||||
elseif(DEFINED PKG_ARGS_BUNDLED_PACKAGE AND NOT PKG_ARGS_BUNDLED_PACKAGE STREQUAL "unset")
|
||||
if(PKG_ARGS_BUNDLED_PACKAGE)
|
||||
elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE AND NOT PKG_ARGS_BUNDLED_PACKAGE STREQUAL "unset")
|
||||
if (PKG_ARGS_BUNDLED_PACKAGE)
|
||||
set(local OFF)
|
||||
else()
|
||||
set(local ON)
|
||||
@@ -451,7 +449,7 @@ function(AddPackage)
|
||||
set_precedence(ON OFF)
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_VERSION)
|
||||
if (DEFINED PKG_ARGS_VERSION)
|
||||
list(APPEND EXTRA_ARGS
|
||||
VERSION ${PKG_ARGS_VERSION}
|
||||
)
|
||||
@@ -477,32 +475,32 @@ function(AddPackage)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES ${PKG_ARGS_NAME})
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS ${pkg_git_url})
|
||||
|
||||
if(${PKG_ARGS_NAME}_ADDED)
|
||||
if(DEFINED PKG_ARGS_SHA)
|
||||
if (${PKG_ARGS_NAME}_ADDED)
|
||||
if (DEFINED PKG_ARGS_SHA)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_SHA})
|
||||
elseif(DEFINED PKG_ARGS_GIT_VERSION)
|
||||
${PKG_ARGS_SHA})
|
||||
elseif (DEFINED PKG_ARGS_GIT_VERSION)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_GIT_VERSION})
|
||||
elseif (DEFINED PKG_ARGS_TAG)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_GIT_VERSION})
|
||||
elseif(DEFINED PKG_ARGS_TAG)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_TAG})
|
||||
elseif(DEFINED PKG_ARGS_VERSION)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_VERSION})
|
||||
${PKG_ARGS_TAG})
|
||||
elseif(DEFINED PKG_ARGS_VERSION)
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
${PKG_ARGS_VERSION})
|
||||
else()
|
||||
cpm_utils_message(WARNING ${PKG_ARGS_NAME}
|
||||
"Package has no specified sha, tag, or version")
|
||||
"Package has no specified sha, tag, or version")
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS "unknown")
|
||||
endif()
|
||||
else()
|
||||
if(DEFINED CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION AND NOT
|
||||
if (DEFINED CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION AND NOT
|
||||
"${CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION}" STREQUAL "")
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
"${CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION} (system)")
|
||||
"${CPM_PACKAGE_${PKG_ARGS_NAME}_VERSION} (system)")
|
||||
else()
|
||||
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_SHAS
|
||||
"unknown (system)")
|
||||
"unknown (system)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -563,7 +561,7 @@ function(AddCIPackage)
|
||||
message(FATAL_ERROR "[CPMUtil] PACKAGE is required")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED PKG_ARGS_CMAKE_FILENAME)
|
||||
if (NOT DEFINED PKG_ARGS_CMAKE_FILENAME)
|
||||
set(ARTIFACT_CMAKE ${PKG_ARGS_NAME})
|
||||
else()
|
||||
set(ARTIFACT_CMAKE ${PKG_ARGS_CMAKE_FILENAME})
|
||||
@@ -575,11 +573,11 @@ function(AddCIPackage)
|
||||
set(ARTIFACT_EXT ${PKG_ARGS_EXTENSION})
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_MIN_VERSION)
|
||||
if (DEFINED PKG_ARGS_MIN_VERSION)
|
||||
set(ARTIFACT_MIN_VERSION ${PKG_ARGS_MIN_VERSION})
|
||||
endif()
|
||||
|
||||
if(DEFINED PKG_ARGS_DISABLED_PLATFORMS)
|
||||
if (DEFINED PKG_ARGS_DISABLED_PLATFORMS)
|
||||
set(DISABLED_PLATFORMS ${PKG_ARGS_DISABLED_PLATFORMS})
|
||||
endif()
|
||||
|
||||
@@ -589,19 +587,19 @@ function(AddCIPackage)
|
||||
set(ARTIFACT_REPO ${PKG_ARGS_REPO})
|
||||
set(ARTIFACT_PACKAGE ${PKG_ARGS_PACKAGE})
|
||||
|
||||
if((MSVC AND ARCHITECTURE_x86_64) AND NOT "windows-amd64" IN_LIST DISABLED_PLATFORMS)
|
||||
if ((MSVC AND ARCHITECTURE_x86_64) AND NOT "windows-amd64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(windows-amd64)
|
||||
endif()
|
||||
|
||||
if((MSVC AND ARCHITECTURE_arm64) AND NOT "windows-arm64" IN_LIST DISABLED_PLATFORMS)
|
||||
if ((MSVC AND ARCHITECTURE_arm64) AND NOT "windows-arm64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(windows-arm64)
|
||||
endif()
|
||||
|
||||
if((MINGW AND ARCHITECTURE_x86_64) AND NOT "mingw-amd64" IN_LIST DISABLED_PLATFORMS)
|
||||
if ((MINGW AND ARCHITECTURE_x86_64) AND NOT "mingw-amd64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(mingw-amd64)
|
||||
endif()
|
||||
|
||||
if((MINGW AND ARCHITECTURE_arm64) AND NOT "mingw-arm64" IN_LIST DISABLED_PLATFORMS)
|
||||
if ((MINGW AND ARCHITECTURE_arm64) AND NOT "mingw-arm64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(mingw-arm64)
|
||||
endif()
|
||||
|
||||
@@ -630,11 +628,11 @@ function(AddCIPackage)
|
||||
endif()
|
||||
|
||||
# TODO(crueter): macOS amd64/aarch64 split mayhaps
|
||||
if(APPLE AND NOT "macos-universal" IN_LIST DISABLED_PLATFORMS)
|
||||
if (APPLE AND NOT "macos-universal" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(macos-universal)
|
||||
endif()
|
||||
|
||||
if(DEFINED ARTIFACT_DIR)
|
||||
if (DEFINED ARTIFACT_DIR)
|
||||
set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE)
|
||||
set(${ARTIFACT_PACKAGE}_SOURCE_DIR "${ARTIFACT_DIR}" PARENT_SCOPE)
|
||||
else()
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
<h4 align="center"><b>Eden</b> is a free and opensource (FOSS) Switch 1 emulator, derived from Yuzu and Sudachi - started by developer Camille LaVey.
|
||||
It's written in C++ with portability in mind, with builds for Windows, Linux, macOS, Android, FreeBSD and more.
|
||||
<h4 align="center"><b>Eden</b> is an open-source Nintendo Switch emulator, forked from the Yuzu emulator — started by former Citron developer Camille LaVey and the Eden team.
|
||||
It is written in C++ with portability in mind, and we actively maintain builds for Windows, Linux and Android.
|
||||
</h4>
|
||||
|
||||
<p align="center">
|
||||
|
||||
@@ -9,7 +9,7 @@ Version=1.0
|
||||
Type=Application
|
||||
Name=Eden
|
||||
GenericName=Switch Emulator
|
||||
Comment=Multiplatform FOSS Switch 1 emulator written in C++, derived from Yuzu and Sudachi
|
||||
Comment=Nintendo Switch video game console emulator
|
||||
Icon=dev.eden_emu.eden
|
||||
TryExec=eden
|
||||
Exec=eden %f
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
-->
|
||||
|
||||
<component type="desktop-application">
|
||||
<id>org.eden_emu.eden</id>
|
||||
<id>org.yuzu_emu.yuzu</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<name>eden</name>
|
||||
<name>yuzu</name>
|
||||
<summary>Nintendo Switch emulator</summary>
|
||||
<description>
|
||||
<p>Multiplatform FOSS Switch 1 emulator written in C++, derived from Yuzu and Sudachi</p>
|
||||
<p>yuzu is the world's most popular, open-source, Nintendo Switch emulator — started by the creators of Citra.</p>
|
||||
<p>The emulator is capable of running most commercial games at full speed, provided you meet the necessary hardware requirements.</p>
|
||||
<p>For a full list of games yuzu support, please visit our Compatibility page.</p>
|
||||
<p>Check out our website for the latest news on exciting features, monthly progress reports, and more!</p>
|
||||
</description>
|
||||
<categories>
|
||||
<category>Game</category>
|
||||
@@ -26,16 +24,16 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<keyword>switch</keyword>
|
||||
<keyword>emulator</keyword>
|
||||
</keywords>
|
||||
<url type="homepage">https://eden-emu.dev/</url>
|
||||
<url type="bugtracker">https://git.eden-emu.dev/eden-emu/eden/issues</url>
|
||||
<url type="faq">https://eden-emu.dev/docs</url>
|
||||
<url type="help">https://eden-emu.dev/docs</url>
|
||||
<url type="donation">https://eden-emu.dev/donations</url>
|
||||
<url type="translate">https://explore.transifex.com/edenemu/eden-emulator</url>
|
||||
<url type="contact">https://discord.gg/edenemu</url>
|
||||
<url type="vcs-browser">https://git.eden-emu.dev</url>
|
||||
<url type="contribute">https://git.eden-emu.dev/eden-emu/eden</url>
|
||||
<launchable type="desktop-id">org.eden_emu.eden.desktop</launchable>
|
||||
<url type="homepage">https://yuzu-emu.org/</url>
|
||||
<url type="bugtracker">https://github.com/yuzu-emu/yuzu/issues</url>
|
||||
<url type="faq">https://yuzu-emu.org/wiki/faq/</url>
|
||||
<url type="help">https://yuzu-emu.org/wiki/home/</url>
|
||||
<url type="donation">https://yuzu-emu.org/donate/</url>
|
||||
<url type="translate">https://www.transifex.com/projects/p/yuzu</url>
|
||||
<url type="contact">https://community.citra-emu.org/</url>
|
||||
<url type="vcs-browser">https://github.com/yuzu-emu/yuzu</url>
|
||||
<url type="contribute">https://yuzu-emu.org/wiki/contributing/</url>
|
||||
<launchable type="desktop-id">org.yuzu_emu.yuzu.desktop</launchable>
|
||||
<provides>
|
||||
<binary>yuzu</binary>
|
||||
<binary>yuzu-cmd</binary>
|
||||
@@ -52,6 +50,13 @@ SPDX-License-Identifier: CC0-1.0
|
||||
<memory>16384</memory>
|
||||
</recommends>
|
||||
<project_license>GPL-3.0-or-later</project_license>
|
||||
<developer_name>Eden Emulator Team</developer_name>
|
||||
<developer_name>yuzu Emulator Team</developer_name>
|
||||
<content_rating type="oars-1.0"/>
|
||||
<screenshots>
|
||||
<screenshot type="default"><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/001-Super%20Mario%20Odyssey%20.png</image></screenshot>
|
||||
<screenshot><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/004-The%20Legend%20of%20Zelda%20Skyward%20Sword%20HD.png</image></screenshot>
|
||||
<screenshot><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/007-Pokemon%20Sword.png</image></screenshot>
|
||||
<screenshot><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/010-Hyrule%20Warriors%20Age%20of%20Calamity.png</image></screenshot>
|
||||
<screenshot><image>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/039-Pok%C3%A9mon%20Mystery%20Dungeon%20Rescue%20Team%20DX.png.png.png</image></screenshot>
|
||||
</screenshots>
|
||||
</component>
|
||||
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 345 KiB After Width: | Height: | Size: 346 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
@@ -0,0 +1,17 @@
|
||||
# AddPackage
|
||||
|
||||
- `VERSION` (required): The version to get (the tag will be `v${VERSION}`)
|
||||
- `NAME` (required): Name used within the artifacts
|
||||
- `REPO` (required): CI repository, e.g. `crueter-ci/OpenSSL`
|
||||
- `PACKAGE` (required): `find_package` package name
|
||||
- `EXTENSION`: Artifact extension (default `tar.zst`)
|
||||
- `MIN_VERSION`: Minimum version for `find_package`. Only used if platform does not support this package as a bundled artifact
|
||||
- `DISABLED_PLATFORMS`: List of platforms that lack artifacts for this package. Options:
|
||||
* `windows-amd64`
|
||||
* `windows-arm64`
|
||||
* `android`
|
||||
* `solaris-amd64`
|
||||
* `freebsd-amd64`
|
||||
* `linux-amd64`
|
||||
* `linux-aarch64`
|
||||
* `macos-universal`
|
||||
@@ -10,13 +10,12 @@ Global Options:
|
||||
|
||||
You are highly encouraged to read AddPackage first, even if you plan to only interact with CPMUtil via `AddJsonPackage`.
|
||||
|
||||
<!-- TOC -->
|
||||
- [AddPackage](#addpackage)
|
||||
- [AddCIPackage](#addcipackage)
|
||||
- [AddJsonPackage](#addjsonpackage)
|
||||
- [Lists](#lists)
|
||||
- [For Packagers](#for-packagers)
|
||||
- [Network Sandbox](#network-sandbox)
|
||||
- [Unsandboxed](#unsandboxed)
|
||||
<!-- /TOC -->
|
||||
|
||||
## AddPackage
|
||||
|
||||
@@ -44,16 +43,4 @@ For an example of how this might be implemented in an application, see Eden's im
|
||||
|
||||
- [`dep_hashes.h.in`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/dep_hashes.h.in)
|
||||
- [`GenerateDepHashes.cmake`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CMakeModules/GenerateDepHashes.cmake)
|
||||
- [`deps_dialog.cpp`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/yuzu/deps_dialog.cpp)
|
||||
|
||||
## For Packagers
|
||||
|
||||
If you are packaging a project that uses CPMUtil, read this!
|
||||
|
||||
### Network Sandbox
|
||||
|
||||
For sandboxed environments (e.g. Gentoo, nixOS) you must install all dependencies to the system beforehand and set `-DCPMUTIL_FORCE_SYSTEM=ON`. If a dependency is missing, get creating!
|
||||
|
||||
### Unsandboxed
|
||||
|
||||
For others (AUR, MPR, etc). CPMUtil will handle everything for you, including if some of the project's dependencies are missing from your distribution's repositories. That is pretty much half the reason I created this behemoth, after all.
|
||||
- [`deps_dialog.cpp`](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/src/yuzu/deps_dialog.cpp)
|
||||
@@ -1,20 +1,17 @@
|
||||
# Caveats
|
||||
|
||||
<!-- TOC -->
|
||||
- [Arch Linux](#arch-linux)
|
||||
- [Gentoo Linux](#gentoo-linux)
|
||||
- [macOS](#macos)
|
||||
- [Solaris](#solaris)
|
||||
- [HaikuOS](#haikuos)
|
||||
- [OpenBSD](#openbsd)
|
||||
- [FreeBSD](#freebsd)
|
||||
- [NetBSD](#netbsd)
|
||||
- [MSYS2](#msys2)
|
||||
- [RedoxOS](#redoxos)
|
||||
- [Windows](#windows)
|
||||
- [Windows 7, Windows 8 and Windows 8.1](#windows-7-windows-8-and-windows-81)
|
||||
- [Windows Vista and below](#windows-vista-and-below)
|
||||
- [Windows on ARM](#windows-on-arm)
|
||||
- [Caveats](#caveats)
|
||||
- [Arch Linux](#arch-linux)
|
||||
- [Gentoo Linux](#gentoo-linux)
|
||||
- [macOS](#macos)
|
||||
- [Solaris](#solaris)
|
||||
- [HaikuOS](#haikuos)
|
||||
- [OpenBSD](#openbsd)
|
||||
- [FreeBSD](#freebsd)
|
||||
- [NetBSD](#netbsd)
|
||||
- [MSYS2](#msys2)
|
||||
- [Windows 8.1 and below](#windows-81-and-below)
|
||||
<!-- /TOC -->
|
||||
|
||||
## Arch Linux
|
||||
@@ -52,7 +49,6 @@ export PATH="$PATH:$PWD"
|
||||
```
|
||||
|
||||
Default MESA is a bit outdated, the following environment variables should be set for a smoother experience:
|
||||
|
||||
```sh
|
||||
export MESA_GL_VERSION_OVERRIDE=4.6
|
||||
export MESA_GLSL_VERSION_OVERRIDE=460
|
||||
@@ -97,16 +93,9 @@ Eden is not currently available as a port on FreeBSD, though it is in the works.
|
||||
|
||||
The available OpenSSL port (3.0.17) is out-of-date, and using a bundled static library instead is recommended; to do so, add `-DYUZU_USE_BUNDLED_OPENSSL=ON` to your CMake configure command.
|
||||
|
||||
Gamepad/controllers may not work on 15.0, this is due to an outdated SDL not responding well to the new `usbhid(2)` driver. To workaround this simply disable `usbhid(2)` (add the following to `/boot/loader.conf`):
|
||||
|
||||
```sh
|
||||
hw.usb.usbhid.enable="0"
|
||||
```
|
||||
|
||||
## NetBSD
|
||||
|
||||
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`:
|
||||
|
||||
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/x86_64/10.0_2025Q3/All/"' >/etc/pkg_install.conf`. If `pkgin` is taking too much time consider adding the following to `/etc/rc.conf`:
|
||||
```sh
|
||||
ip6addrctl=YES
|
||||
ip6addrctl_policy=ipv4_prefer
|
||||
@@ -120,10 +109,9 @@ System provides a default `g++-10` which doesn't support the current C++ codebas
|
||||
|
||||
Make may error out when generating C++ headers of SPIRV shaders, hence it's recommended to use `gmake` over the default system one.
|
||||
|
||||
[parallel/spirv-tools](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/parallel/spirv-tools/index.html) isn't available in binary form and must be built from source.
|
||||
|
||||
glslang is not available on NetBSD, to circumvent this simply build glslang by yourself:
|
||||
[parallel/spirv-tools](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/parallel/spirv-tools/index.html) isn't available in binary form and must be build from source.
|
||||
|
||||
Such that glslang is not available on NetBSD, to circumvent this simply build glslang by yourself:
|
||||
```sh
|
||||
pkgin python313
|
||||
git clone --depth=1 https://github.com/KhronosGroup/glslang.git
|
||||
@@ -136,15 +124,13 @@ 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.
|
||||
|
||||
## DragonFlyBSD
|
||||
# DragonFlyBSD
|
||||
|
||||
If `libstdc++.so.6` is not found (`GLIBCXX_3.4.30`) then attempt:
|
||||
|
||||
```sh
|
||||
rm /usr/local/lib/gcc11/libstdc++.so.6
|
||||
ln -s /usr/local/lib/gcc14/libstdc++.so /usr/local/lib/gcc11/libstdc++.so.6
|
||||
```
|
||||
|
||||
This may have unforeseen consequences of which we don't need to worry about for now.
|
||||
|
||||
Default `g++` (and the libstdc++) is too outdated - so install `gcc14` and redirect CMake to the new compiler toolchain `-DCMAKE_CXX_COMPILER=gcc14 -DCMAKE_C_COMPILER=g++14`.
|
||||
@@ -155,9 +141,13 @@ If build hangs, use `hammer2 bulkfree`.
|
||||
|
||||
## MSYS2
|
||||
|
||||
Only the `MINGW64` environment is tested (or `CLANGARM64` on ARM); however, all of the others should work (in theory) sans `MINGW32`.
|
||||
`qt6-static` isn't supported yet.
|
||||
|
||||
When packaging an MSYS2 build that is NOT fully static, you will need to copy all dependent DLLs recursively alongside the `windeployqt6`; for example:
|
||||
Only the `MINGW64` environment is tested; however, all of the others should work (in theory) sans `MINGW32`.
|
||||
|
||||
Currently, only FFmpeg can be used as a system dependency; the others will result in linker errors.
|
||||
|
||||
When packaging an MSYS2 build, you will need to copy all dependent DLLs recursively alongside the `windeployqt6`; for example:
|
||||
|
||||
```sh
|
||||
# MSYS_TOOLCHAIN is typically just mingw64
|
||||
@@ -206,24 +196,14 @@ windeployqt6 --no-compiler-runtime --no-opengl-sw --no-system-dxc-compiler \
|
||||
find ./*/ -name "*.dll" | while read -r dll; do deps "$dll"; done
|
||||
```
|
||||
|
||||
## RedoxOS
|
||||
|
||||
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
|
||||
|
||||
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
||||
|
||||
## Windows
|
||||
|
||||
### Windows 7, Windows 8 and Windows 8.1
|
||||
## Windows 8.1 and below
|
||||
|
||||
DirectX 12 is not available - simply copy and paste a random DLL and name it `d3d12.dll`.
|
||||
|
||||
Install [Qt6 compatibility libraries](github.com/ANightly/qt6windows7) specifically Qt 6.9.5.
|
||||
|
||||
### Windows Vista and below
|
||||
## RedoxOS
|
||||
|
||||
No support for Windows Vista (or below) is present at the moment. Check back later.
|
||||
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
|
||||
|
||||
### Windows on ARM
|
||||
|
||||
If you're using Snapdragon X or 8CX, use the [the Vulkan translation layer](https://apps.microsoft.com/detail/9nqpsl29bfff?hl=en-us&gl=USE) only if the stock drivers do not work. And of course always keep your system up-to-date.
|
||||
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
||||
|
||||
@@ -10,13 +10,7 @@ Simply put, types/classes are named as `PascalCase`, same for methods and functi
|
||||
|
||||
Except for Qt MOC where `functionName` is preferred.
|
||||
|
||||
Template typenames prefer short names like `T`, `I`, `U`, if a longer name is required either `Iterator` or `perform_action` are fine as well. Do not use names like `SS` as systems like solaris define it for registers, in general do not use any of the following for short names:
|
||||
- `SS`, `DS`, `GS`, `FS`: Segment registers, defined by Solaris `<ucontext.h>`
|
||||
- `EAX`, `EBX`, `ECX`, `EDX`, `ESI`, `EDI`, `ESP`, `EBP`, `EIP`: Registers, defined by Solaris.
|
||||
- `X`: Defined by some utility headers, avoid.
|
||||
- `_`: Defined by gettext, avoid.
|
||||
- `N`, `M`, `S`: Preferably don't use this for types, use it for numeric constants.
|
||||
- `TR`: Used by some weird `<ucontext.h>` whom define the Task Register as a logical register to provide to the user... (Need to remember which OS in specific).
|
||||
Template typenames prefer short names like `T`, `I`, `U`, if a longer name is required either `Iterator` or `perform_action` are fine as well.
|
||||
|
||||
Macros must always be in `SCREAMING_CASE`. Do not use short letter macros as systems like Solaris will conflict with them; a good rule of thumb is >5 characters per macro - i.e `THIS_MACRO_IS_GOOD`, `AND_ALSO_THIS_ONE`.
|
||||
|
||||
@@ -24,45 +18,25 @@ Try not using hungarian notation, if you're able.
|
||||
|
||||
## Formatting
|
||||
|
||||
Formatting is extremelly lax, the general rule of thumb is: Don't add new lines just to increase line count. The less lines we have to look at, the better. This means also packing densely your code while not making it a clusterfuck. Strike a balance of "this is a short and comprehensible piece of code" and "my eyes are actually happy to see this!". Don't just drop the entire thing in a single line and call it "dense code", that's just spaghetti posing as code. In general, be mindful of what other devs need to look at.
|
||||
|
||||
Do not put if/while/etc braces after lines:
|
||||
```c++
|
||||
// no dont do this
|
||||
// this is more lines of code for no good reason (why braces need their separate lines?)
|
||||
// and those take space in someone's screen, cumulatively
|
||||
if (thing)
|
||||
{ //<--
|
||||
{
|
||||
some(); // ...
|
||||
} //<-- 2 lines of code for basically "opening" and "closing" an statment
|
||||
}
|
||||
|
||||
// do this
|
||||
if (thing) { //<-- [...] and with your brain you can deduce it's this piece of code
|
||||
// that's being closed
|
||||
if (thing) {
|
||||
some(); // ...
|
||||
} //<-- only one line, and it's clearer since you know its closing something [...]
|
||||
}
|
||||
|
||||
// or this, albeit the extra line isn't needed (at your discretion of course)
|
||||
// or this
|
||||
if (thing)
|
||||
some(); // ...
|
||||
|
||||
// this is also ok, keeps things in one line and makes it extremely clear
|
||||
// this is also ok
|
||||
if (thing) some();
|
||||
|
||||
// NOT ok, don't be "clever" and use the comma operator to stash a bunch of statments
|
||||
// in a single line, doing this will definitely ruin someone's day - just do the thing below
|
||||
// vvv
|
||||
if (thing) some(), thing(), a2(a1(), y1(), j1()), do_complex_shit(wa(), wo(), ploo());
|
||||
// ... and in general don't use the comma operator for "multiple statments", EXCEPT if you think
|
||||
// that it makes the code more readable (the situation may be rare however)
|
||||
|
||||
// Wow so much clearer! Now I can actually see what each statment is meant to do!
|
||||
if (thing) {
|
||||
some();
|
||||
thing();
|
||||
a2(a1(), y1(), j1());
|
||||
do_complex_shit(wa(), wo(), ploo());
|
||||
}
|
||||
```
|
||||
|
||||
Brace rules are lax, if you can get the point across, do it:
|
||||
@@ -103,21 +77,3 @@ if (device_name.empty()) {
|
||||
SDL_AudioSpec obtained;
|
||||
device = SDL_OpenAudioDevice(device_name.empty() ? nullptr : device_name.c_str(), capture, &spec, &obtained, false);
|
||||
```
|
||||
|
||||
A note about operators: Use them sparingly, yes, the language is lax on them, but some usages can be... tripping to say the least.
|
||||
```c++
|
||||
a, b, c; //<-- NOT OK multiple statments with comma operator is definitely a recipe for disaster
|
||||
return c ? a : b; //<-- OK ternaries at end of return statments are clear and fine
|
||||
return a, b; //<-- NOT OK return will take value of `b` but also evaluate `a`, just use a separate statment
|
||||
void f(int a[]) //<-- OK? if you intend to use the pointer as an array, otherwise just mark it as *
|
||||
```
|
||||
|
||||
And about templates, use them sparingly, don't just do meta-templating for the sake of it, do it when you actually need it. This isn't a competition to see who can make the most complicated and robust meta-templating system. Just use what works, and preferably stick to the standard libary instead of reinventing the wheel. Additionally:
|
||||
|
||||
```c++
|
||||
// NOT OK This will create (T * N * C * P) versions of the same function. DO. NOT. DO. THIS.
|
||||
template<typename T, size_t N, size_t C, size_t P> inline void what() const noexcept;
|
||||
|
||||
// OK use parameters like a normal person, don't be afraid to use them :)
|
||||
template<typename T> inline void what(size_t n, size_t c, size_t p) const noexcept;
|
||||
```
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# Cross compiling
|
||||
# Cross Compile
|
||||
|
||||
General guide for cross compiling.
|
||||
|
||||
## Debian ARM64
|
||||
## ARM64
|
||||
|
||||
A painless guide for cross compilation (or to test NCE) from a x86_64 system without polluting your main.
|
||||
|
||||
|
||||
@@ -1,44 +1,42 @@
|
||||
# Dependencies
|
||||
|
||||
To build Eden, you MUST have a C++ compiler.
|
||||
|
||||
* On Linux, this is usually [GCC](https://gcc.gnu.org/) 11+ or [Clang](https://clang.llvm.org/) v14+
|
||||
* GCC 12 also requires Clang 14+
|
||||
- GCC 12 also requires Clang 14+
|
||||
* On Windows, we support:
|
||||
* **[MSVC](https://visualstudio.microsoft.com/downloads/)** (default)
|
||||
* It's STRONGLY RECOMMENDED to use the **Community** option and **Visual Studio 2022**
|
||||
* You need to install: **[Desktop development with C++](https://learn.microsoft.com/en-us/cpp/build/vscpp-step-0-installation?view=msvc-170)**
|
||||
* **[clang-cl](https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild?view=msvc-180)**
|
||||
* You need to install: **C++ Clang tools for Windows**
|
||||
* **[MSYS2](https://www.msys2.org)**
|
||||
- **[MSVC](https://visualstudio.microsoft.com/downloads/)** (default)
|
||||
- It's STRONGLY RECOMMENDED to use the **Community** option and **Visual Studio 2022**
|
||||
- You need to install: **[Desktop development with C++](https://learn.microsoft.com/en-us/cpp/build/vscpp-step-0-installation?view=msvc-170)**
|
||||
- **[clang-cl](https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild?view=msvc-180)**
|
||||
- You need to install: **C++ Clang tools for Windows**
|
||||
- **[MSYS2](https://www.msys2.org)** (experimental)
|
||||
* On macOS, this is Apple Clang
|
||||
* This can be installed with `xcode-select --install`
|
||||
- This can be installed with `xcode-select --install`
|
||||
|
||||
The following additional tools are also required:
|
||||
|
||||
* **[CMake](https://www.cmake.org/)** 3.22+ - already included with the Android SDK
|
||||
* **[Git](https://git-scm.com/)** for version control
|
||||
* **[Windows installer](https://gitforwindows.org)**
|
||||
- **[Windows installer](https://gitforwindows.org)**
|
||||
* **[Python3](https://www.python.org/downloads/)** 3.10+ - necessary to download external repositories
|
||||
* On Windows, you must install the **[Vulkan SDK](https://vulkan.lunarg.com/sdk/home#windows)** as well
|
||||
* *A convenience script to install the latest SDK is provided in:*
|
||||
* `tools/windows/install-vulkan-sdk.ps1` (for PowerShell 5+)
|
||||
* `tools/windows/install-vulkan-sdk.sh` (for Git Bash, etc)
|
||||
- *A convenience script to install the latest SDK is provided in:*
|
||||
- `tools/windows/install-vulkan-sdk.ps1` (for PowerShell 5+)
|
||||
- `tools/windows/install-vulkan-sdk.sh` (for MSYS2, Git Bash, etc)
|
||||
|
||||
If you are on desktop and plan to use the Qt frontend, you *must* install Qt 6, and optionally Qt Creator (the **RECOMMENDED** IDE for building)
|
||||
|
||||
* On Linux, *BSD and macOS, this can be done by the package manager
|
||||
* If you wish to use Qt Creator, append `qtcreator` or `qt-creator` to the commands seen below.
|
||||
- If you wish to use Qt Creator, append `qtcreator` or `qt-creator` to the commands seen below.
|
||||
* MSVC/clang-cl users on Windows must install through the official [Qt](https://www.qt.io/download-qt-installer-oss) installer
|
||||
* Linux and macOS users may choose to use the installer as well.
|
||||
* MSYS2 can also install Qt 6 via the package manager
|
||||
|
||||
* For help setting up Qt Creator, run `./install.sh -h qtcreator`
|
||||
If you are on Windows, a convenience script to install MSVC, MSYS2, Qt, all necessary packages for MSYS2, and set up a zsh environment with useful keybinds and aliases can be found [here](https://git.crueter.xyz/scripts/windev).
|
||||
- For help setting up Qt Creator, run `./install.sh -h qtcreator`
|
||||
|
||||
If you are on **Windows** and building with **MSVC** or **clang-cl**, you may go [back home](Build.md) and continue.
|
||||
|
||||
## Externals
|
||||
|
||||
The following are handled by Eden's externals:
|
||||
|
||||
* [FFmpeg](https://ffmpeg.org/) (should use `-DYUZU_USE_EXTERNAL_FFMPEG=ON`)
|
||||
@@ -59,7 +57,6 @@ All other dependencies will be downloaded and built by [CPM](https://github.com/
|
||||
* [MbedTLS](https://github.com/Mbed-TLS/mbedtls) 3+
|
||||
|
||||
Vulkan 1.3.274+ is also needed:
|
||||
|
||||
* [VulkanUtilityLibraries](https://github.com/KhronosGroup/Vulkan-Utility-Libraries)
|
||||
* [VulkanHeaders](https://github.com/KhronosGroup/Vulkan-Headers)
|
||||
* [SPIRV-Tools](https://github.com/KhronosGroup/SPIRV-Tools)
|
||||
@@ -74,21 +71,18 @@ Certain other dependencies will be fetched by CPM regardless. System packages *c
|
||||
* [VulkanMemoryAllocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
|
||||
* [sirit](https://github.com/eden-emulator/sirit)
|
||||
* [httplib](https://github.com/yhirose/cpp-httplib) - if `ENABLE_UPDATE_CHECKER` or `ENABLE_WEB_SERVICE` are on
|
||||
* This package is known to be broken on the AUR.
|
||||
- This package is known to be broken on the AUR.
|
||||
* [cpp-jwt](https://github.com/arun11299/cpp-jwt) 1.4+ - if `ENABLE_WEB_SERVICE` is on
|
||||
* [unordered-dense](https://github.com/martinus/unordered_dense)
|
||||
* [mcl](https://github.com/azahar-emu/mcl) - subject to removal
|
||||
|
||||
On amd64:
|
||||
|
||||
* [xbyak](https://github.com/herumi/xbyak) - 7.22 or earlier is recommended
|
||||
|
||||
On aarch64 OR if `DYNARMIC_TESTS` is on:
|
||||
|
||||
* [oaknut](https://github.com/merryhime/oaknut) 2.0.1+
|
||||
|
||||
On riscv64:
|
||||
|
||||
* [biscuit](https://github.com/lioncash/biscuit) 0.9.1+
|
||||
|
||||
## Commands
|
||||
@@ -104,7 +98,7 @@ Click on the arrows to expand.
|
||||
|
||||
GURU must be enabled:
|
||||
|
||||
```sh
|
||||
```
|
||||
sudo emerge -a app-eselect/eselect-repository
|
||||
sudo eselect repository enable guru
|
||||
sudo emaint sync -r guru
|
||||
@@ -130,18 +124,17 @@ sudo emerge -a \
|
||||
virtual/pkgconfig
|
||||
```
|
||||
|
||||
* On `amd64`, also add `dev-libs/xbyak`
|
||||
* On `riscv64`, also add `dev-libs/biscuit` (currently unavailable)
|
||||
* On `aarch64`, also add `dev-libs/oaknut`
|
||||
* If tests are enabled, also add `dev-libs/oaknut` and `dev-cpp/catch`
|
||||
- On `amd64`, also add `dev-libs/xbyak`
|
||||
- On `riscv64`, also add `dev-libs/biscuit` (currently unavailable)
|
||||
- On `aarch64`, also add `dev-libs/oaknut`
|
||||
- If tests are enabled, also add `dev-libs/oaknut` and `dev-cpp/catch`
|
||||
|
||||
Required USE flags:
|
||||
|
||||
* `dev-qt/qtbase network concurrent dbus gui widgets`
|
||||
* `dev-libs/quazip qt6`
|
||||
* `net-libs/mbedtls cmac`
|
||||
* `media-libs/libsdl2 haptic joystick sound video`
|
||||
* `dev-cpp/cpp-httplib ssl`
|
||||
- `dev-qt/qtbase network concurrent dbus gui widgets`
|
||||
- `dev-libs/quazip qt6`
|
||||
- `net-libs/mbedtls cmac`
|
||||
- `media-libs/libsdl2 haptic joystick sound video`
|
||||
- `dev-cpp/cpp-httplib ssl`
|
||||
|
||||
[Caveats](./Caveats.md#gentoo-linux)
|
||||
|
||||
@@ -157,7 +150,6 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
|
||||
* Building with QT Web Engine requires `qt6-webengine` as well.
|
||||
* Proper Wayland support requires `qt6-wayland`
|
||||
* GCC 11 or later is required.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
@@ -169,20 +161,17 @@ sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev l
|
||||
|
||||
* Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
|
||||
* To enable QT Web Engine, add `-DYUZU_USE_QT_WEB_ENGINE=ON` when running CMake.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>AlmaLinux, Fedora, Red Hat Linux</summary>
|
||||
|
||||
Fedora:
|
||||
|
||||
```sh
|
||||
sudo dnf install autoconf cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel boost jq
|
||||
```
|
||||
|
||||
AlmaLinux (use `YUZU_USE_CPM=ON`):
|
||||
|
||||
```sh
|
||||
# vvv - Only if RPMfusion is not installed or EPEL isn't either
|
||||
sudo dnf install epel-release dnf-utils
|
||||
@@ -199,14 +188,12 @@ For systems like OpenEuler or derivates, don't forget to also install: `SDL2-dev
|
||||
* [RPM Fusion](https://rpmfusion.org/Configuration) is required for `ffmpeg-devel`
|
||||
* Fedora 32 or later is required.
|
||||
* Fedora 36+ users with GCC 12 need Clang and should configure CMake with: `cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -B build`
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Alpine Linux</summary>
|
||||
|
||||
First, enable the community repository; [see here](https://wiki.alpinelinux.org/wiki/Repositories#Enabling_the_community_repository).
|
||||
|
||||
```sh
|
||||
# Enable the community repository
|
||||
setup-apkrepos -c
|
||||
@@ -246,9 +233,8 @@ brew install autoconf automake boost ffmpeg fmt glslang hidapi libtool libusb lz
|
||||
If you are compiling on Intel Mac, or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` with `/usr/local`.
|
||||
|
||||
To run with MoltenVK, install additional dependencies:
|
||||
|
||||
```sh
|
||||
brew install molten-vk
|
||||
brew install molten-vk vulkan-loader
|
||||
```
|
||||
|
||||
[Caveats](./Caveats.md#macos).
|
||||
@@ -267,7 +253,7 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
|
||||
<details>
|
||||
<summary>NetBSD</summary>
|
||||
|
||||
For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6 mbedtls3 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx`.
|
||||
For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers ffmpeg7 libva nlohmann-json jq libopus qt6 mbedtls3 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx`.
|
||||
|
||||
[Caveats](./Caveats.md#netbsd).
|
||||
|
||||
@@ -308,24 +294,23 @@ sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json ope
|
||||
|
||||
* Open the `MSYS2 MinGW 64-bit` shell (`mingw64.exe`)
|
||||
* Download and install all dependencies:
|
||||
|
||||
```sh
|
||||
```
|
||||
BASE="git make autoconf libtool automake-wrapper jq patch"
|
||||
MINGW="qt6-base qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus mbedtls libusb unordered_dense openssl SDL2"
|
||||
# Either x86_64 or clang-aarch64 (Windows on ARM)
|
||||
|
||||
MINGW="qt6-base qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus mbedtls libusb unordered_dense"
|
||||
|
||||
packages="$BASE"
|
||||
for pkg in $MINGW; do
|
||||
packages="$packages mingw-w64-x86_64-$pkg"
|
||||
#packages="$packages mingw-w64-clang-aarch64-$pkg"
|
||||
done
|
||||
|
||||
pacman -Syuu --needed --noconfirm $packages
|
||||
```
|
||||
|
||||
* Notes:
|
||||
* Using `qt6-static` is possible as well, provided you build with `-DYUZU_STATIC_BUILD=ON`.
|
||||
* Other environments are entirely untested, but should theoretically work provided you install all the necessary packages.
|
||||
* GCC is proven to work better with the MinGW environment. On ARM, only Clang is available through the CLANGARM64 environment, so use that until a GNU ARM environment is available.
|
||||
* Add `qt-creator` to the `MINGW` variable to install Qt Creator. You can then create a Start Menu shortcut to the MinGW Qt Creator by running `powershell "\$s=(New-Object -COM WScript.Shell).CreateShortcut('C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Qt Creator.lnk');\$s.TargetPath='C:\\msys64\\mingw64\\bin\\qtcreator.exe';\$s.Save()"` in Git Bash or MSYS2.
|
||||
- Using `qt6-static` is possible but currently untested.
|
||||
- Other environments are entirely untested, but should theoretically work provided you install all the necessary packages.
|
||||
- GCC is proven to work better with the MinGW environment. If you choose to use Clang, you *may* be better off using the clang64 environment.
|
||||
- Add `qt-creator` to the `MINGW` variable to install Qt Creator. You can then create a Start Menu shortcut to the MinGW Qt Creator by running `powershell "\$s=(New-Object -COM WScript.Shell).CreateShortcut('C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Qt Creator.lnk');\$s.TargetPath='C:\\msys64\\mingw64\\bin\\qtcreator.exe';\$s.Save()"` in Git Bash or MSYS2.
|
||||
* Add MinGW binaries to the PATH if they aren't already:
|
||||
* `echo 'PATH=/mingw64/bin:$PATH' >> ~/.bashrc`
|
||||
* or `echo 'PATH=/mingw64/bin:$PATH' >> ~/.zshrc`
|
||||
|
||||
@@ -13,5 +13,3 @@ This contains documentation created by developers. This contains build instructi
|
||||
- **[The NVIDIA SM86 (Maxwell) GPU](./NvidiaGpu.md)**
|
||||
- **[User Handbook](./user)**
|
||||
- **[Release Policy](./ReleasePolicy.md)**
|
||||
- **[Dynarmic](./dynarmic)**
|
||||
- **[Cross compilation](./CrossCompile.md)**
|
||||
|
||||
@@ -76,12 +76,12 @@ The APK and AAB will be output into "artifacts".
|
||||
|
||||
Examples:
|
||||
|
||||
* Build legacy release with update checker:
|
||||
* `.ci/android/build.sh -r -t legacy`
|
||||
* Build legacy release with update checker for ChromeOS:
|
||||
* `.ci/android/build.sh -c -r -t legacy`
|
||||
* Build standard release with debug info without update checker for phones:
|
||||
* `.ci/android/build.sh -b RelWithDebInfo`
|
||||
* Build optimized release with update checker for ChromeOS:
|
||||
* `.ci/android/build.sh -c -r -t optimized`
|
||||
* Build optimized release with update checker:
|
||||
* `.ci/android/build.sh -r -t optimized`
|
||||
|
||||
### Additional Resources
|
||||
|
||||
|
||||
@@ -71,9 +71,9 @@
|
||||
"hash": "9697e80a7d5d9bcb3ce51051a9a24962fb90ca79d215f1f03ae6b58da8ba13a63b5dda1b4dde3d26ac6445029696b8ef2883f4e5a777b342bba01283ed293856"
|
||||
},
|
||||
"libadrenotools": {
|
||||
"repo": "eden-emulator/libadrenotools",
|
||||
"sha": "8ba23b42d7",
|
||||
"hash": "f6526620cb752876edc5ed4c0925d57b873a8218ee09ad10859ee476e9333259784f61c1dcc55a2bcba597352d18aff22cd2e4c1925ec2ae94074e09d7da2265",
|
||||
"repo": "bylaws/libadrenotools",
|
||||
"sha": "8fae8ce254",
|
||||
"hash": "db4a74ce15559c75e01d1868a90701519b655d77f2a343bbee283a42f8332dc9046960fb022dc969f205e457348a3f99cb8be6e1cd91264d2ae1235294b9f9b2",
|
||||
"patches": [
|
||||
"0001-linkerns-cpm.patch"
|
||||
]
|
||||
@@ -180,8 +180,8 @@
|
||||
"discord-rpc": {
|
||||
"package": "DiscordRPC",
|
||||
"repo": "eden-emulator/discord-rpc",
|
||||
"sha": "0d8b2d6a37",
|
||||
"hash": "8213c43dcb0f7d479f5861091d111ed12fbdec1e62e6d729d65a4bc181d82f48a35d5fd3cd5c291f2393ac7c9681eabc6b76609755f55376284c8a8d67e148f3",
|
||||
"sha": "1cf7772bb6",
|
||||
"hash": "9a6c35887dcacceb4ba1bf3141edb73b05b2abc719a8d81dad9cb9dd5b039ce203946787335d9d738af669c10cf2534638b645635a22096fc28dcae2475e0cbe",
|
||||
"find_args": "MODULE"
|
||||
},
|
||||
"simpleini": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
let
|
||||
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05";
|
||||
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-25.11";
|
||||
pkgs = import nixpkgs { config = {}; overlays = []; };
|
||||
in
|
||||
pkgs.mkShellNoCC {
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
include_directories(.)
|
||||
|
||||
# Dynarmic
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64))
|
||||
set(DYNARMIC_IGNORE_ASSERTS ON)
|
||||
add_subdirectory(dynarmic)
|
||||
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
||||
endif()
|
||||
|
||||
@@ -29,9 +29,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
|
||||
|
||||
<application
|
||||
android:name="org.yuzu.yuzu_emu.YuzuApplication"
|
||||
|
||||
@@ -61,11 +61,6 @@ class YuzuApplication : Application() {
|
||||
application = this
|
||||
documentsTree = DocumentsTree()
|
||||
DirectoryInitialization.start()
|
||||
|
||||
// Initialize Freedreno config BEFORE loading native library
|
||||
// This ensures GPU driver environment variables are set before adrenotools initializes
|
||||
GpuDriverHelper.initializeFreedrenoConfigEarly()
|
||||
|
||||
NativeLibrary.playTimeManagerInit()
|
||||
GpuDriverHelper.initializeDriverParameters()
|
||||
NativeInput.reloadInputDevices()
|
||||
|
||||
@@ -639,7 +639,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
|
||||
|
||||
companion object {
|
||||
const val EXTRA_SELECTED_GAME = "SelectedGame"
|
||||
const val EXTRA_OVERLAY_GAMELESS_EDIT_MODE = "overlayGamelessEditMode"
|
||||
|
||||
fun stopForegroundService(activity: Activity) {
|
||||
val startIntent = Intent(activity, ForegroundService::class.java)
|
||||
@@ -653,12 +652,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
|
||||
activity.startActivity(launcher)
|
||||
}
|
||||
|
||||
fun launchForOverlayEdit(context: Context): Intent {
|
||||
return Intent(context, EmulationActivity::class.java).apply {
|
||||
putExtra(EXTRA_OVERLAY_GAMELESS_EDIT_MODE, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun areCoordinatesOutside(view: View?, x: Float, y: Float): Boolean {
|
||||
if (view == null) {
|
||||
return true
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.yuzu.yuzu_emu.utils.FreedrenoPreset
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemFreedrenoPresetBinding
|
||||
|
||||
/**
|
||||
* Adapter for displaying Freedreno preset configurations in a horizontal list.
|
||||
*/
|
||||
class FreedrenoPresetAdapter(
|
||||
private val onPresetClicked: (FreedrenoPreset) -> Unit
|
||||
) : ListAdapter<FreedrenoPreset, FreedrenoPresetAdapter.PresetViewHolder>(DiffCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PresetViewHolder {
|
||||
val binding = ListItemFreedrenoPresetBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return PresetViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PresetViewHolder, position: Int) {
|
||||
holder.bind(getItem(position))
|
||||
}
|
||||
|
||||
inner class PresetViewHolder(private val binding: ListItemFreedrenoPresetBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(preset: FreedrenoPreset) {
|
||||
binding.presetButton.apply {
|
||||
text = preset.name
|
||||
setOnClickListener {
|
||||
onPresetClicked(preset)
|
||||
}
|
||||
contentDescription = "${preset.name}: ${preset.description}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DiffCallback = object : DiffUtil.ItemCallback<FreedrenoPreset>() {
|
||||
override fun areItemsTheSame(oldItem: FreedrenoPreset, newItem: FreedrenoPreset): Boolean =
|
||||
oldItem.name == newItem.name
|
||||
|
||||
override fun areContentsTheSame(oldItem: FreedrenoPreset, newItem: FreedrenoPreset): Boolean =
|
||||
oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemFreedrenoVariableBinding
|
||||
import org.yuzu.yuzu_emu.fragments.FreedrenoVariable
|
||||
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
||||
|
||||
/**
|
||||
* Adapter for displaying currently set Freedreno environment variables in a list.
|
||||
*/
|
||||
class FreedrenoVariableAdapter(
|
||||
private val context: Context,
|
||||
private val onItemClicked: (FreedrenoVariable, () -> Unit) -> Unit
|
||||
) : ListAdapter<FreedrenoVariable, FreedrenoVariableAdapter.VariableViewHolder>(DiffCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VariableViewHolder {
|
||||
val binding = ListItemFreedrenoVariableBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return VariableViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: VariableViewHolder, position: Int) {
|
||||
holder.bind(getItem(position))
|
||||
}
|
||||
|
||||
inner class VariableViewHolder(private val binding: ListItemFreedrenoVariableBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(variable: FreedrenoVariable) {
|
||||
binding.variableName.text = variable.name
|
||||
binding.variableValue.text = variable.value
|
||||
|
||||
binding.buttonDelete.setOnClickListener {
|
||||
onItemClicked(variable) {
|
||||
NativeFreedrenoConfig.clearFreedrenoEnv(variable.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DiffCallback = object : DiffUtil.ItemCallback<FreedrenoVariable>() {
|
||||
override fun areItemsTheSame(oldItem: FreedrenoVariable, newItem: FreedrenoVariable): Boolean =
|
||||
oldItem.name == newItem.name
|
||||
|
||||
override fun areContentsTheSame(oldItem: FreedrenoVariable, newItem: FreedrenoVariable): Boolean =
|
||||
oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
DPAD_SLIDE("dpad_slide"),
|
||||
HAPTIC_FEEDBACK("haptic_feedback"),
|
||||
SHOW_INPUT_OVERLAY("show_input_overlay"),
|
||||
OVERLAY_SNAP_TO_GRID("overlay_snap_to_grid"),
|
||||
TOUCHSCREEN("touchscreen"),
|
||||
AIRPLANE_MODE("airplane_mode"),
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||
WIFI_WEB_AUTH_APPLET("wifi_web_auth_applet_mode"),
|
||||
MY_PAGE_APPLET("my_page_applet_mode"),
|
||||
INPUT_OVERLAY_AUTO_HIDE("input_overlay_auto_hide"),
|
||||
OVERLAY_GRID_SIZE("overlay_grid_size"),
|
||||
DEBUG_KNOBS("debug_knobs")
|
||||
;
|
||||
|
||||
|
||||
@@ -25,9 +25,7 @@ object Settings {
|
||||
SECTION_INPUT_PLAYER_SEVEN,
|
||||
SECTION_INPUT_PLAYER_EIGHT,
|
||||
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_APPLETS(R.string.applets_menu);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||
|
||||
import android.content.Intent
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
/**
|
||||
* A settings item that launches an intent when clicked.
|
||||
*/
|
||||
class LaunchableSetting(
|
||||
@StringRes titleId: Int = 0,
|
||||
titleString: String = "",
|
||||
@StringRes descriptionId: Int = 0,
|
||||
descriptionString: String = "",
|
||||
val launchIntent: (android.content.Context) -> Intent
|
||||
) : SettingsItem(emptySetting, titleId, titleString, descriptionId, descriptionString) {
|
||||
override val type = SettingsItem.TYPE_LAUNCHABLE
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
|
||||
class PathSetting(
|
||||
@StringRes titleId: Int = 0,
|
||||
titleString: String = "",
|
||||
@StringRes descriptionId: Int = 0,
|
||||
descriptionString: String = "",
|
||||
@DrawableRes val iconId: Int = 0,
|
||||
val pathType: PathType,
|
||||
val defaultPathGetter: () -> String,
|
||||
val currentPathGetter: () -> String,
|
||||
val pathSetter: (String) -> Unit
|
||||
) : SettingsItem(emptySetting, titleId, titleString, descriptionId, descriptionString) {
|
||||
|
||||
override val type = TYPE_PATH
|
||||
|
||||
enum class PathType {
|
||||
SAVE_DATA,
|
||||
NAND,
|
||||
SDMC
|
||||
}
|
||||
|
||||
fun getCurrentPath(): String = currentPathGetter()
|
||||
|
||||
fun getDefaultPath(): String = defaultPathGetter()
|
||||
|
||||
fun setPath(path: String) = pathSetter(path)
|
||||
|
||||
fun isUsingDefaultPath(): Boolean = getCurrentPath() == getDefaultPath()
|
||||
|
||||
companion object {
|
||||
const val TYPE_PATH = 14
|
||||
}
|
||||
}
|
||||
@@ -97,8 +97,6 @@ abstract class SettingsItem(
|
||||
const val TYPE_INPUT_PROFILE = 10
|
||||
const val TYPE_STRING_INPUT = 11
|
||||
const val TYPE_SPINBOX = 12
|
||||
const val TYPE_LAUNCHABLE = 13
|
||||
const val TYPE_PATH = 14
|
||||
|
||||
const val FASTMEM_COMBINED = "fastmem_combined"
|
||||
|
||||
@@ -306,7 +304,6 @@ abstract class SettingsItem(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.RENDERER_ACCURACY,
|
||||
titleId = R.string.renderer_accuracy,
|
||||
descriptionId = R.string.renderer_accuracy_description,
|
||||
choicesId = R.array.rendererAccuracyNames,
|
||||
valuesId = R.array.rendererAccuracyValues
|
||||
)
|
||||
@@ -367,30 +364,6 @@ abstract class SettingsItem(
|
||||
warningMessage = R.string.warning_resolution
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_INPUT_OVERLAY,
|
||||
titleId = R.string.show_input_overlay,
|
||||
descriptionId = R.string.show_input_overlay_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.OVERLAY_SNAP_TO_GRID,
|
||||
titleId = R.string.overlay_snap_to_grid,
|
||||
descriptionId = R.string.overlay_snap_to_grid_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SliderSetting(
|
||||
IntSetting.OVERLAY_GRID_SIZE,
|
||||
titleId = R.string.overlay_grid_size,
|
||||
descriptionId = R.string.overlay_grid_size_description,
|
||||
min = 16,
|
||||
max = 128,
|
||||
units = "px"
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE,
|
||||
@@ -450,7 +423,7 @@ abstract class SettingsItem(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_FRAMETIME,
|
||||
R.string.show_frametime,
|
||||
descriptionId = 0
|
||||
descriptionId = R.string.show_frametime_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
@@ -471,7 +444,7 @@ abstract class SettingsItem(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_BAT_TEMPERATURE,
|
||||
R.string.show_bat_temperature,
|
||||
descriptionId = 0
|
||||
descriptionId = R.string.show_bat_temperature_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
@@ -501,21 +474,21 @@ abstract class SettingsItem(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_SOC_OVERLAY,
|
||||
R.string.enable_soc_overlay,
|
||||
descriptionId = 0
|
||||
descriptionId = R.string.soc_overlay_options_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SOC_OVERLAY_BACKGROUND,
|
||||
R.string.perf_overlay_background,
|
||||
descriptionId = 0
|
||||
descriptionId = R.string.perf_overlay_background_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.SOC_OVERLAY_POSITION,
|
||||
titleId = R.string.overlay_position,
|
||||
descriptionId = 0,
|
||||
descriptionId = R.string.overlay_position_description,
|
||||
choicesId = R.array.statsPosition,
|
||||
valuesId = R.array.staticThemeValues
|
||||
)
|
||||
@@ -525,28 +498,28 @@ abstract class SettingsItem(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_DEVICE_MODEL,
|
||||
titleId = R.string.show_device_model,
|
||||
descriptionId = 0
|
||||
descriptionId = R.string.show_device_model_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_GPU_MODEL,
|
||||
titleId = R.string.show_gpu_model,
|
||||
descriptionId = 0
|
||||
descriptionId = R.string.show_gpu_model_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_SOC_MODEL,
|
||||
titleId = R.string.show_soc_model,
|
||||
descriptionId = 0
|
||||
descriptionId = R.string.show_soc_model_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_FW_VERSION,
|
||||
titleId = R.string.show_fw_version,
|
||||
descriptionId = 0
|
||||
descriptionId = R.string.show_fw_version_description
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.*
|
||||
import org.yuzu.yuzu_emu.features.settings.ui.viewholder.*
|
||||
import org.yuzu.yuzu_emu.utils.ParamPackage
|
||||
@@ -94,13 +93,6 @@ class SettingsAdapter(
|
||||
StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_LAUNCHABLE -> {
|
||||
LaunchableViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_PATH -> {
|
||||
PathViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
else -> {
|
||||
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
||||
}
|
||||
@@ -213,20 +205,8 @@ class SettingsAdapter(
|
||||
}
|
||||
|
||||
fun onSubmenuClick(item: SubmenuSetting) {
|
||||
// Check if this is the Freedreno Settings submenu
|
||||
if (item.menuKey == Settings.MenuTag.SECTION_FREEDRENO) {
|
||||
fragment.view?.findNavController()?.navigate(
|
||||
R.id.action_settingsFragment_to_freedrenoSettingsFragment
|
||||
)
|
||||
} else {
|
||||
val action = SettingsNavigationDirections.actionGlobalSettingsFragment(item.menuKey, null)
|
||||
fragment.view?.findNavController()?.navigate(action)
|
||||
}
|
||||
}
|
||||
|
||||
fun onLaunchableClick(item: LaunchableSetting) {
|
||||
val intent = item.launchIntent(context)
|
||||
fragment.requireActivity().startActivity(intent)
|
||||
val action = SettingsNavigationDirections.actionGlobalSettingsFragment(item.menuKey, null)
|
||||
fragment.view?.findNavController()?.navigate(action)
|
||||
}
|
||||
|
||||
fun onInputProfileClick(item: InputProfileSetting, position: Int) {
|
||||
@@ -462,18 +442,6 @@ class SettingsAdapter(
|
||||
settingsViewModel.setShouldReloadSettingsList(true)
|
||||
}
|
||||
|
||||
fun onPathClick(item: PathSetting, position: Int) {
|
||||
settingsViewModel.clickedItem = item
|
||||
settingsViewModel.setPathSettingPosition(position)
|
||||
settingsViewModel.setShouldShowPathPicker(true)
|
||||
}
|
||||
|
||||
fun onPathReset(item: PathSetting, position: Int) {
|
||||
settingsViewModel.clickedItem = item
|
||||
settingsViewModel.setPathSettingPosition(position)
|
||||
settingsViewModel.setShouldShowPathResetDialog(true)
|
||||
}
|
||||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<SettingsItem>() {
|
||||
override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean {
|
||||
return oldItem.setting.key == newItem.setting.key
|
||||
|
||||
@@ -7,16 +7,10 @@
|
||||
package org.yuzu.yuzu_emu.features.settings.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.Settings as AndroidSettings
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updatePadding
|
||||
@@ -25,19 +19,14 @@ import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.PathSetting
|
||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||
import org.yuzu.yuzu_emu.utils.PathUtil
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||
import org.yuzu.yuzu_emu.utils.*
|
||||
import java.io.File
|
||||
import androidx.core.net.toUri
|
||||
|
||||
class SettingsFragment : Fragment() {
|
||||
private lateinit var presenter: SettingsFragmentPresenter
|
||||
@@ -50,20 +39,6 @@ class SettingsFragment : Fragment() {
|
||||
|
||||
private val settingsViewModel: SettingsViewModel by activityViewModels()
|
||||
|
||||
private val requestAllFilesPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) {
|
||||
if (hasAllFilesPermission()) {
|
||||
showPathPickerDialog()
|
||||
} else {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.all_files_permission_required,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
@@ -159,24 +134,6 @@ class SettingsFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
settingsViewModel.shouldShowPathPicker.collect(
|
||||
viewLifecycleOwner,
|
||||
resetState = { settingsViewModel.setShouldShowPathPicker(false) }
|
||||
) {
|
||||
if (it) {
|
||||
handlePathPickerRequest()
|
||||
}
|
||||
}
|
||||
|
||||
settingsViewModel.shouldShowPathResetDialog.collect(
|
||||
viewLifecycleOwner,
|
||||
resetState = { settingsViewModel.setShouldShowPathResetDialog(false) }
|
||||
) {
|
||||
if (it) {
|
||||
showPathResetDialog()
|
||||
}
|
||||
}
|
||||
|
||||
if (args.menuTag == Settings.MenuTag.SECTION_ROOT) {
|
||||
binding.toolbarSettings.inflateMenu(R.menu.menu_settings)
|
||||
binding.toolbarSettings.setOnMenuItemClickListener {
|
||||
@@ -227,199 +184,4 @@ class SettingsFragment : Fragment() {
|
||||
windowInsets
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasAllFilesPermission(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
Environment.isExternalStorageManager()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestAllFilesPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
val intent = Intent(AndroidSettings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
|
||||
intent.data = "package:${requireContext().packageName}".toUri()
|
||||
requestAllFilesPermissionLauncher.launch(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePathPickerRequest() {
|
||||
if (!hasAllFilesPermission()) {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.all_files_permission_required)
|
||||
.setMessage(R.string.all_files_permission_required)
|
||||
.setPositiveButton(R.string.grant_permission) { _, _ ->
|
||||
requestAllFilesPermission()
|
||||
}
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show()
|
||||
return
|
||||
}
|
||||
showPathPickerDialog()
|
||||
}
|
||||
|
||||
private fun showPathPickerDialog() {
|
||||
directoryPickerLauncher.launch(null)
|
||||
}
|
||||
|
||||
private val directoryPickerLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.OpenDocumentTree()
|
||||
) { uri ->
|
||||
if (uri != null) {
|
||||
val pathSetting = settingsViewModel.clickedItem as? PathSetting ?: return@registerForActivityResult
|
||||
val rawPath = PathUtil.getPathFromUri(uri)
|
||||
if (rawPath != null) {
|
||||
handleSelectedPath(pathSetting, rawPath)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.invalid_directory,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSelectedPath(pathSetting: PathSetting, path: String) {
|
||||
if (!PathUtil.validateDirectory(path)) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.invalid_directory,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
return
|
||||
}
|
||||
|
||||
if (pathSetting.pathType == PathSetting.PathType.SAVE_DATA) {
|
||||
val oldPath = pathSetting.getCurrentPath()
|
||||
if (oldPath != path) {
|
||||
promptSaveMigration(pathSetting, oldPath, path)
|
||||
}
|
||||
} else {
|
||||
setPathAndNotify(pathSetting, path)
|
||||
}
|
||||
}
|
||||
|
||||
private fun promptSaveMigration(pathSetting: PathSetting, fromPath: String, toPath: String) {
|
||||
val sourceSavePath = "$fromPath/user/save"
|
||||
val destSavePath = "$toPath/user/save"
|
||||
val sourceSaveDir = File(sourceSavePath)
|
||||
val destSaveDir = File(destSavePath)
|
||||
|
||||
val sourceHasSaves = PathUtil.hasContent(sourceSavePath)
|
||||
val destHasSaves = PathUtil.hasContent(destSavePath)
|
||||
|
||||
if (!sourceHasSaves) {
|
||||
setPathAndNotify(pathSetting, toPath)
|
||||
return
|
||||
}
|
||||
|
||||
if (destHasSaves) {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.migrate_save_data)
|
||||
.setMessage(R.string.destination_has_saves)
|
||||
.setPositiveButton(R.string.confirm) { _, _ ->
|
||||
migrateSaveData(pathSetting, sourceSaveDir, destSaveDir, toPath)
|
||||
}
|
||||
.setNegativeButton(R.string.skip_migration) { _, _ ->
|
||||
setPathAndNotify(pathSetting, toPath)
|
||||
}
|
||||
.setNeutralButton(R.string.cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.migrate_save_data)
|
||||
.setMessage(R.string.migrate_save_data_question)
|
||||
.setPositiveButton(R.string.confirm) { _, _ ->
|
||||
migrateSaveData(pathSetting, sourceSaveDir, destSaveDir, toPath)
|
||||
}
|
||||
.setNegativeButton(R.string.skip_migration) { _, _ ->
|
||||
setPathAndNotify(pathSetting, toPath)
|
||||
}
|
||||
.setNeutralButton(R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun migrateSaveData(
|
||||
pathSetting: PathSetting,
|
||||
sourceDir: File,
|
||||
destDir: File,
|
||||
newPath: String
|
||||
) {
|
||||
Thread {
|
||||
val success = PathUtil.copyDirectory(sourceDir, destDir, overwrite = true)
|
||||
|
||||
requireActivity().runOnUiThread {
|
||||
if (success) {
|
||||
setPathAndNotify(pathSetting, newPath)
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.save_migration_complete,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} else {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.save_migration_failed,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun setPathAndNotify(pathSetting: PathSetting, path: String) {
|
||||
pathSetting.setPath(path)
|
||||
NativeConfig.saveGlobalConfig()
|
||||
|
||||
NativeConfig.reloadGlobalConfig()
|
||||
|
||||
val messageResId = if (pathSetting.pathType == PathSetting.PathType.SAVE_DATA) {
|
||||
R.string.save_directory_set
|
||||
} else {
|
||||
R.string.path_set
|
||||
}
|
||||
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
messageResId,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
|
||||
val position = settingsViewModel.pathSettingPosition.value
|
||||
if (position >= 0) {
|
||||
settingsAdapter?.notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPathResetDialog() {
|
||||
val pathSetting = settingsViewModel.clickedItem as? PathSetting ?: return
|
||||
|
||||
if (pathSetting.isUsingDefaultPath()) {
|
||||
return
|
||||
}
|
||||
|
||||
val currentPath = pathSetting.getCurrentPath()
|
||||
val defaultPath = pathSetting.getDefaultPath()
|
||||
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.reset_to_nand)
|
||||
.setMessage(R.string.migrate_save_data_question)
|
||||
.setPositiveButton(R.string.confirm) { _, _ ->
|
||||
val sourceSaveDir = File(currentPath, "user/save")
|
||||
val destSaveDir = File(defaultPath, "user/save")
|
||||
|
||||
if (sourceSaveDir.exists() && sourceSaveDir.listFiles()?.isNotEmpty() == true) {
|
||||
migrateSaveData(pathSetting, sourceSaveDir, destSaveDir, defaultPath)
|
||||
} else {
|
||||
setPathAndNotify(pathSetting, defaultPath)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
// just dismiss
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import androidx.preference.PreferenceManager
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
|
||||
import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
|
||||
@@ -27,10 +26,8 @@ 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
|
||||
@@ -110,9 +107,7 @@ class SettingsFragmentPresenter(
|
||||
MenuTag.SECTION_INPUT_PLAYER_EIGHT -> addInputPlayer(sl, 7)
|
||||
MenuTag.SECTION_APP_SETTINGS -> addThemeSettings(sl)
|
||||
MenuTag.SECTION_DEBUG -> addDebugSettings(sl)
|
||||
MenuTag.SECTION_FREEDRENO -> addFreedrenoSettings(sl)
|
||||
MenuTag.SECTION_APPLETS -> addAppletSettings(sl)
|
||||
MenuTag.SECTION_CUSTOM_PATHS -> addCustomPathsSettings(sl)
|
||||
}
|
||||
settingsList = sl
|
||||
adapter.submitList(settingsList) {
|
||||
@@ -183,16 +178,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,
|
||||
@@ -201,16 +186,6 @@ class SettingsFragmentPresenter(
|
||||
menuKey = MenuTag.SECTION_APPLETS
|
||||
)
|
||||
)
|
||||
if (!NativeConfig.isPerGameConfigLoaded()) {
|
||||
add(
|
||||
SubmenuSetting(
|
||||
titleId = R.string.preferences_custom_paths,
|
||||
descriptionId = R.string.preferences_custom_paths_description,
|
||||
iconId = R.drawable.ic_folder_open,
|
||||
menuKey = MenuTag.SECTION_CUSTOM_PATHS
|
||||
)
|
||||
)
|
||||
}
|
||||
add(
|
||||
RunnableSetting(
|
||||
titleId = R.string.reset_to_default,
|
||||
@@ -319,19 +294,6 @@ class SettingsFragmentPresenter(
|
||||
|
||||
private fun addInputOverlaySettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(BooleanSetting.SHOW_INPUT_OVERLAY.key)
|
||||
add(BooleanSetting.OVERLAY_SNAP_TO_GRID.key)
|
||||
add(IntSetting.OVERLAY_GRID_SIZE.key)
|
||||
add(
|
||||
LaunchableSetting(
|
||||
titleId = R.string.edit_overlay_layout,
|
||||
descriptionId = R.string.edit_overlay_layout_description,
|
||||
launchIntent = { context ->
|
||||
EmulationActivity.launchForOverlayEdit(context)
|
||||
}
|
||||
)
|
||||
)
|
||||
add(HeaderSetting(R.string.input_overlay_behavior))
|
||||
add(BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.key)
|
||||
add(IntSetting.INPUT_OVERLAY_AUTO_HIDE.key)
|
||||
add(BooleanSetting.HIDE_OVERLAY_ON_CONTROLLER_INPUT.key)
|
||||
@@ -510,11 +472,6 @@ class SettingsFragmentPresenter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun addFreedrenoSettings(sl: ArrayList<SettingsItem>) {
|
||||
// No additional settings needed here - the SubmenuSetting handles navigation
|
||||
// This method is kept for consistency with other menu sections
|
||||
}
|
||||
|
||||
private fun addAppletSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(IntSetting.SWKBD_APPLET.key)
|
||||
@@ -1142,16 +1099,14 @@ class SettingsFragmentPresenter(
|
||||
)
|
||||
)
|
||||
|
||||
if (IntSetting.THEME.getInt() != 1) {
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
staticThemeColor,
|
||||
titleId = R.string.static_theme_color,
|
||||
choicesId = R.array.staticThemeNames,
|
||||
valuesId = R.array.staticThemeValues
|
||||
)
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
staticThemeColor,
|
||||
titleId = R.string.static_theme_color,
|
||||
choicesId = R.array.staticThemeNames,
|
||||
valuesId = R.array.staticThemeValues
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting {
|
||||
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
||||
@@ -1213,42 +1168,4 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.DEBUG_KNOBS.key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCustomPathsSettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(
|
||||
PathSetting(
|
||||
titleId = R.string.custom_save_directory,
|
||||
descriptionId = R.string.custom_save_directory_description,
|
||||
iconId = R.drawable.ic_save,
|
||||
pathType = PathSetting.PathType.SAVE_DATA,
|
||||
defaultPathGetter = { NativeConfig.getDefaultSaveDir() },
|
||||
currentPathGetter = { NativeConfig.getSaveDir() },
|
||||
pathSetter = { path -> NativeConfig.setSaveDir(path) }
|
||||
)
|
||||
)
|
||||
add(
|
||||
PathSetting(
|
||||
titleId = R.string.custom_nand_directory,
|
||||
descriptionId = R.string.custom_nand_directory_description,
|
||||
iconId = R.drawable.ic_folder_open,
|
||||
pathType = PathSetting.PathType.NAND,
|
||||
defaultPathGetter = { DirectoryInitialization.userDirectory + "/nand" },
|
||||
currentPathGetter = { NativeConfig.getNandDir() },
|
||||
pathSetter = { path -> NativeConfig.setNandDir(path) }
|
||||
)
|
||||
)
|
||||
add(
|
||||
PathSetting(
|
||||
titleId = R.string.custom_sdmc_directory,
|
||||
descriptionId = R.string.custom_sdmc_directory_description,
|
||||
iconId = R.drawable.ic_folder_open,
|
||||
pathType = PathSetting.PathType.SDMC,
|
||||
defaultPathGetter = { DirectoryInitialization.userDirectory + "/sdmc" },
|
||||
currentPathGetter = { NativeConfig.getSdmcDir() },
|
||||
pathSetter = { path -> NativeConfig.setSdmcDir(path) }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,16 +59,6 @@ class SettingsViewModel : ViewModel() {
|
||||
|
||||
private val _shouldRecreateForLanguageChange = MutableStateFlow(false)
|
||||
val shouldRecreateForLanguageChange = _shouldRecreateForLanguageChange.asStateFlow()
|
||||
|
||||
private val _shouldShowPathPicker = MutableStateFlow(false)
|
||||
val shouldShowPathPicker = _shouldShowPathPicker.asStateFlow()
|
||||
|
||||
private val _shouldShowPathResetDialog = MutableStateFlow(false)
|
||||
val shouldShowPathResetDialog = _shouldShowPathResetDialog.asStateFlow()
|
||||
|
||||
private val _pathSettingPosition = MutableStateFlow(-1)
|
||||
val pathSettingPosition = _pathSettingPosition.asStateFlow()
|
||||
|
||||
fun setShouldRecreate(value: Boolean) {
|
||||
_shouldRecreate.value = value
|
||||
}
|
||||
@@ -122,18 +112,6 @@ class SettingsViewModel : ViewModel() {
|
||||
_shouldRecreateForLanguageChange.value = value
|
||||
}
|
||||
|
||||
fun setShouldShowPathPicker(value: Boolean) {
|
||||
_shouldShowPathPicker.value = value
|
||||
}
|
||||
|
||||
fun setShouldShowPathResetDialog(value: Boolean) {
|
||||
_shouldShowPathResetDialog.value = value
|
||||
}
|
||||
|
||||
fun setPathSettingPosition(value: Int) {
|
||||
_pathSettingPosition.value = value
|
||||
}
|
||||
|
||||
fun getCurrentDeviceParams(defaultParams: ParamPackage): ParamPackage =
|
||||
try {
|
||||
InputHandler.registeredControllers[currentDevice]
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.LaunchableSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||
|
||||
class LaunchableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||
SettingViewHolder(binding.root, adapter) {
|
||||
private lateinit var setting: LaunchableSetting
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
setting = item as LaunchableSetting
|
||||
|
||||
binding.textSettingName.text = setting.title
|
||||
binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
|
||||
binding.textSettingDescription.text = setting.description
|
||||
|
||||
binding.textSettingValue.setVisible(true)
|
||||
binding.textSettingValue.text = ""
|
||||
binding.textSettingValue.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
0, 0, R.drawable.ic_arrow_forward, 0
|
||||
)
|
||||
|
||||
binding.buttonClear.setVisible(false)
|
||||
}
|
||||
|
||||
override fun onClick(clicked: View) {
|
||||
adapter.onLaunchableClick(setting)
|
||||
}
|
||||
|
||||
override fun onLongClick(clicked: View): Boolean {
|
||||
// no-op
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.PathSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||
import org.yuzu.yuzu_emu.utils.PathUtil
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||
|
||||
class PathViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||
SettingViewHolder(binding.root, adapter) {
|
||||
|
||||
private lateinit var setting: PathSetting
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
setting = item as PathSetting
|
||||
binding.icon.setVisible(setting.iconId != 0)
|
||||
if (setting.iconId != 0) {
|
||||
binding.icon.setImageDrawable(
|
||||
ResourcesCompat.getDrawable(
|
||||
binding.icon.resources,
|
||||
setting.iconId,
|
||||
binding.icon.context.theme
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
binding.textSettingName.text = setting.title
|
||||
binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
|
||||
binding.textSettingDescription.text = setting.description
|
||||
|
||||
val currentPath = setting.getCurrentPath()
|
||||
val displayPath = PathUtil.truncatePathForDisplay(currentPath)
|
||||
|
||||
binding.textSettingValue.setVisible(true)
|
||||
binding.textSettingValue.text = if (setting.isUsingDefaultPath()) {
|
||||
binding.root.context.getString(R.string.default_string)
|
||||
} else {
|
||||
displayPath
|
||||
}
|
||||
|
||||
binding.buttonClear.setVisible(!setting.isUsingDefaultPath())
|
||||
binding.buttonClear.text = binding.root.context.getString(R.string.reset_to_default)
|
||||
binding.buttonClear.setOnClickListener {
|
||||
adapter.onPathReset(setting, bindingAdapterPosition)
|
||||
}
|
||||
|
||||
setStyle(true, binding)
|
||||
}
|
||||
|
||||
override fun onClick(clicked: View) {
|
||||
adapter.onPathClick(setting, bindingAdapterPosition)
|
||||
}
|
||||
|
||||
override fun onLongClick(clicked: View): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ class DriverFetcherFragment : Fragment() {
|
||||
private val client = OkHttpClient()
|
||||
|
||||
private val gpuModel: String?
|
||||
get() = GpuDriverHelper.hookLibPath?.let { GpuDriverHelper.getGpuModel(hookLibPath = it) }
|
||||
get() = GpuDriverHelper.getGpuModel()
|
||||
|
||||
private val adrenoModel: Int
|
||||
get() = parseAdrenoModel()
|
||||
|
||||
@@ -87,7 +87,6 @@ import org.yuzu.yuzu_emu.utils.GameIconUtils
|
||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||
import org.yuzu.yuzu_emu.utils.Log
|
||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||
import org.yuzu.yuzu_emu.utils.collect
|
||||
@@ -202,10 +201,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
super.onCreate(savedInstanceState)
|
||||
updateOrientation()
|
||||
|
||||
if (args.overlayGamelessEditMode) {
|
||||
return
|
||||
}
|
||||
|
||||
val intent = requireActivity().intent
|
||||
val intentUri: Uri? = intent.data
|
||||
intentGame = null
|
||||
@@ -304,18 +299,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
throw fallbackException
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (GpuDriverHelper.isAdrenoGpu()) {
|
||||
val programIdHex = game!!.programIdHex
|
||||
if (NativeFreedrenoConfig.loadPerGameConfigWithGlobalFallback(programIdHex)) {
|
||||
Log.info("[EmulationFragment] Loaded per-game Freedreno config for $programIdHex")
|
||||
} else {
|
||||
Log.info("[EmulationFragment] Using global Freedreno config for $programIdHex")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.warning("[EmulationFragment] Failed to load Freedreno config: ${e.message}")
|
||||
}
|
||||
|
||||
emulationState = EmulationState(game!!.path) {
|
||||
return@EmulationState driverViewModel.isInteractionAllowed.value
|
||||
@@ -575,11 +558,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
return
|
||||
}
|
||||
|
||||
if (args.overlayGamelessEditMode) {
|
||||
setupOverlayGamelessEditMode()
|
||||
return
|
||||
}
|
||||
|
||||
if (game == null) {
|
||||
Log.warning(
|
||||
"[EmulationFragment] Game not yet initialized in onViewCreated - will be set up by async intent handler"
|
||||
@@ -590,46 +568,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
completeViewSetup()
|
||||
}
|
||||
|
||||
|
||||
private fun setupOverlayGamelessEditMode() {
|
||||
binding.surfaceInputOverlay.post {
|
||||
binding.surfaceInputOverlay.refreshControls(gameless = true)
|
||||
}
|
||||
|
||||
binding.doneControlConfig.setOnClickListener {
|
||||
finishOverlayGamelessEditMode()
|
||||
}
|
||||
|
||||
binding.doneControlConfig.visibility = View.VISIBLE
|
||||
binding.surfaceInputOverlay.setIsInEditMode(true)
|
||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||
binding.surfaceInputOverlay.visibility = View.VISIBLE
|
||||
binding.loadingIndicator.visibility = View.GONE
|
||||
|
||||
// in gameless edit mode, back = done
|
||||
requireActivity().onBackPressedDispatcher.addCallback(
|
||||
viewLifecycleOwner,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
finishOverlayGamelessEditMode()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun finishOverlayGamelessEditMode() {
|
||||
binding.surfaceInputOverlay.setIsInEditMode(false)
|
||||
NativeConfig.saveGlobalConfig()
|
||||
requireActivity().finish()
|
||||
}
|
||||
|
||||
private fun completeViewSetup() {
|
||||
if (_binding == null || game == null) {
|
||||
return
|
||||
}
|
||||
Log.info("[EmulationFragment] Starting view setup for game: ${game?.title}")
|
||||
|
||||
gpuModel = GpuDriverHelper.hookLibPath?.let { GpuDriverHelper.getGpuModel(hookLibPath = it).toString() } ?: "Unknown"
|
||||
gpuModel = GpuDriverHelper.getGpuModel().toString()
|
||||
fwVersion = NativeLibrary.firmwareVersion()
|
||||
|
||||
updateQuickOverlayMenuEntry(BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean())
|
||||
@@ -955,12 +900,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
b.surfaceInputOverlay.setVisible(visible = false, gone = false)
|
||||
}
|
||||
} else {
|
||||
val shouldShowOverlay = if (args.overlayGamelessEditMode) {
|
||||
true
|
||||
} else {
|
||||
b.surfaceInputOverlay.setVisible(
|
||||
showInputOverlay && emulationViewModel.emulationStarted.value
|
||||
}
|
||||
b.surfaceInputOverlay.setVisible(shouldShowOverlay)
|
||||
)
|
||||
if (!isInFoldableLayout) {
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
b.surfaceInputOverlay.layout = OverlayLayout.Portrait
|
||||
@@ -1589,8 +1531,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
|
||||
findItem(R.id.menu_show_overlay).isChecked =
|
||||
BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
|
||||
findItem(R.id.menu_snap_to_grid).isChecked =
|
||||
BooleanSetting.OVERLAY_SNAP_TO_GRID.getBoolean()
|
||||
findItem(R.id.menu_haptics).isChecked = BooleanSetting.HAPTIC_FEEDBACK.getBoolean()
|
||||
findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean()
|
||||
}
|
||||
@@ -1619,13 +1559,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_snap_to_grid -> {
|
||||
it.isChecked = !it.isChecked
|
||||
BooleanSetting.OVERLAY_SNAP_TO_GRID.setBoolean(it.isChecked)
|
||||
binding.surfaceInputOverlay.invalidate()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_adjust_overlay -> {
|
||||
adjustOverlay()
|
||||
true
|
||||
@@ -2002,17 +1935,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
|
||||
handler.postDelayed({
|
||||
if (isOverlayVisible && isAdded && _binding != null) {
|
||||
if (isOverlayVisible) {
|
||||
hideOverlay()
|
||||
}
|
||||
}, seconds * 1000L)
|
||||
}
|
||||
|
||||
fun handleScreenTap(isLongTap: Boolean) {
|
||||
if (binding.surfaceInputOverlay.isGamelessMode()) {
|
||||
return
|
||||
}
|
||||
|
||||
val autoHideSeconds = IntSetting.INPUT_OVERLAY_AUTO_HIDE.getInt()
|
||||
val shouldProceed = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() && BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean()
|
||||
|
||||
@@ -2034,10 +1963,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
|
||||
private fun initializeOverlayAutoHide() {
|
||||
if (binding.surfaceInputOverlay.isGamelessMode()) {
|
||||
return
|
||||
}
|
||||
|
||||
val autoHideSeconds = IntSetting.INPUT_OVERLAY_AUTO_HIDE.getInt()
|
||||
val autoHideEnabled = BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean()
|
||||
val showOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.adapters.FreedrenoPresetAdapter
|
||||
import org.yuzu.yuzu_emu.adapters.FreedrenoVariableAdapter
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentFreedrenoSettingsBinding
|
||||
import org.yuzu.yuzu_emu.model.Game
|
||||
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
||||
import org.yuzu.yuzu_emu.utils.FreedrenoPresets
|
||||
|
||||
|
||||
class FreedrenoSettingsFragment : Fragment() {
|
||||
private var _binding: FragmentFreedrenoSettingsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
private val args by navArgs<FreedrenoSettingsFragmentArgs>()
|
||||
private val game: Game? get() = args.game
|
||||
private val isPerGameConfig: Boolean get() = game != null
|
||||
|
||||
private lateinit var presetAdapter: FreedrenoPresetAdapter
|
||||
private lateinit var settingsAdapter: FreedrenoVariableAdapter
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
|
||||
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentFreedrenoSettingsBinding.inflate(layoutInflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
NativeFreedrenoConfig.setFreedrenoBasePath(requireContext().cacheDir.absolutePath)
|
||||
NativeFreedrenoConfig.initializeFreedrenoConfig()
|
||||
|
||||
if (isPerGameConfig) {
|
||||
NativeFreedrenoConfig.loadPerGameConfig(game!!.programIdHex)
|
||||
} else {
|
||||
NativeFreedrenoConfig.reloadFreedrenoConfig()
|
||||
}
|
||||
|
||||
setupToolbar()
|
||||
setupAdapters()
|
||||
loadCurrentSettings()
|
||||
setupButtonListeners()
|
||||
setupWindowInsets()
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
binding.toolbarFreedreno.setNavigationOnClickListener {
|
||||
requireActivity().onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
if (isPerGameConfig) {
|
||||
binding.toolbarFreedreno.title = getString(R.string.freedreno_per_game_title)
|
||||
binding.toolbarFreedreno.subtitle = game!!.title
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupAdapters() {
|
||||
// Setup presets adapter (horizontal list)
|
||||
presetAdapter = FreedrenoPresetAdapter { preset ->
|
||||
applyPreset(preset)
|
||||
}
|
||||
binding.listFreedrenoPresets.apply {
|
||||
adapter = presetAdapter
|
||||
layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
|
||||
}
|
||||
presetAdapter.submitList(FreedrenoPresets.ALL_PRESETS)
|
||||
|
||||
// Setup current settings adapter (vertical list)
|
||||
settingsAdapter = FreedrenoVariableAdapter(requireContext()) { variable, onDelete ->
|
||||
onDelete()
|
||||
loadCurrentSettings() // Refresh list after deletion
|
||||
}
|
||||
binding.listFreedrenoSettings.apply {
|
||||
adapter = settingsAdapter
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadCurrentSettings() {
|
||||
// Load all currently set environment variables
|
||||
val variables = mutableListOf<FreedrenoVariable>()
|
||||
|
||||
// Common variables to check
|
||||
val commonVars = listOf(
|
||||
"TU_DEBUG", "FD_MESA_DEBUG", "IR3_SHADER_DEBUG",
|
||||
"FD_RD_DUMP", "FD_RD_DUMP_FRAMES", "FD_RD_DUMP_TESTNAME",
|
||||
"TU_BREADCRUMBS"
|
||||
)
|
||||
|
||||
for (varName in commonVars) {
|
||||
if (NativeFreedrenoConfig.isFreedrenoEnvSet(varName)) {
|
||||
val value = NativeFreedrenoConfig.getFreedrenoEnv(varName)
|
||||
variables.add(FreedrenoVariable(varName, value))
|
||||
}
|
||||
}
|
||||
|
||||
settingsAdapter.submitList(variables)
|
||||
}
|
||||
|
||||
private fun setupButtonListeners() {
|
||||
binding.buttonAddVariable.setOnClickListener {
|
||||
val varName = binding.variableNameInput.text.toString().trim()
|
||||
val varValue = binding.variableValueInput.text.toString().trim()
|
||||
|
||||
if (varName.isEmpty()) {
|
||||
showSnackbar(getString(R.string.freedreno_error_empty_name))
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
if (NativeFreedrenoConfig.setFreedrenoEnv(varName, varValue)) {
|
||||
showSnackbar(getString(R.string.freedreno_variable_added, varName))
|
||||
binding.variableNameInput.text?.clear()
|
||||
binding.variableValueInput.text?.clear()
|
||||
loadCurrentSettings()
|
||||
} else {
|
||||
showSnackbar(getString(R.string.freedreno_error_setting_variable))
|
||||
}
|
||||
}
|
||||
|
||||
binding.buttonClearAll.setOnClickListener {
|
||||
NativeFreedrenoConfig.clearAllFreedrenoEnv()
|
||||
showSnackbar(getString(R.string.freedreno_cleared_all))
|
||||
loadCurrentSettings()
|
||||
}
|
||||
|
||||
binding.buttonSave.setOnClickListener {
|
||||
if (isPerGameConfig) {
|
||||
NativeFreedrenoConfig.savePerGameConfig(game!!.programIdHex)
|
||||
showSnackbar(getString(R.string.freedreno_per_game_saved))
|
||||
} else {
|
||||
NativeFreedrenoConfig.saveFreedrenoConfig()
|
||||
showSnackbar(getString(R.string.freedreno_saved))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyPreset(preset: org.yuzu.yuzu_emu.utils.FreedrenoPreset) {
|
||||
// Clear all first for consistency
|
||||
NativeFreedrenoConfig.clearAllFreedrenoEnv()
|
||||
|
||||
// Apply all variables in the preset
|
||||
for ((varName, varValue) in preset.variables) {
|
||||
NativeFreedrenoConfig.setFreedrenoEnv(varName, varValue)
|
||||
}
|
||||
|
||||
showSnackbar(getString(R.string.freedreno_preset_applied, preset.name))
|
||||
loadCurrentSettings()
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSnackbar(message: String) {
|
||||
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class representing a Freedreno environment variable.
|
||||
*/
|
||||
data class FreedrenoVariable(
|
||||
val name: String,
|
||||
val value: String
|
||||
)
|
||||
@@ -325,20 +325,6 @@ class GamePropertiesFragment : Fragment() {
|
||||
)
|
||||
)
|
||||
}
|
||||
if (GpuDriverHelper.isAdrenoGpu()) {
|
||||
add(
|
||||
SubmenuProperty(
|
||||
R.string.freedreno_per_game_title,
|
||||
R.string.freedreno_per_game_description,
|
||||
R.drawable.ic_graphics,
|
||||
action = {
|
||||
val action = GamePropertiesFragmentDirections
|
||||
.actionPerGamePropertiesFragmentToFreedrenoSettingsFragment(args.game)
|
||||
binding.root.findNavController().navigate(action)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (!args.game.isHomebrew) {
|
||||
add(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
@@ -31,7 +31,6 @@ import org.yuzu.yuzu_emu.model.TaskState
|
||||
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||
import org.yuzu.yuzu_emu.utils.collect
|
||||
import java.io.BufferedOutputStream
|
||||
@@ -100,11 +99,11 @@ class InstallableFragment : Fragment() {
|
||||
},
|
||||
export = {
|
||||
val oldSaveDataFolder = File(
|
||||
NativeConfig.getSaveDir() +
|
||||
"${DirectoryInitialization.userDirectory}/nand" +
|
||||
NativeLibrary.getDefaultProfileSaveDataRoot(false)
|
||||
)
|
||||
val futureSaveDataFolder = File(
|
||||
NativeConfig.getSaveDir() +
|
||||
"${DirectoryInitialization.userDirectory}/nand" +
|
||||
NativeLibrary.getDefaultProfileSaveDataRoot(true)
|
||||
)
|
||||
if (!oldSaveDataFolder.exists() && !futureSaveDataFolder.exists()) {
|
||||
@@ -214,7 +213,7 @@ class InstallableFragment : Fragment() {
|
||||
}
|
||||
|
||||
val internalSaveFolder = File(
|
||||
"${NativeConfig.getSaveDir()}$baseSaveDir"
|
||||
"${DirectoryInitialization.userDirectory}/nand$baseSaveDir"
|
||||
)
|
||||
internalSaveFolder.deleteRecursively()
|
||||
internalSaveFolder.mkdir()
|
||||
@@ -291,7 +290,7 @@ class InstallableFragment : Fragment() {
|
||||
cacheSaveDir.mkdir()
|
||||
|
||||
val oldSaveDataFolder = File(
|
||||
NativeConfig.getSaveDir() +
|
||||
"${DirectoryInitialization.userDirectory}/nand" +
|
||||
NativeLibrary.getDefaultProfileSaveDataRoot(false)
|
||||
)
|
||||
if (oldSaveDataFolder.exists()) {
|
||||
@@ -299,7 +298,7 @@ class InstallableFragment : Fragment() {
|
||||
}
|
||||
|
||||
val futureSaveDataFolder = File(
|
||||
NativeConfig.getSaveDir() +
|
||||
"${DirectoryInitialization.userDirectory}/nand" +
|
||||
NativeLibrary.getDefaultProfileSaveDataRoot(true)
|
||||
)
|
||||
if (futureSaveDataFolder.exists()) {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -18,7 +15,6 @@ import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
@@ -61,7 +57,8 @@ class Game(
|
||||
}.zip"
|
||||
|
||||
val saveDir: String
|
||||
get() = NativeConfig.getSaveDir() + NativeLibrary.getSavePath(programId)
|
||||
get() = DirectoryInitialization.userDirectory + "/nand" +
|
||||
NativeLibrary.getSavePath(programId)
|
||||
|
||||
val addonDir: String
|
||||
get() = DirectoryInitialization.userDirectory + "/load/" + programIdHex + "/"
|
||||
|
||||
@@ -8,8 +8,6 @@ import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
@@ -52,7 +50,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
private val overlayJoysticks: MutableSet<InputOverlayDrawableJoystick> = HashSet()
|
||||
|
||||
private var inEditMode = false
|
||||
private var gamelessMode = false
|
||||
private var buttonBeingConfigured: InputOverlayDrawableButton? = null
|
||||
private var dpadBeingConfigured: InputOverlayDrawableDpad? = null
|
||||
private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null
|
||||
@@ -63,12 +60,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
private var hasMoved = false
|
||||
private val moveThreshold = 20f
|
||||
|
||||
private val gridPaint = Paint().apply {
|
||||
color = Color.argb(60, 255, 255, 255)
|
||||
strokeWidth = 1f
|
||||
style = Paint.Style.STROKE
|
||||
}
|
||||
|
||||
private lateinit var windowInsets: WindowInsets
|
||||
|
||||
var layout = OverlayLayout.Landscape
|
||||
@@ -100,12 +91,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
|
||||
override fun draw(canvas: Canvas) {
|
||||
super.draw(canvas)
|
||||
|
||||
// Draw grid when in edit mode and snap-to-grid is enabled
|
||||
if (inEditMode && BooleanSetting.OVERLAY_SNAP_TO_GRID.getBoolean()) {
|
||||
drawGrid(canvas)
|
||||
}
|
||||
|
||||
for (button in overlayButtons) {
|
||||
button.draw(canvas)
|
||||
}
|
||||
@@ -117,26 +102,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawGrid(canvas: Canvas) {
|
||||
val gridSize = IntSetting.OVERLAY_GRID_SIZE.getInt()
|
||||
val width = canvas.width
|
||||
val height = canvas.height
|
||||
|
||||
// Draw vertical lines
|
||||
var x = 0
|
||||
while (x <= width) {
|
||||
canvas.drawLine(x.toFloat(), 0f, x.toFloat(), height.toFloat(), gridPaint)
|
||||
x += gridSize
|
||||
}
|
||||
|
||||
// Draw horizontal lines
|
||||
var y = 0
|
||||
while (y <= height) {
|
||||
canvas.drawLine(0f, y.toFloat(), width.toFloat(), y.toFloat(), gridPaint)
|
||||
y += gridSize
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||
if (inEditMode) {
|
||||
return onTouchWhileEditing(event)
|
||||
@@ -703,19 +668,14 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshControls(gameless: Boolean = false) {
|
||||
// Store gameless mode if set to true
|
||||
if (gameless) {
|
||||
gamelessMode = true
|
||||
}
|
||||
|
||||
fun refreshControls() {
|
||||
// Remove all the overlay buttons from the HashSet.
|
||||
overlayButtons.clear()
|
||||
overlayDpads.clear()
|
||||
overlayJoysticks.clear()
|
||||
|
||||
// Add all the enabled overlay items back to the HashSet.
|
||||
if (gamelessMode || BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) {
|
||||
if (BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()) {
|
||||
addOverlayControls(layout)
|
||||
}
|
||||
invalidate()
|
||||
@@ -752,14 +712,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
if (!editMode) {
|
||||
scaleDialog?.dismiss()
|
||||
scaleDialog = null
|
||||
gamelessMode = false
|
||||
}
|
||||
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun isGamelessMode(): Boolean = gamelessMode
|
||||
|
||||
private fun showScaleDialog(
|
||||
button: InputOverlayDrawableButton?,
|
||||
dpad: InputOverlayDrawableDpad?,
|
||||
@@ -912,7 +867,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
// Increase this number every time there is a breaking change to every overlay layout
|
||||
const val OVERLAY_VERSION = 1
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -14,8 +11,6 @@ import android.graphics.drawable.BitmapDrawable
|
||||
import android.view.MotionEvent
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput.ButtonState
|
||||
import org.yuzu.yuzu_emu.features.input.model.NativeButton
|
||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
|
||||
|
||||
/**
|
||||
@@ -126,23 +121,11 @@ class InputOverlayDrawableButton(
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
controlPositionX += fingerPositionX - previousTouchX
|
||||
controlPositionY += fingerPositionY - previousTouchY
|
||||
|
||||
val finalX = if (BooleanSetting.OVERLAY_SNAP_TO_GRID.getBoolean()) {
|
||||
snapToGrid(controlPositionX)
|
||||
} else {
|
||||
controlPositionX
|
||||
}
|
||||
val finalY = if (BooleanSetting.OVERLAY_SNAP_TO_GRID.getBoolean()) {
|
||||
snapToGrid(controlPositionY)
|
||||
} else {
|
||||
controlPositionY
|
||||
}
|
||||
|
||||
setBounds(
|
||||
finalX,
|
||||
finalY,
|
||||
width + finalX,
|
||||
height + finalY
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
width + controlPositionX,
|
||||
height + controlPositionY
|
||||
)
|
||||
previousTouchX = fingerPositionX
|
||||
previousTouchY = fingerPositionY
|
||||
@@ -151,11 +134,6 @@ class InputOverlayDrawableButton(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun snapToGrid(value: Int): Int {
|
||||
val gridSize = IntSetting.OVERLAY_GRID_SIZE.getInt()
|
||||
return ((value + gridSize / 2) / gridSize) * gridSize
|
||||
}
|
||||
|
||||
fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
|
||||
defaultStateBitmap.setBounds(left, top, right, bottom)
|
||||
pressedStateBitmap.setBounds(left, top, right, bottom)
|
||||
|
||||
@@ -11,8 +11,6 @@ import android.graphics.drawable.BitmapDrawable
|
||||
import android.view.MotionEvent
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput.ButtonState
|
||||
import org.yuzu.yuzu_emu.features.input.model.NativeButton
|
||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||
|
||||
/**
|
||||
* Custom [BitmapDrawable] that is capable
|
||||
@@ -231,23 +229,11 @@ class InputOverlayDrawableDpad(
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
controlPositionX += fingerPositionX - previousTouchX
|
||||
controlPositionY += fingerPositionY - previousTouchY
|
||||
|
||||
val finalX = if (BooleanSetting.OVERLAY_SNAP_TO_GRID.getBoolean()) {
|
||||
snapToGrid(controlPositionX)
|
||||
} else {
|
||||
controlPositionX
|
||||
}
|
||||
val finalY = if (BooleanSetting.OVERLAY_SNAP_TO_GRID.getBoolean()) {
|
||||
snapToGrid(controlPositionY)
|
||||
} else {
|
||||
controlPositionY
|
||||
}
|
||||
|
||||
setBounds(
|
||||
finalX,
|
||||
finalY,
|
||||
width + finalX,
|
||||
height + finalY
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
width + controlPositionX,
|
||||
height + controlPositionY
|
||||
)
|
||||
previousTouchX = fingerPositionX
|
||||
previousTouchY = fingerPositionY
|
||||
@@ -256,11 +242,6 @@ class InputOverlayDrawableDpad(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun snapToGrid(value: Int): Int {
|
||||
val gridSize = IntSetting.OVERLAY_GRID_SIZE.getInt()
|
||||
return ((value + gridSize / 2) / gridSize) * gridSize
|
||||
}
|
||||
|
||||
fun setPosition(x: Int, y: Int) {
|
||||
controlPositionX = x
|
||||
controlPositionY = y
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.yuzu.yuzu_emu.features.input.NativeInput.ButtonState
|
||||
import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
|
||||
import org.yuzu.yuzu_emu.features.input.model.NativeButton
|
||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||
|
||||
/**
|
||||
* Custom [BitmapDrawable] that is capable
|
||||
@@ -214,37 +213,25 @@ class InputOverlayDrawableJoystick(
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
controlPositionX += fingerPositionX - previousTouchX
|
||||
controlPositionY += fingerPositionY - previousTouchY
|
||||
|
||||
val finalX = if (BooleanSetting.OVERLAY_SNAP_TO_GRID.getBoolean()) {
|
||||
snapToGrid(controlPositionX)
|
||||
} else {
|
||||
controlPositionX
|
||||
}
|
||||
val finalY = if (BooleanSetting.OVERLAY_SNAP_TO_GRID.getBoolean()) {
|
||||
snapToGrid(controlPositionY)
|
||||
} else {
|
||||
controlPositionY
|
||||
}
|
||||
|
||||
bounds = Rect(
|
||||
finalX,
|
||||
finalY,
|
||||
outerBitmap.intrinsicWidth + finalX,
|
||||
outerBitmap.intrinsicHeight + finalY
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
outerBitmap.intrinsicWidth + controlPositionX,
|
||||
outerBitmap.intrinsicHeight + controlPositionY
|
||||
)
|
||||
virtBounds = Rect(
|
||||
finalX,
|
||||
finalY,
|
||||
outerBitmap.intrinsicWidth + finalX,
|
||||
outerBitmap.intrinsicHeight + finalY
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
outerBitmap.intrinsicWidth + controlPositionX,
|
||||
outerBitmap.intrinsicHeight + controlPositionY
|
||||
)
|
||||
setInnerBounds()
|
||||
bounds = Rect(
|
||||
Rect(
|
||||
finalX,
|
||||
finalY,
|
||||
outerBitmap.intrinsicWidth + finalX,
|
||||
outerBitmap.intrinsicHeight + finalY
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
outerBitmap.intrinsicWidth + controlPositionX,
|
||||
outerBitmap.intrinsicHeight + controlPositionY
|
||||
)
|
||||
)
|
||||
previousTouchX = fingerPositionX
|
||||
@@ -255,11 +242,6 @@ class InputOverlayDrawableJoystick(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun snapToGrid(value: Int): Int {
|
||||
val gridSize = IntSetting.OVERLAY_GRID_SIZE.getInt()
|
||||
return ((value + gridSize / 2) / gridSize) * gridSize
|
||||
}
|
||||
|
||||
private fun setInnerBounds() {
|
||||
var x = virtBounds.centerX() + (xAxis * (virtBounds.width() / 2)).toInt()
|
||||
var y = virtBounds.centerY() + (yAxis * (virtBounds.height() / 2)).toInt()
|
||||
|
||||
@@ -456,7 +456,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") }
|
||||
|
||||
val firmwarePath =
|
||||
File(NativeConfig.getNandDir() + "/system/Contents/registered/")
|
||||
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
|
||||
val cacheFirmwareDir = File("${cacheDir.path}/registered/")
|
||||
|
||||
ProgressDialogFragment.newInstance(
|
||||
@@ -499,7 +499,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
|
||||
fun uninstallFirmware() {
|
||||
val firmwarePath =
|
||||
File(NativeConfig.getNandDir() + "/system/Contents/registered/")
|
||||
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
|
||||
ProgressDialogFragment.newInstance(
|
||||
this,
|
||||
R.string.firmware_uninstalling
|
||||
|
||||
@@ -23,16 +23,10 @@ object GpuDriverHelper {
|
||||
private const val META_JSON_FILENAME = "meta.json"
|
||||
private var fileRedirectionPath: String? = null
|
||||
var driverInstallationPath: String? = null
|
||||
internal var hookLibPath: String? = null
|
||||
private var hookLibPath: String? = null
|
||||
|
||||
val driverStoragePath get() = DirectoryInitialization.userDirectory!! + "/gpu_drivers/"
|
||||
|
||||
fun initializeFreedrenoConfigEarly() {
|
||||
NativeFreedrenoConfig.setFreedrenoBasePath(YuzuApplication.appContext.cacheDir.absolutePath)
|
||||
NativeFreedrenoConfig.initializeFreedrenoConfig()
|
||||
NativeFreedrenoConfig.reloadFreedrenoConfig()
|
||||
}
|
||||
|
||||
fun initializeDriverParameters() {
|
||||
try {
|
||||
// Initialize the file redirection directory.
|
||||
@@ -46,9 +40,11 @@ object GpuDriverHelper {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
|
||||
// Initialize directories.
|
||||
initializeDirectories()
|
||||
|
||||
// Initialize hook libraries directory.
|
||||
hookLibPath = YuzuApplication.appContext.applicationInfo.nativeLibraryDir + "/"
|
||||
NativeFreedrenoConfig.reloadFreedrenoConfig()
|
||||
|
||||
// Initialize GPU driver.
|
||||
NativeLibrary.initializeGpuDriver(
|
||||
@@ -215,17 +211,9 @@ object GpuDriverHelper {
|
||||
|
||||
external fun getGpuModel(
|
||||
surface: Surface = Surface(SurfaceTexture(true)),
|
||||
hookLibPath: String
|
||||
hookLibPath: String = GpuDriverHelper.hookLibPath!!
|
||||
): String?
|
||||
|
||||
fun isAdrenoGpu(): Boolean {
|
||||
return try {
|
||||
supportsCustomDriverLoading()
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the custom driver metadata to retrieve the name.
|
||||
val installedCustomDriverData: GpuDriverMetadata
|
||||
get() = GpuDriverMetadata(File(driverInstallationPath + META_JSON_FILENAME))
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -186,22 +183,4 @@ object NativeConfig {
|
||||
*/
|
||||
@Synchronized
|
||||
external fun saveControlPlayerValues()
|
||||
|
||||
/**
|
||||
* Directory paths getters and setters
|
||||
*/
|
||||
@Synchronized
|
||||
external fun getSaveDir(): String
|
||||
@Synchronized
|
||||
external fun getDefaultSaveDir(): String
|
||||
@Synchronized
|
||||
external fun setSaveDir(path: String)
|
||||
@Synchronized
|
||||
external fun getNandDir(): String
|
||||
@Synchronized
|
||||
external fun setNandDir(path: String)
|
||||
@Synchronized
|
||||
external fun getSdmcDir(): String
|
||||
@Synchronized
|
||||
external fun setSdmcDir(path: String)
|
||||
}
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
|
||||
/**
|
||||
* Provides access to Freedreno/Turnip driver configuration through JNI bindings.
|
||||
*
|
||||
* This class allows Java/Kotlin code to configure Freedreno environment variables
|
||||
* for the GPU driver (Turnip/Freedreno) that runs in the emulator on Android.
|
||||
*
|
||||
* Variables must be set BEFORE starting emulation for them to take effect.
|
||||
*
|
||||
* See https://docs.mesa3d.org/drivers/freedreno.html for documentation.
|
||||
*/
|
||||
object NativeFreedrenoConfig {
|
||||
|
||||
@Synchronized
|
||||
external fun setFreedrenoBasePath(basePath: String)
|
||||
|
||||
@Synchronized
|
||||
external fun initializeFreedrenoConfig()
|
||||
|
||||
@Synchronized
|
||||
external fun saveFreedrenoConfig()
|
||||
|
||||
@Synchronized
|
||||
external fun reloadFreedrenoConfig()
|
||||
|
||||
@Synchronized
|
||||
external fun setFreedrenoEnv(varName: String, value: String): Boolean
|
||||
|
||||
@Synchronized
|
||||
external fun getFreedrenoEnv(varName: String): String
|
||||
|
||||
@Synchronized
|
||||
external fun isFreedrenoEnvSet(varName: String): Boolean
|
||||
|
||||
@Synchronized
|
||||
external fun clearFreedrenoEnv(varName: String): Boolean
|
||||
|
||||
@Synchronized
|
||||
external fun clearAllFreedrenoEnv()
|
||||
|
||||
@Synchronized
|
||||
external fun getFreedrenoEnvSummary(): String
|
||||
|
||||
@Synchronized
|
||||
external fun setCurrentProgramId(programId: String)
|
||||
|
||||
@Synchronized
|
||||
external fun loadPerGameConfig(programId: String): Boolean
|
||||
|
||||
@Synchronized
|
||||
external fun loadPerGameConfigWithGlobalFallback(programId: String): Boolean
|
||||
|
||||
@Synchronized
|
||||
external fun savePerGameConfig(programId: String): Boolean
|
||||
|
||||
@Synchronized
|
||||
external fun hasPerGameConfig(programId: String): Boolean
|
||||
|
||||
@Synchronized
|
||||
external fun deletePerGameConfig(programId: String): Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class representing a Freedreno preset configuration.
|
||||
* Presets are commonly used debugging/profiling configurations.
|
||||
*/
|
||||
data class FreedrenoPreset(
|
||||
val name: String, // Display name (e.g., "Debug - CPU Memory")
|
||||
val description: String, // Description of what this preset does
|
||||
val icon: String, // Icon identifier
|
||||
val variables: Map<String, String> // Map of env vars to set
|
||||
)
|
||||
|
||||
/**
|
||||
* Predefined Freedreno presets for quick configuration.
|
||||
*/
|
||||
object FreedrenoPresets {
|
||||
|
||||
val DEBUG_CPU_MEMORY = FreedrenoPreset(
|
||||
name = "Debug - CPU Memory",
|
||||
description = "Use CPU memory (slower but more stable)",
|
||||
icon = "ic_debug_cpu",
|
||||
variables = mapOf(
|
||||
"TU_DEBUG" to "sysmem"
|
||||
)
|
||||
)
|
||||
|
||||
val DEBUG_UBWC_DISABLED = FreedrenoPreset(
|
||||
name = "Debug - No UBWC",
|
||||
description = "Disable UBWC compression for debugging",
|
||||
icon = "ic_debug_ubwc",
|
||||
variables = mapOf(
|
||||
"TU_DEBUG" to "noubwc"
|
||||
)
|
||||
)
|
||||
|
||||
val DEBUG_NO_BINNING = FreedrenoPreset(
|
||||
name = "Debug - No Binning",
|
||||
description = "Disable binning optimization",
|
||||
icon = "ic_debug_bin",
|
||||
variables = mapOf(
|
||||
"TU_DEBUG" to "nobin"
|
||||
)
|
||||
)
|
||||
|
||||
val CAPTURE_RENDERPASS = FreedrenoPreset(
|
||||
name = "Capture - Renderpass",
|
||||
description = "Capture command stream data for debugging",
|
||||
icon = "ic_capture",
|
||||
variables = mapOf(
|
||||
"FD_RD_DUMP" to "enable"
|
||||
)
|
||||
)
|
||||
|
||||
val CAPTURE_FRAMES = FreedrenoPreset(
|
||||
name = "Capture - First 100 Frames",
|
||||
description = "Capture command stream for first 100 frames only",
|
||||
icon = "ic_capture",
|
||||
variables = mapOf(
|
||||
"FD_RD_DUMP" to "enable",
|
||||
"FD_RD_DUMP_FRAMES" to "0-100"
|
||||
)
|
||||
)
|
||||
|
||||
val SHADER_DEBUG = FreedrenoPreset(
|
||||
name = "Shader Debug",
|
||||
description = "Enable IR3 shader compiler debugging",
|
||||
icon = "ic_shader",
|
||||
variables = mapOf(
|
||||
"IR3_SHADER_DEBUG" to "nouboopt,spillall"
|
||||
)
|
||||
)
|
||||
|
||||
val GPU_HANG_TRACE = FreedrenoPreset(
|
||||
name = "GPU Hang Trace",
|
||||
description = "Trace GPU progress for debugging hangs",
|
||||
icon = "ic_hang_trace",
|
||||
variables = mapOf(
|
||||
"TU_BREADCRUMBS" to "1"
|
||||
)
|
||||
)
|
||||
|
||||
val PERFORMANCE_DEFAULT = FreedrenoPreset(
|
||||
name = "Performance - Default",
|
||||
description = "Clear all debug options for performance",
|
||||
icon = "ic_performance",
|
||||
variables = emptyMap() // Clears all when applied
|
||||
)
|
||||
|
||||
val ALL_PRESETS = listOf(
|
||||
DEBUG_CPU_MEMORY,
|
||||
DEBUG_UBWC_DISABLED,
|
||||
DEBUG_NO_BINNING,
|
||||
CAPTURE_RENDERPASS,
|
||||
CAPTURE_FRAMES,
|
||||
SHADER_DEBUG,
|
||||
GPU_HANG_TRACE,
|
||||
PERFORMANCE_DEFAULT
|
||||
)
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
|
||||
import android.net.Uri
|
||||
import android.provider.DocumentsContract
|
||||
import java.io.File
|
||||
|
||||
object PathUtil {
|
||||
|
||||
/**
|
||||
* Converts a content:// URI from the Storage Access Framework to a real filesystem path.
|
||||
*/
|
||||
fun getPathFromUri(uri: Uri): String? {
|
||||
val docId = try {
|
||||
DocumentsContract.getTreeDocumentId(uri)
|
||||
} catch (_: Exception) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (docId.startsWith("primary:")) {
|
||||
val relativePath = docId.substringAfter(":")
|
||||
val primaryStoragePath = android.os.Environment.getExternalStorageDirectory().absolutePath
|
||||
return "$primaryStoragePath/$relativePath"
|
||||
}
|
||||
|
||||
// external SD cards and other volumes)
|
||||
val storageIdString = docId.substringBefore(":")
|
||||
val removablePath = getRemovableStoragePath(storageIdString)
|
||||
if (removablePath != null) {
|
||||
return "$removablePath/${docId.substringAfter(":")}"
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a path is a valid, writable directory.
|
||||
* Creates the directory if it doesn't exist.
|
||||
*/
|
||||
fun validateDirectory(path: String): Boolean {
|
||||
val dir = File(path)
|
||||
|
||||
if (!dir.exists()) {
|
||||
if (!dir.mkdirs()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return dir.isDirectory && dir.canWrite()
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a directory recursively from source to destination.
|
||||
*/
|
||||
fun copyDirectory(source: File, destination: File, overwrite: Boolean = true): Boolean {
|
||||
return try {
|
||||
source.copyRecursively(destination, overwrite)
|
||||
true
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a directory has any content.
|
||||
*/
|
||||
fun hasContent(path: String): Boolean {
|
||||
val dir = File(path)
|
||||
return dir.exists() && dir.listFiles()?.isNotEmpty() == true
|
||||
}
|
||||
|
||||
|
||||
fun truncatePathForDisplay(path: String, maxLength: Int = 40): String {
|
||||
return if (path.length > maxLength) {
|
||||
"...${path.takeLast(maxLength - 3)}"
|
||||
} else {
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
// This really shouldn't be necessary, but the Android API seemingly
|
||||
// doesn't have a way of doing this?
|
||||
// Apparently, on certain devices the mount location can vary, so add
|
||||
// extra cases here if we discover any new ones.
|
||||
fun getRemovableStoragePath(idString: String): String? {
|
||||
var pathFile: File
|
||||
|
||||
pathFile = File("/mnt/media_rw/$idString");
|
||||
if (pathFile.exists()) {
|
||||
return pathFile.absolutePath
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -35,14 +35,6 @@ class GradientBorderCardView @JvmOverloads constructor(
|
||||
updateThemeState()
|
||||
}
|
||||
|
||||
private fun updateBorderState() {
|
||||
val shouldShow = isPressed || isFocused || isSelected
|
||||
if (showGradientBorder != shouldShow) {
|
||||
showGradientBorder = shouldShow
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateThemeState() {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val themeIndex = try {
|
||||
@@ -51,7 +43,6 @@ class GradientBorderCardView @JvmOverloads constructor(
|
||||
0 // Default to Eden theme if error
|
||||
}
|
||||
isEdenTheme = themeIndex == 0
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
@@ -102,22 +93,27 @@ class GradientBorderCardView @JvmOverloads constructor(
|
||||
|
||||
override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
|
||||
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
|
||||
updateBorderState()
|
||||
showGradientBorder = gainFocus
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun setSelected(selected: Boolean) {
|
||||
super.setSelected(selected)
|
||||
updateBorderState()
|
||||
showGradientBorder = selected
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun setPressed(pressed: Boolean) {
|
||||
super.setPressed(pressed)
|
||||
updateBorderState()
|
||||
if (pressed) {
|
||||
showGradientBorder = true
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
if (showGradientBorder) {
|
||||
if (showGradientBorder && !isPressed) {
|
||||
canvas.drawPath(borderPath, borderPaint)
|
||||
}
|
||||
}
|
||||
@@ -125,5 +121,6 @@ class GradientBorderCardView @JvmOverloads constructor(
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
updateThemeState()
|
||||
requestLayout()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ add_library(yuzu-android SHARED
|
||||
native.cpp
|
||||
native.h
|
||||
native_config.cpp
|
||||
native_freedreno.cpp
|
||||
android_settings.cpp
|
||||
game_metadata.cpp
|
||||
native_log.cpp
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <common/fs/path_util.h>
|
||||
#include <common/logging/log.h>
|
||||
#include <input_common/main.h>
|
||||
#include "android_config.h"
|
||||
@@ -69,24 +68,6 @@ void AndroidConfig::ReadPathValues() {
|
||||
}
|
||||
EndArray();
|
||||
|
||||
const auto nand_dir_setting = ReadStringSetting(std::string("nand_directory"));
|
||||
if (!nand_dir_setting.empty()) {
|
||||
Common::FS::SetEdenPath(Common::FS::EdenPath::NANDDir, nand_dir_setting);
|
||||
}
|
||||
|
||||
const auto sdmc_dir_setting = ReadStringSetting(std::string("sdmc_directory"));
|
||||
if (!sdmc_dir_setting.empty()) {
|
||||
Common::FS::SetEdenPath(Common::FS::EdenPath::SDMCDir, sdmc_dir_setting);
|
||||
}
|
||||
|
||||
const auto save_dir_setting = ReadStringSetting(std::string("save_directory"));
|
||||
if (save_dir_setting.empty()) {
|
||||
Common::FS::SetEdenPath(Common::FS::EdenPath::SaveDir,
|
||||
Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir));
|
||||
} else {
|
||||
Common::FS::SetEdenPath(Common::FS::EdenPath::SaveDir, save_dir_setting);
|
||||
}
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
@@ -241,26 +222,6 @@ void AndroidConfig::SavePathValues() {
|
||||
}
|
||||
EndArray();
|
||||
|
||||
// Save custom NAND directory
|
||||
const auto nand_path = Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir);
|
||||
WriteStringSetting(std::string("nand_directory"), nand_path,
|
||||
std::make_optional(std::string("")));
|
||||
|
||||
// Save custom SDMC directory
|
||||
const auto sdmc_path = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
|
||||
WriteStringSetting(std::string("sdmc_directory"), sdmc_path,
|
||||
std::make_optional(std::string("")));
|
||||
|
||||
// Save custom save directory
|
||||
const auto save_path = Common::FS::GetEdenPathString(Common::FS::EdenPath::SaveDir);
|
||||
if (save_path == nand_path) {
|
||||
WriteStringSetting(std::string("save_directory"), std::string(""),
|
||||
std::make_optional(std::string("")));
|
||||
} else {
|
||||
WriteStringSetting(std::string("save_directory"), save_path,
|
||||
std::make_optional(std::string("")));
|
||||
}
|
||||
|
||||
EndGroup();
|
||||
}
|
||||
|
||||
|
||||
@@ -146,10 +146,6 @@ namespace AndroidSettings {
|
||||
|
||||
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
|
||||
Settings::Category::Overlay};
|
||||
Settings::Setting<bool> overlay_snap_to_grid{linkage, false, "overlay_snap_to_grid",
|
||||
Settings::Category::Overlay};
|
||||
Settings::Setting<s32> overlay_grid_size{linkage, 32, "overlay_grid_size",
|
||||
Settings::Category::Overlay};
|
||||
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen",
|
||||
Settings::Category::Overlay};
|
||||
Settings::Setting<s32> lock_drawer{linkage, false, "lock_drawer",
|
||||
|
||||
@@ -730,28 +730,11 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
|
||||
return false;
|
||||
}
|
||||
|
||||
void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz,
|
||||
void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* env, jclass clazz,
|
||||
jstring hook_lib_dir,
|
||||
jstring custom_driver_dir,
|
||||
jstring custom_driver_name,
|
||||
jstring file_redirect_dir) {
|
||||
// Log active Freedreno environment variables
|
||||
const char* tu_debug = getenv("TU_DEBUG");
|
||||
const char* fd_debug = getenv("FD_MESA_DEBUG");
|
||||
const char* ir3_debug = getenv("IR3_SHADER_DEBUG");
|
||||
const char* fd_rd_dump = getenv("FD_RD_DUMP");
|
||||
const char* tu_breadcrumbs = getenv("TU_BREADCRUMBS");
|
||||
|
||||
if (tu_debug || fd_debug || ir3_debug || fd_rd_dump || tu_breadcrumbs) {
|
||||
LOG_INFO(Frontend, "[Freedreno] Initializing GPU driver with configuration:");
|
||||
if (tu_debug) LOG_INFO(Frontend, "[Freedreno] TU_DEBUG={}", tu_debug);
|
||||
if (fd_debug) LOG_INFO(Frontend, "[Freedreno] FD_MESA_DEBUG={}", fd_debug);
|
||||
if (ir3_debug) LOG_INFO(Frontend, "[Freedreno] IR3_SHADER_DEBUG={}", ir3_debug);
|
||||
if (fd_rd_dump) LOG_INFO(Frontend, "[Freedreno] FD_RD_DUMP={}", fd_rd_dump);
|
||||
if (tu_breadcrumbs) LOG_INFO(Frontend, "[Freedreno] TU_BREADCRUMBS={}", tu_breadcrumbs);
|
||||
}
|
||||
|
||||
EmulationSession::GetInstance().InitializeGpuDriver(
|
||||
Common::Android::GetJString(env, hook_lib_dir),
|
||||
Common::Android::GetJString(env, custom_driver_dir),
|
||||
@@ -1183,8 +1166,11 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerInit(JNIEnv* env, jobject obj) {
|
||||
// for some reason the full user directory isnt initialized in Android, so we need to create it
|
||||
const auto play_time_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::PlayTimeDir);
|
||||
if (!Common::FS::IsDir(play_time_dir) && !Common::FS::CreateDir(play_time_dir))
|
||||
LOG_WARNING(Frontend, "Failed to create play time directory");
|
||||
if (!Common::FS::IsDir(play_time_dir)) {
|
||||
if (!Common::FS::CreateDir(play_time_dir)) {
|
||||
LOG_WARNING(Frontend, "Failed to create play time directory");
|
||||
}
|
||||
}
|
||||
|
||||
play_time_manager = std::make_unique<PlayTime::PlayTimeManager>();
|
||||
}
|
||||
@@ -1197,16 +1183,13 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerStart(JNIEnv* env, job
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerStop(JNIEnv* env, jobject obj) {
|
||||
if (play_time_manager)
|
||||
play_time_manager->Stop();
|
||||
play_time_manager->Stop();
|
||||
}
|
||||
|
||||
jlong Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerGetPlayTime(JNIEnv* env, jobject obj, jstring jprogramId) {
|
||||
if (play_time_manager) {
|
||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
return play_time_manager->GetPlayTime(program_id);
|
||||
}
|
||||
return 0UL;
|
||||
jlong Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerGetPlayTime(JNIEnv* env, jobject obj,
|
||||
jstring jprogramId) {
|
||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
return play_time_manager->GetPlayTime(program_id);
|
||||
}
|
||||
|
||||
jlong Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerGetCurrentTitleId(JNIEnv* env,
|
||||
@@ -1216,17 +1199,17 @@ jlong Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerGetCurrentTitleId(JNI
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerResetProgramPlayTime(JNIEnv* env, jobject obj,
|
||||
jstring jprogramId) {
|
||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
if (play_time_manager) {
|
||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
play_time_manager->ResetProgramPlayTime(program_id);
|
||||
}
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerSetPlayTime(JNIEnv* env, jobject obj,
|
||||
jstring jprogramId, jlong playTimeSeconds) {
|
||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
if (play_time_manager) {
|
||||
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
|
||||
play_time_manager->SetPlayTime(program_id, u64(playTimeSeconds));
|
||||
play_time_manager->SetPlayTime(program_id, static_cast<u64>(playTimeSeconds));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1406,12 +1389,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
|
||||
const auto user_id = manager.GetUser(static_cast<std::size_t>(0));
|
||||
ASSERT(user_id);
|
||||
|
||||
const auto saveDir = Common::FS::GetEdenPath(Common::FS::EdenPath::SaveDir);
|
||||
auto vfsSaveDir = system.GetFilesystem()->OpenDirectory(Common::FS::PathToUTF8String(saveDir),
|
||||
const auto nandDir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir);
|
||||
auto vfsNandDir = system.GetFilesystem()->OpenDirectory(Common::FS::PathToUTF8String(nandDir),
|
||||
FileSys::OpenMode::Read);
|
||||
|
||||
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
||||
{}, vfsSaveDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
|
||||
{}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
|
||||
user_id->AsU128(), 0);
|
||||
return Common::Android::ToJString(env, user_save_data_path);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <string>
|
||||
|
||||
#include <jni.h>
|
||||
#include <common/fs/path_util.h>
|
||||
|
||||
#include "android_config.h"
|
||||
#include "android_settings.h"
|
||||
@@ -546,39 +545,4 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveControlPlayerValues(JNIEnv*
|
||||
}
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getSaveDir(JNIEnv* env, jobject obj) {
|
||||
return Common::Android::ToJString(env,
|
||||
Common::FS::GetEdenPathString(Common::FS::EdenPath::SaveDir));
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDefaultSaveDir(JNIEnv* env, jobject obj) {
|
||||
return Common::Android::ToJString(env,
|
||||
Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir));
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setSaveDir(JNIEnv* env, jobject obj, jstring jpath) {
|
||||
auto path = Common::Android::GetJString(env, jpath);
|
||||
Common::FS::SetEdenPath(Common::FS::EdenPath::SaveDir, path);
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getNandDir(JNIEnv* env, jobject obj) {
|
||||
return Common::Android::ToJString(env,
|
||||
Common::FS::GetEdenPathString(Common::FS::EdenPath::NANDDir));
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setNandDir(JNIEnv* env, jobject obj, jstring jpath) {
|
||||
auto path = Common::Android::GetJString(env, jpath);
|
||||
Common::FS::SetEdenPath(Common::FS::EdenPath::NANDDir, path);
|
||||
}
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getSdmcDir(JNIEnv* env, jobject obj) {
|
||||
return Common::Android::ToJString(env,
|
||||
Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir));
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setSdmcDir(JNIEnv* env, jobject obj, jstring jpath) {
|
||||
auto path = Common::Android::GetJString(env, jpath);
|
||||
Common::FS::SetEdenPath(Common::FS::EdenPath::SDMCDir, path);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -1,477 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* @file native_freedreno.cpp
|
||||
* @brief JNI bindings for Freedreno/Turnip GPU driver configuration.
|
||||
*
|
||||
* Provides runtime configuration of Mesa Freedreno environment variables
|
||||
* for the Turnip Vulkan driver on Adreno GPUs.
|
||||
*
|
||||
* @see https://docs.mesa3d.org/drivers/freedreno.html
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "common/android/android_common.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "native.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct FreedrenoConfig {
|
||||
std::map<std::string, std::string> env_vars;
|
||||
std::string config_file_path;
|
||||
};
|
||||
|
||||
std::unique_ptr<FreedrenoConfig> g_config;
|
||||
std::string g_base_path;
|
||||
std::string g_current_program_id;
|
||||
|
||||
constexpr const char* kConfigFileName = ".freedreno.conf";
|
||||
constexpr const char* kPerGameConfigDir = "freedreno_games";
|
||||
|
||||
void LogActiveVariables() {
|
||||
if (!g_config || g_config->env_vars.empty()) {
|
||||
return;
|
||||
}
|
||||
for (const auto& [key, value] : g_config->env_vars) {
|
||||
LOG_INFO(Frontend, "[Freedreno] {}={}", key, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool ApplyEnvironmentVariable(const std::string& key, const std::string& value) {
|
||||
if (setenv(key.c_str(), value.c_str(), 1) != 0) {
|
||||
LOG_ERROR(Frontend, "[Freedreno] Failed to set {}={} (errno: {})", key, value, errno);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClearAllEnvironmentVariables() {
|
||||
if (!g_config) return;
|
||||
for (const auto& [key, value] : g_config->env_vars) {
|
||||
unsetenv(key.c_str());
|
||||
}
|
||||
g_config->env_vars.clear();
|
||||
}
|
||||
|
||||
std::string GetConfigPath() {
|
||||
return g_base_path + "/" + kConfigFileName;
|
||||
}
|
||||
|
||||
std::string GetPerGameConfigPath(const std::string& program_id) {
|
||||
return g_base_path + "/" + kPerGameConfigDir + "/" + program_id + ".conf";
|
||||
}
|
||||
|
||||
void EnsurePerGameConfigDir() {
|
||||
std::string dir_path = g_base_path + "/" + kPerGameConfigDir;
|
||||
mkdir(dir_path.c_str(), 0755);
|
||||
}
|
||||
|
||||
bool LoadConfigFromFile(const std::string& config_path) {
|
||||
if (!g_config) return false;
|
||||
|
||||
FILE* file = fopen(config_path.c_str(), "r");
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char line[512];
|
||||
int count = 0;
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
size_t len = strlen(line);
|
||||
if (len > 0 && line[len - 1] == '\n') {
|
||||
line[len - 1] = '\0';
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len == 0 || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* eq = strchr(line, '=');
|
||||
if (!eq) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string key(line, eq - line);
|
||||
std::string value(eq + 1);
|
||||
|
||||
g_config->env_vars[key] = value;
|
||||
ApplyEnvironmentVariable(key, value);
|
||||
count++;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
bool SaveConfigToFile(const std::string& config_path) {
|
||||
if (!g_config) return false;
|
||||
|
||||
FILE* file = fopen(config_path.c_str(), "w");
|
||||
if (!file) {
|
||||
LOG_ERROR(Frontend, "[Freedreno] Failed to open {} for writing", config_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(file, "# Freedreno/Turnip Configuration\n");
|
||||
fprintf(file, "# Auto-generated by Eden Emulator\n\n");
|
||||
|
||||
for (const auto& [key, value] : g_config->env_vars) {
|
||||
fprintf(file, "%s=%s\n", key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_setFreedrenoBasePath(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jbasePath) {
|
||||
g_base_path = Common::Android::GetJString(env, jbasePath);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_initializeFreedrenoConfig(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||
if (!g_config) {
|
||||
g_config = std::make_unique<FreedrenoConfig>();
|
||||
LOG_INFO(Frontend, "[Freedreno] Configuration system initialized");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_saveFreedrenoConfig(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||
if (!g_config) {
|
||||
LOG_WARNING(Frontend, "[Freedreno] Cannot save: not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string config_path = GetConfigPath();
|
||||
FILE* file = fopen(config_path.c_str(), "w");
|
||||
if (!file) {
|
||||
LOG_ERROR(Frontend, "[Freedreno] Failed to open {} for writing", config_path);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(file, "# Freedreno/Turnip Configuration\n");
|
||||
fprintf(file, "# Auto-generated by Eden Emulator\n\n");
|
||||
|
||||
for (const auto& [key, value] : g_config->env_vars) {
|
||||
fprintf(file, "%s=%s\n", key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
g_config->config_file_path = config_path;
|
||||
|
||||
LOG_INFO(Frontend, "[Freedreno] Saved {} variables to {}",
|
||||
g_config->env_vars.size(), config_path);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_reloadFreedrenoConfig(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||
if (!g_config) {
|
||||
LOG_WARNING(Frontend, "[Freedreno] Cannot reload: not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string config_path = GetConfigPath();
|
||||
g_config->env_vars.clear();
|
||||
|
||||
FILE* file = fopen(config_path.c_str(), "r");
|
||||
if (!file) {
|
||||
LOG_DEBUG(Frontend, "[Freedreno] No config file found at {}", config_path);
|
||||
return;
|
||||
}
|
||||
|
||||
char line[512];
|
||||
while (fgets(line, sizeof(line), file)) {
|
||||
// Remove trailing newline
|
||||
size_t len = strlen(line);
|
||||
if (len > 0 && line[len - 1] == '\n') {
|
||||
line[len - 1] = '\0';
|
||||
len--;
|
||||
}
|
||||
|
||||
// Skip empty lines and comments
|
||||
if (len == 0 || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse key=value
|
||||
const char* eq = strchr(line, '=');
|
||||
if (!eq) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string key(line, eq - line);
|
||||
std::string value(eq + 1);
|
||||
|
||||
g_config->env_vars[key] = value;
|
||||
ApplyEnvironmentVariable(key, value);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
g_config->config_file_path = config_path;
|
||||
|
||||
if (!g_config->env_vars.empty()) {
|
||||
LOG_INFO(Frontend, "[Freedreno] Loaded {} variables:", g_config->env_vars.size());
|
||||
LogActiveVariables();
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_setFreedrenoEnv(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jvarName, jstring jvalue) {
|
||||
if (!g_config) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
auto var_name = Common::Android::GetJString(env, jvarName);
|
||||
auto value = Common::Android::GetJString(env, jvalue);
|
||||
|
||||
if (var_name.empty()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
g_config->env_vars[var_name] = value;
|
||||
|
||||
if (!ApplyEnvironmentVariable(var_name, value)) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
LOG_INFO(Frontend, "[Freedreno] Set {}={}", var_name, value);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_getFreedrenoEnv(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jvarName) {
|
||||
if (!g_config) {
|
||||
return env->NewStringUTF("");
|
||||
}
|
||||
|
||||
auto var_name = Common::Android::GetJString(env, jvarName);
|
||||
auto it = g_config->env_vars.find(var_name);
|
||||
|
||||
if (it != g_config->env_vars.end()) {
|
||||
return env->NewStringUTF(it->second.c_str());
|
||||
}
|
||||
|
||||
return env->NewStringUTF("");
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_isFreedrenoEnvSet(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jvarName) {
|
||||
if (!g_config) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
auto var_name = Common::Android::GetJString(env, jvarName);
|
||||
auto it = g_config->env_vars.find(var_name);
|
||||
|
||||
return (it != g_config->env_vars.end() && !it->second.empty()) ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_clearFreedrenoEnv(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jvarName) {
|
||||
if (!g_config) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
auto var_name = Common::Android::GetJString(env, jvarName);
|
||||
auto it = g_config->env_vars.find(var_name);
|
||||
|
||||
if (it != g_config->env_vars.end()) {
|
||||
g_config->env_vars.erase(it);
|
||||
unsetenv(var_name.c_str());
|
||||
LOG_INFO(Frontend, "[Freedreno] Cleared {}", var_name);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_clearAllFreedrenoEnv(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||
if (!g_config) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& [key, value] : g_config->env_vars) {
|
||||
unsetenv(key.c_str());
|
||||
}
|
||||
|
||||
size_t count = g_config->env_vars.size();
|
||||
g_config->env_vars.clear();
|
||||
|
||||
if (count > 0) {
|
||||
LOG_INFO(Frontend, "[Freedreno] Cleared all {} variables", count);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_getFreedrenoEnvSummary(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||
if (!g_config || g_config->env_vars.empty()) {
|
||||
return env->NewStringUTF("");
|
||||
}
|
||||
|
||||
std::string summary;
|
||||
for (const auto& [key, value] : g_config->env_vars) {
|
||||
if (!summary.empty()) {
|
||||
summary += ",";
|
||||
}
|
||||
summary += key + "=" + value;
|
||||
}
|
||||
|
||||
return env->NewStringUTF(summary.c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_setCurrentProgramId(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jprogramId) {
|
||||
g_current_program_id = Common::Android::GetJString(env, jprogramId);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_loadPerGameConfig(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jprogramId) {
|
||||
if (!g_config) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
auto program_id = Common::Android::GetJString(env, jprogramId);
|
||||
if (program_id.empty()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// Clear current environment variables first
|
||||
ClearAllEnvironmentVariables();
|
||||
g_current_program_id = program_id;
|
||||
|
||||
// Try to load per-game config - do NOT fall back to global
|
||||
// Per-game config should start empty if no config exists yet
|
||||
std::string per_game_path = GetPerGameConfigPath(program_id);
|
||||
if (LoadConfigFromFile(per_game_path)) {
|
||||
LOG_INFO(Frontend, "[Freedreno] Loaded per-game config for {}", program_id);
|
||||
LogActiveVariables();
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
// No per-game config exists - start with empty config
|
||||
LOG_INFO(Frontend, "[Freedreno] No per-game config for {}, starting empty", program_id);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_loadPerGameConfigWithGlobalFallback(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jprogramId) {
|
||||
if (!g_config) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
auto program_id = Common::Android::GetJString(env, jprogramId);
|
||||
if (program_id.empty()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// Clear current environment variables first
|
||||
ClearAllEnvironmentVariables();
|
||||
g_current_program_id = program_id;
|
||||
|
||||
// Try to load per-game config first
|
||||
std::string per_game_path = GetPerGameConfigPath(program_id);
|
||||
if (LoadConfigFromFile(per_game_path)) {
|
||||
LOG_INFO(Frontend, "[Freedreno] Loaded per-game config for {}", program_id);
|
||||
LogActiveVariables();
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
// Fall back to global config for emulation
|
||||
std::string global_path = GetConfigPath();
|
||||
if (LoadConfigFromFile(global_path)) {
|
||||
LOG_INFO(Frontend, "[Freedreno] No per-game config for {}, using global for emulation", program_id);
|
||||
LogActiveVariables();
|
||||
}
|
||||
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_savePerGameConfig(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jprogramId) {
|
||||
if (!g_config) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
auto program_id = Common::Android::GetJString(env, jprogramId);
|
||||
if (program_id.empty()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
EnsurePerGameConfigDir();
|
||||
std::string config_path = GetPerGameConfigPath(program_id);
|
||||
|
||||
if (SaveConfigToFile(config_path)) {
|
||||
LOG_INFO(Frontend, "[Freedreno] Saved per-game config for {}", program_id);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_hasPerGameConfig(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jprogramId) {
|
||||
auto program_id = Common::Android::GetJString(env, jprogramId);
|
||||
if (program_id.empty()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
std::string config_path = GetPerGameConfigPath(program_id);
|
||||
FILE* file = fopen(config_path.c_str(), "r");
|
||||
if (file) {
|
||||
fclose(file);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_yuzu_yuzu_1emu_utils_NativeFreedrenoConfig_deletePerGameConfig(
|
||||
JNIEnv* env, [[maybe_unused]] jobject obj, jstring jprogramId) {
|
||||
auto program_id = Common::Android::GetJString(env, jprogramId);
|
||||
if (program_id.empty()) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
std::string config_path = GetPerGameConfigPath(program_id);
|
||||
if (remove(config_path.c_str()) == 0) {
|
||||
LOG_INFO(Frontend, "[Freedreno] Deleted per-game config for {}", program_id);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
Before Width: | Height: | Size: 672 KiB After Width: | Height: | Size: 631 KiB |
|
Before Width: | Height: | Size: 102 KiB |
@@ -0,0 +1,39 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M317.52,255.37C318.06,255.37 318.6,255.38 319.65,255.41C322.37,255.43 324.58,255.42 326.79,255.41C349.49,255.43 372.2,255.43 394.91,255.46C400.46,255.47 406.02,255.65 411.58,255.6C413.68,255.59 414.71,256.12 414.54,258.43C414.35,261.26 414.33,264.1 414.37,266.94C414.4,269.64 413.52,270.71 410.51,270.7C377.29,270.59 344.07,270.65 310.85,270.66C295.82,270.66 280.79,270.66 265.75,270.66C264.61,270.66 263.47,270.66 262.06,270.66C262.06,272.3 262.06,273.7 262.06,275.5C312.31,275.5 362.6,275.5 413.71,275.5C412.65,281.11 411.74,286.21 410.66,291.28C410.55,291.83 409.53,292.38 408.84,292.56C407.95,292.78 406.96,292.62 406.01,292.62C359.34,292.62 312.66,292.62 265.99,292.62C264.75,292.62 263.51,292.62 262.03,292.62C262.03,294.2 262.03,295.49 262.03,297.18C310.9,297.18 359.72,297.18 409.36,297.18C408.27,300.87 407.4,304.03 406.39,307.15C404.52,312.95 404.48,312.94 398.53,312.94C354.38,312.94 310.22,312.95 266.07,312.92C263.76,312.91 261.86,313.09 262.84,316.08C263.07,316.81 264.11,317.46 264.92,317.77C265.65,318.06 266.58,317.84 267.42,317.84C310.84,317.84 354.26,317.84 397.67,317.84C399.01,317.84 400.34,317.84 402.55,317.84C400.14,322.79 398.2,327.17 395.86,331.32C395.42,332.11 393.44,332.31 392.17,332.31C373.14,332.37 354.11,332.35 335.08,332.35C313.54,332.35 291.98,332.36 270.43,332.35C268.66,332.35 266.89,332.26 264.63,332.33C262.52,332.45 260.88,332.45 259.24,332.45C258.67,327.67 257.69,322.9 257.58,318.11C257.21,300.69 257.06,283.26 257.01,265.84C257,262.52 257.85,259.2 258.72,255.69C260.68,255.49 262.21,255.48 264.04,255.51C279.33,255.53 294.33,255.5 309.62,255.47C312.44,255.44 314.98,255.4 317.52,255.37Z"
|
||||
android:fillColor="#BF42F6"/>
|
||||
<path
|
||||
android:pathData="M196.08,256.6C196.08,254.63 196.08,252.67 196.08,250.27C194.45,250.27 192.91,250.27 191.37,250.27C161.1,250.29 130.82,250.28 100.54,250.37C97.92,250.38 96.9,249.67 97.32,246.97C97.78,243.97 98.17,240.93 98.27,237.9C98.34,235.6 99.36,235.17 101.4,235.17C132.61,235.1 163.82,234.94 195.04,234.86C197.66,234.86 199.69,234.63 199.14,230.9C165.95,230.9 132.78,230.9 99.13,230.9C100.08,226.41 100.73,222.27 101.94,218.31C102.23,217.39 104.41,216.53 105.72,216.53C137.99,216.47 170.27,216.52 202.54,216.6C204.76,216.61 206.52,216.34 206.71,213.17C172.35,213.17 138.07,213.17 102.94,213.17C105.27,206.84 107.26,201.13 109.56,195.55C109.89,194.76 111.78,194.23 112.96,194.22C129.67,194.14 146.39,194.08 163.1,194.23C166.69,194.27 168.59,192.48 170.67,189.3C151.01,189.3 131.87,189.3 111.88,189.3C114.84,183.98 117.32,179.27 120.09,174.74C120.55,174 122.27,173.74 123.4,173.74C144.22,173.68 165.04,173.54 185.85,173.82C190.74,173.88 194.5,172.04 198.31,169.21C173.73,169.21 149.15,169.21 123.5,169.21C125.26,166.62 126.46,164.76 127.76,162.97C133.8,154.66 133.81,154.67 144.13,154.67C171.78,154.66 199.43,154.67 227.08,154.67C228.19,154.67 229.29,154.67 231.08,154.67C228.38,151.86 226.32,149.93 222.7,149.94C196.21,150.06 169.72,150.01 143.22,150.01C142.01,150.01 140.79,150.01 139.58,150.01C139.41,149.71 139.24,149.41 139.08,149.12C141.68,146.49 144.22,143.8 146.91,141.27C154.7,133.92 154.72,133.79 165.43,133.98C181.21,134.26 196.1,138.61 210.47,144.78C214.32,146.44 217.65,147.31 221.76,145.43C224.98,143.95 228.71,143.61 232.67,143.03C229.67,148.57 233.27,151.22 236.42,154.19C240.32,157.87 244.05,161.72 247.81,165.54C248.6,166.35 249.19,167.35 250.32,168.84C248.78,168.93 247.82,169.03 246.87,169.03C240.24,169.04 233.61,169.23 227,168.97C207.93,168.24 191.92,175.26 178.31,188.15C173.45,192.76 169.11,197.93 164.57,202.87C164.1,203.38 163.83,204.06 163.06,205.34C186.14,197.23 207.86,186.73 232.14,185.87C232.34,186.18 232.53,186.5 232.73,186.82C229.85,190.18 227.16,193.72 224.07,196.87C211.77,209.42 204.42,224.53 201.03,241.6C200.07,246.39 200.14,251.4 199.32,256.52C197.97,256.68 197.03,256.64 196.08,256.6ZM209.68,194.22C212.31,194.23 214.96,194.01 217.56,194.29C221.34,194.69 223.62,192.8 226.08,189.17C219.87,190.63 214.42,191.92 208.98,193.24C208.98,193.24 209.12,193.87 209.68,194.22Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M195.81,256.61C197.03,256.64 197.97,256.68 199.2,256.74C199.58,258.84 199.68,260.93 199.79,263.02C200.15,263.15 200.52,263.28 200.89,263.41C202.45,261.11 204.02,258.8 205.97,256.3C207.64,256.04 208.92,255.97 210.44,255.9C211.39,255.81 212.11,255.66 212.84,255.65C221.05,255.54 229.27,255.45 237.79,255.4C240.14,255.48 242.19,255.51 244.24,255.54C243.48,260.08 242.67,264.61 241.96,269.16C238.76,289.76 238.29,310.44 239.8,331.49C238.12,331.99 236.72,332.2 235.33,332.4C197.17,332.39 159.01,332.31 120.85,332.45C117.22,332.46 115.21,331.39 113.93,328.08C112.65,324.8 111,321.67 109.23,317.84C113.61,317.84 117.25,317.84 120.89,317.84C157.58,317.84 194.27,317.85 230.96,317.81C232.33,317.8 234.26,318.64 234.58,316.04C234.9,313.41 233.71,312.89 231.33,312.9C204.94,312.97 178.55,312.94 152.17,312.95C138.29,312.95 124.42,312.9 110.54,313.03C108.13,313.05 106.9,312.32 106.24,310.03C105.12,306.12 103.81,302.26 102.24,297.34C146.69,297.16 190.42,297.32 234.45,297.24C234.54,295.65 234.62,294.35 234.7,292.8C233.41,292.73 232.39,292.63 231.38,292.63C191.74,292.61 152.11,292.59 112.48,292.59C109.43,292.59 106.38,292.78 103.34,292.7C102.57,292.68 101.25,292.09 101.13,291.56C99.99,286.28 99.05,280.95 97.99,275.27C103.72,275.27 108.74,275.24 113.75,275.28C115.11,275.29 116.47,275.55 117.83,275.55C155.88,275.57 193.94,275.57 231.99,275.56C236.12,275.56 236.28,275.39 236.25,270.67C190.27,270.67 144.28,270.67 97.69,270.67C97.5,266.15 97.2,262.01 97.29,257.87C97.3,257.33 99.29,256.41 100.37,256.4C110.67,256.26 120.97,256.28 131.28,256.27C143.26,256.26 155.24,256.22 167.23,256.28C176.66,256.33 186.1,256.51 195.81,256.61Z"
|
||||
android:fillColor="#BF43F5"/>
|
||||
<path
|
||||
android:pathData="M235.35,332.69C236.72,332.2 238.12,331.99 239.8,331.78C241.62,343.91 242.64,356.16 244.79,368.19C247.54,383.59 251.45,398.75 257.46,413.28C257.66,413.75 257.8,414.25 257.96,414.73C240.7,421.84 173.22,399.36 158.05,381.11C172.31,381.11 186.11,381.11 199.9,381.11C213.75,381.11 227.59,381.11 241.47,381.11C241.67,377.83 240.89,376.4 237.49,376.42C210.37,376.55 183.25,376.46 156.13,376.54C153.11,376.55 150.66,375.97 148.51,373.71C143.83,368.81 138.99,364.07 134.22,359.27C134.38,358.97 134.53,358.67 134.69,358.38C168.96,358.38 203.24,358.38 237.91,358.38C237.59,356.49 237.35,355.09 237.06,353.42C235.66,353.42 234.41,353.42 233.17,353.42C204.05,353.42 174.93,353.43 145.82,353.41C141.61,353.41 137.4,353.12 133.21,353.29C130.69,353.4 129.04,352.57 127.7,350.52C124.9,346.24 122.01,342.03 118.68,337.09C158.03,337.09 196.51,337.09 235.37,337.09C235.37,335.43 235.37,334.21 235.35,332.69Z"
|
||||
android:fillColor="#985DED"/>
|
||||
<path
|
||||
android:pathData="M259.22,332.74C260.88,332.45 262.52,332.45 264.42,332.44C264.74,333.79 264.81,335.15 264.9,336.86C307.33,336.86 349.65,336.86 392.94,336.86C390.82,340.23 389.17,342.95 387.42,345.59C382.22,353.42 382.21,353.42 372.98,353.42C339.55,353.42 306.12,353.42 272.68,353.42C271.45,353.42 270.21,353.42 269.01,353.42C268.6,357.97 268.9,358.32 272.97,358.32C306.4,358.33 339.83,358.33 373.27,358.33C374.49,358.33 375.71,358.33 377.95,358.33C375.2,361.41 372.88,363.64 370.99,366.18C364.84,374.47 357,377.15 346.54,376.75C324.07,375.9 301.55,376.49 279.05,376.49C277.81,376.49 276.57,376.49 275.34,376.49C275.16,380.42 275.74,381.1 279.15,381.1C302.59,381.11 326.04,381.1 349.48,381.11C350.69,381.11 351.89,381.11 353.09,381.11C353.19,381.39 353.29,381.68 353.39,381.97C351.01,383.75 348.69,385.61 346.25,387.3C330.27,398.36 312.8,406.17 293.96,410.9C291.74,411.45 289.36,411.83 287.12,411.64C285.84,411.52 284.3,410.33 283.54,409.19C277.07,399.49 273.01,388.7 269.22,377.75C264.17,363.21 261.34,348.2 259.22,332.74Z"
|
||||
android:fillColor="#985DED"/>
|
||||
<path
|
||||
android:pathData="M326.78,255.15C324.58,255.42 322.37,255.43 319.85,255.39C321.63,245.65 321.41,236 319.06,226.36C315.84,213.14 308.31,203.06 296.96,195.73C296.52,195.45 296.09,195.16 295.7,194.28C307.61,194.28 319.52,194.28 331.43,194.28C331.48,193.93 331.53,193.59 331.57,193.25C326.8,191.44 322.07,189.34 316.8,189.29C306.29,189.2 295.77,189.33 285.27,189.21C283.16,189.19 281.07,188.5 279.01,187.57C291.5,182.55 304.29,183.1 317.13,185.13C330.14,187.18 341.45,193.94 354.27,199.15C353.23,197.19 352.63,196.05 351.78,194.42C353.03,194.32 353.99,194.18 354.94,194.18C369.55,194.16 384.16,194.21 398.77,194.12C400.99,194.11 402.21,194.7 402.93,196.91C404.51,201.76 406.34,206.52 408.3,211.96C378.96,211.96 350.45,211.96 321.79,211.96C321.89,215.04 323.22,215.9 325.8,215.89C345.56,215.82 365.32,215.82 385.08,215.87C392.43,215.89 399.77,216.08 407.11,216.34C408.02,216.37 409.48,217.14 409.67,217.85C410.73,221.77 411.47,225.78 412.41,230.2C383.7,230.2 355.5,230.2 327.33,230.2C326.95,234.48 327.15,234.7 330.87,234.7C357.35,234.74 383.84,234.81 410.32,234.8C412.27,234.8 413.19,235.26 413.31,237.37C413.52,240.82 413.96,244.26 414.41,247.69C414.69,249.87 413.98,250.71 411.68,250.63C407.17,250.48 402.65,250.56 398.13,250.56C375.85,250.56 353.57,250.56 331.29,250.56C327.03,250.56 327.03,250.57 326.78,255.15Z"
|
||||
android:fillColor="#FF43C4"/>
|
||||
<path
|
||||
android:pathData="M227.85,100.36C256.3,95.58 282.98,98.91 297.89,104.06C295.79,108.97 293.7,113.87 291.61,118.76C290.5,121.37 289.2,123.91 288.3,126.59C287.56,128.8 286.27,129.35 284.07,129.34C269.05,129.26 254.03,129.29 238.21,129.29C240.88,132.05 242.88,134.26 246.57,134.22C257.92,134.12 269.27,134.18 280.62,134.18C281.77,134.18 282.91,134.18 285.21,134.18C282.72,138.33 281.09,142.24 278.43,145.21C274.25,149.87 269.29,153.82 264.85,158.26C263.14,159.97 262.34,159.9 260.7,158.1C253.98,150.75 247.23,143.42 240.16,136.4C232.38,128.67 222.49,125.46 211.78,124.23C202.25,123.13 193.21,124.88 184.27,127.97C182.14,128.71 179.81,129.15 177.55,129.24C172.62,129.42 167.68,129.29 162.59,128.89C181.97,114.22 203.7,104.88 227.85,100.36ZM264.4,152.93C265.08,152.12 265.76,151.3 266.85,150.01C264.04,150.01 261.99,150.01 259.33,150.01C260.37,151.48 260.92,152.63 261.81,153.37C262.25,153.73 263.32,153.32 264.4,152.93Z"
|
||||
android:fillColor="#FF42C3"/>
|
||||
<path
|
||||
android:pathData="M338.22,180.32C330,173.61 320.35,171.22 310.4,169.77C298.87,168.1 287.56,168.74 276.35,173.62C276.99,172.43 277.52,171.16 278.31,170.08C288.95,155.53 302.06,143.72 317.99,135.27C320.4,133.99 323.68,134.06 326.56,134.01C335.71,133.86 344.86,133.9 354,134.01C355.37,134.02 357.07,134.45 358.04,135.32C362.81,139.6 367.39,144.09 372.01,148.53C372.28,148.78 372.38,149.19 372.81,150.01C371.31,150.01 370.2,150.01 369.09,150.01C348.07,150.01 327.04,150.08 306.02,149.93C302.48,149.9 300.52,151.7 297.87,154.67C299.78,154.67 300.97,154.67 302.15,154.67C326.02,154.67 349.88,154.71 373.74,154.6C376.46,154.59 378.32,155.41 379.86,157.57C382.39,161.15 385.05,164.63 388.18,168.84C367.16,168.84 347,168.84 326.84,168.84C326.8,169.1 326.77,169.35 326.73,169.61C331.21,171.27 335.15,173.92 340.45,173.81C356.21,173.5 371.98,173.75 387.75,173.65C390.3,173.63 391.87,174.45 393.01,176.69C395.03,180.7 397.23,184.61 399.61,189.04C398.04,189.14 397.06,189.26 396.07,189.26C380.83,189.27 365.59,189.23 350.34,189.31C348.17,189.32 346.58,188.76 345.1,187.13C343,184.79 340.64,182.68 338.22,180.32Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M263.75,255.47C262.21,255.48 260.68,255.49 258.86,255.49C260.26,237.4 261.8,219.3 267.17,201.8C267.96,199.21 268.84,198.07 271.41,199.91C273.97,201.74 276.92,203.14 279.13,205.31C294.14,220.1 308.29,235.58 317.44,255.16C314.98,255.4 312.44,255.44 309.6,255.22C308.77,252.11 307.31,250.9 304.14,250.95C292.11,251.14 280.07,251.03 268.03,251.04C266.7,251.04 265.38,251.04 263.75,251.04C263.75,252.81 263.75,254.14 263.75,255.47ZM265.23,234.42C275.39,234.42 285.55,234.42 295.71,234.42C295.83,234.04 295.95,233.66 296.07,233.28C294.82,232.66 293.59,231.54 292.34,231.52C283.86,231.36 275.38,231.45 266.9,231.42C264.98,231.41 264.11,232.09 265.23,234.42ZM272.28,213.13C270.05,212.98 268.06,213.13 268.44,216.24C272.26,216.24 276,216.24 279.86,216.24C278.35,212.79 275.57,213.04 272.28,213.13Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M244.37,255.35C242.19,255.51 240.14,255.48 237.87,255.14C237.72,253.74 237.8,252.65 237.92,251.1C230.12,251.1 222.74,251.09 215.35,251.1C211.33,251.1 210.79,251.62 210.2,255.9C208.92,255.97 207.64,256.04 206.08,256.11C209.18,249.49 212.07,242.57 216.01,236.32C223.02,225.18 230.96,214.72 241.59,206.63C246.5,202.9 251.86,200.11 257.81,198.49C258.58,198.28 259.39,198.25 261.09,198.02C254,217.03 248.24,235.81 244.37,255.35ZM226.88,230.34C223.86,230.04 223.17,232.3 221.91,234.84C228.63,234.84 234.89,234.75 241.15,234.88C244,234.94 244.78,233.68 244.4,230.4C238.69,230.4 233.05,230.4 226.88,230.34ZM249.9,214.76C249.15,214.31 248.42,213.55 247.63,213.47C245.66,213.28 243.65,213.49 241.66,213.37C239.1,213.21 237.69,214.56 236.27,217.12C240.49,217.12 244.21,217.2 247.93,217.03C248.58,217 249.17,215.9 249.9,214.76Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M315.52,109.68C327.71,114.67 338.96,120.8 349.32,129.08C328.46,127.7 308.6,131.4 289.08,139.83C289.67,136.65 290.71,134.68 293.44,133.84C297.43,132.61 301.38,131.27 305.32,129.43C301.9,129.43 298.47,129.43 294.12,129.43C298.11,121.6 301.71,114.44 305.48,107.37C305.75,106.86 307.39,106.71 308.22,106.96C310.62,107.69 312.94,108.7 315.52,109.68Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,39 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M346.71,255.31C347.5,255.31 348.29,255.32 349.83,255.37C353.84,255.39 357.09,255.38 360.33,255.37C393.73,255.39 427.12,255.4 460.51,255.45C468.68,255.46 476.86,255.73 485.03,255.65C488.12,255.63 489.63,256.4 489.39,259.81C489.1,263.97 489.08,268.15 489.13,272.32C489.18,276.29 487.88,277.86 483.45,277.85C434.6,277.69 385.75,277.78 336.9,277.79C314.79,277.8 292.68,277.79 270.58,277.79C268.9,277.79 267.22,277.79 265.15,277.79C265.15,280.2 265.15,282.26 265.15,284.91C339.05,284.91 412.99,284.91 488.16,284.91C486.61,293.16 485.26,300.67 483.68,308.12C483.51,308.93 482.02,309.74 481,309.99C479.69,310.32 478.23,310.09 476.84,310.09C408.2,310.09 339.56,310.09 270.92,310.09C269.1,310.09 267.27,310.09 265.1,310.09C265.1,312.41 265.1,314.32 265.1,316.79C336.97,316.79 408.77,316.79 481.77,316.79C480.16,322.22 478.88,326.87 477.4,331.45C474.64,339.99 474.59,339.98 465.83,339.98C400.9,339.98 335.98,339.99 271.05,339.94C267.64,339.93 264.86,340.19 266.29,344.59C266.64,345.66 268.16,346.61 269.36,347.08C270.43,347.5 271.8,347.17 273.04,347.17C336.88,347.17 400.73,347.17 464.58,347.17C466.54,347.17 468.5,347.17 471.75,347.17C468.21,354.46 465.35,360.89 461.91,367C461.26,368.16 458.35,368.45 456.48,368.46C428.5,368.54 400.52,368.52 372.54,368.52C340.85,368.52 309.15,368.52 277.46,368.51C274.85,368.51 272.24,368.39 268.93,368.49C265.82,368.66 263.41,368.67 261.01,368.67C260.16,361.64 258.72,354.62 258.57,347.57C258.02,321.95 257.79,296.33 257.72,270.71C257.71,265.83 258.95,260.94 260.24,255.78C263.12,255.48 265.37,255.47 268.05,255.52C290.54,255.54 312.61,255.5 335.09,255.46C339.23,255.41 342.97,255.36 346.71,255.31Z"
|
||||
android:fillColor="#BF42F6"/>
|
||||
<path
|
||||
android:pathData="M168.12,257.11C168.12,254.22 168.12,251.34 168.12,247.81C165.72,247.81 163.45,247.81 161.19,247.81C116.67,247.84 72.15,247.82 27.63,247.96C23.77,247.97 22.27,246.93 22.88,242.96C23.56,238.54 24.13,234.07 24.27,229.61C24.38,226.23 25.88,225.61 28.88,225.6C74.78,225.49 120.68,225.26 166.58,225.15C170.45,225.14 173.43,224.81 172.62,219.32C123.81,219.32 75.02,219.32 25.55,219.32C26.94,212.72 27.9,206.64 29.68,200.81C30.1,199.46 33.31,198.19 35.24,198.19C82.7,198.1 130.16,198.18 177.61,198.3C180.89,198.3 183.47,197.92 183.75,193.25C133.22,193.25 82.8,193.25 31.15,193.25C34.58,183.94 37.49,175.54 40.89,167.34C41.37,166.17 44.15,165.4 45.87,165.39C70.46,165.26 95.04,165.18 119.62,165.4C124.9,165.45 127.69,162.82 130.75,158.15C101.83,158.15 73.69,158.15 44.3,158.15C48.65,150.32 52.3,143.4 56.37,136.74C57.04,135.65 59.57,135.27 61.24,135.26C91.85,135.18 122.47,134.97 153.07,135.38C160.26,135.47 165.79,132.76 171.4,128.6C135.25,128.6 99.1,128.6 61.39,128.6C63.98,124.8 65.74,122.06 67.65,119.43C76.53,107.21 76.55,107.22 91.72,107.22C132.38,107.21 173.04,107.21 213.7,107.21C215.33,107.21 216.96,107.21 219.59,107.21C215.62,103.09 212.58,100.25 207.27,100.27C168.31,100.44 129.35,100.36 90.39,100.36C88.6,100.36 86.82,100.36 85.03,100.36C84.78,99.92 84.53,99.49 84.29,99.05C88.12,95.2 91.85,91.24 95.8,87.51C107.26,76.71 107.3,76.52 123.05,76.8C146.26,77.21 168.15,83.6 189.28,92.68C194.94,95.11 199.84,96.4 205.89,93.63C210.61,91.46 216.1,90.96 221.92,90.11C217.51,98.24 222.81,102.15 227.44,106.52C233.17,111.93 238.66,117.59 244.19,123.21C245.36,124.39 246.23,125.87 247.88,128.06C245.62,128.19 244.21,128.34 242.8,128.34C233.06,128.35 223.31,128.63 213.59,128.25C185.54,127.18 161.99,137.5 141.99,156.46C134.83,163.24 128.46,170.84 121.77,178.11C121.09,178.85 120.69,179.85 119.56,181.74C153.5,169.81 185.44,154.36 221.15,153.1C221.44,153.57 221.73,154.03 222.01,154.5C217.78,159.44 213.82,164.64 209.28,169.28C191.19,187.74 180.38,209.95 175.39,235.05C173.99,242.11 174.08,249.46 172.89,256.99C170.89,257.24 169.51,257.18 168.12,257.11ZM188.12,165.39C191.98,165.39 195.88,165.07 199.7,165.48C205.27,166.07 208.62,163.3 212.23,157.96C203.1,160.11 195.09,162 187.09,163.95C187.08,163.95 187.3,164.87 188.12,165.39Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M167.72,257.14C169.51,257.18 170.89,257.24 172.7,257.32C173.27,260.41 173.42,263.49 173.57,266.56C174.11,266.75 174.65,266.95 175.19,267.14C177.49,263.75 179.79,260.35 182.66,256.68C185.11,256.3 187,256.2 189.23,256.08C190.64,255.95 191.7,255.74 192.76,255.73C204.84,255.56 216.92,255.43 229.45,255.36C232.92,255.47 235.93,255.51 238.94,255.56C237.82,262.23 236.63,268.9 235.59,275.59C230.88,305.88 230.19,336.29 232.4,367.24C229.94,367.99 227.89,368.29 225.84,368.59C169.72,368.57 113.6,368.46 57.49,368.65C52.15,368.67 49.19,367.1 47.3,362.24C45.43,357.42 43.01,352.8 40.4,347.17C46.84,347.17 52.19,347.17 57.54,347.17C111.5,347.17 165.45,347.18 219.4,347.13C221.43,347.13 224.27,348.35 224.73,344.53C225.2,340.67 223.46,339.9 219.95,339.91C181.15,340.02 142.34,339.97 103.54,339.98C83.14,339.98 62.73,339.92 42.33,340.11C38.78,340.14 36.96,339.06 36,335.69C34.36,329.94 32.42,324.27 30.12,317.03C95.49,316.77 159.8,317 224.55,316.88C224.68,314.54 224.79,312.64 224.92,310.35C223.02,310.25 221.52,310.11 220.02,310.11C161.74,310.07 103.46,310.05 45.17,310.05C40.69,310.05 36.21,310.32 31.74,310.21C30.6,310.18 28.66,309.31 28.49,308.53C26.81,300.76 25.43,292.93 23.86,284.57C32.3,284.57 39.67,284.54 47.05,284.59C49.04,284.6 51.04,284.99 53.04,284.99C109,285.01 164.97,285.01 220.93,285C227.01,285 227.24,284.75 227.2,277.81C159.57,277.81 91.94,277.81 23.43,277.81C23.15,271.16 22.71,265.07 22.84,258.98C22.86,258.2 25.78,256.84 27.37,256.82C42.52,256.62 57.67,256.64 72.82,256.63C90.44,256.61 108.07,256.55 125.69,256.64C139.57,256.71 153.44,256.98 167.72,257.14Z"
|
||||
android:fillColor="#BF43F5"/>
|
||||
<path
|
||||
android:pathData="M225.87,369.02C227.89,368.29 229.94,367.99 232.42,367.67C235.09,385.52 236.59,403.52 239.75,421.23C243.8,443.87 249.54,466.17 258.38,487.52C258.67,488.22 258.88,488.96 259.13,489.67C233.74,500.12 134.5,467.06 112.2,440.21C133.17,440.21 153.45,440.21 173.74,440.21C194.1,440.21 214.46,440.21 234.87,440.21C235.17,435.4 234.01,433.3 229.01,433.32C189.13,433.52 149.25,433.38 109.36,433.5C104.92,433.52 101.33,432.66 98.16,429.33C91.29,422.13 84.17,415.17 77.15,408.11C77.38,407.67 77.61,407.23 77.84,406.79C128.24,406.79 178.65,406.79 229.63,406.79C229.16,404.01 228.81,401.96 228.39,399.5C226.32,399.5 224.49,399.5 222.66,399.5C179.84,399.5 137.02,399.51 94.2,399.48C88.02,399.48 81.83,399.06 75.66,399.31C71.96,399.47 69.52,398.25 67.56,395.24C63.45,388.95 59.19,382.75 54.3,375.48C112.17,375.48 168.75,375.48 225.9,375.48C225.9,373.05 225.9,371.25 225.87,369.02Z"
|
||||
android:fillColor="#985DED"/>
|
||||
<path
|
||||
android:pathData="M260.97,369.08C263.41,368.67 265.82,368.66 268.61,368.65C269.1,370.64 269.19,372.63 269.32,375.15C331.73,375.15 393.96,375.15 457.62,375.15C454.49,380.1 452.08,384.1 449.5,387.99C441.86,399.51 441.83,399.49 428.27,399.49C379.1,399.5 329.94,399.5 280.77,399.5C278.95,399.5 277.13,399.5 275.36,399.5C274.76,406.19 275.21,406.71 281.19,406.71C330.36,406.72 379.52,406.71 428.69,406.72C430.48,406.72 432.28,406.72 435.58,406.72C431.53,411.25 428.13,414.53 425.35,418.27C416.3,430.46 404.77,434.4 389.38,433.81C356.34,432.56 323.22,433.43 290.13,433.43C288.31,433.43 286.48,433.43 284.68,433.43C284.41,439.2 285.27,440.2 290.28,440.21C324.76,440.22 359.23,440.21 393.71,440.21C395.48,440.21 397.25,440.21 399.01,440.21C399.16,440.64 399.31,441.06 399.46,441.49C395.96,444.11 392.55,446.85 388.96,449.33C365.45,465.59 339.77,477.07 312.06,484.02C308.8,484.84 305.3,485.4 301.99,485.11C300.12,484.95 297.85,483.2 296.73,481.51C287.23,467.26 281.26,451.38 275.67,435.29C268.26,413.89 264.08,391.82 260.97,369.08Z"
|
||||
android:fillColor="#985DED"/>
|
||||
<path
|
||||
android:pathData="M360.32,254.99C357.09,255.38 353.84,255.39 350.13,255.34C352.74,241.02 352.42,226.82 348.97,212.64C344.23,193.2 333.16,178.39 316.47,167.6C315.83,167.19 315.2,166.76 314.61,165.46C332.13,165.46 349.64,165.46 367.16,165.46C367.23,164.96 367.3,164.46 367.37,163.96C360.35,161.29 353.4,158.21 345.64,158.14C330.19,158 314.73,158.19 299.27,158.02C296.18,157.99 293.1,156.98 290.07,155.61C308.44,148.22 327.24,149.03 346.13,152.01C365.26,155.03 381.9,164.97 400.74,172.63C399.23,169.75 398.34,168.07 397.08,165.68C398.93,165.53 400.33,165.32 401.74,165.32C423.23,165.3 444.71,165.37 466.2,165.24C469.46,165.22 471.26,166.09 472.32,169.34C474.64,176.47 477.33,183.47 480.21,191.47C437.06,191.47 395.13,191.47 352.99,191.47C353.13,196.01 355.09,197.26 358.88,197.25C387.94,197.15 417,197.14 446.06,197.22C456.86,197.26 467.67,197.53 478.46,197.91C479.79,197.96 481.95,199.1 482.22,200.13C483.77,205.9 484.86,211.8 486.24,218.3C444.03,218.3 402.55,218.3 361.13,218.3C360.58,224.59 360.87,224.91 366.33,224.91C405.28,224.98 444.23,225.07 483.18,225.06C486.04,225.06 487.39,225.73 487.58,228.83C487.88,233.91 488.53,238.97 489.19,244.02C489.6,247.21 488.55,248.46 485.18,248.34C478.55,248.12 471.9,248.24 465.26,248.24C432.49,248.23 399.72,248.24 366.95,248.24C360.69,248.24 360.69,248.25 360.32,254.99Z"
|
||||
android:fillColor="#FF43C4"/>
|
||||
<path
|
||||
android:pathData="M214.84,27.35C256.67,20.33 295.91,25.23 317.84,32.8C314.75,40.02 311.68,47.22 308.61,54.41C306.97,58.24 305.06,61.99 303.74,65.93C302.65,69.18 300.74,69.98 297.52,69.97C275.43,69.85 253.34,69.9 230.07,69.9C234.01,73.95 236.94,77.2 242.37,77.15C259.06,76.99 275.76,77.09 292.45,77.1C294.13,77.1 295.81,77.1 299.19,77.1C295.53,83.19 293.14,88.94 289.22,93.31C283.08,100.17 275.78,105.97 269.24,112.5C266.73,115.01 265.56,114.91 263.14,112.27C253.27,101.45 243.33,90.67 232.95,80.36C221.49,68.98 206.96,64.27 191.21,62.45C177.19,60.83 163.89,63.42 150.75,67.96C147.61,69.04 144.19,69.69 140.87,69.82C133.62,70.09 126.36,69.9 118.87,69.31C147.37,47.73 179.32,34 214.84,27.35ZM268.58,104.66C269.59,103.46 270.59,102.27 272.19,100.38C268.06,100.38 265.05,100.38 261.13,100.38C262.66,102.53 263.47,104.22 264.79,105.31C265.43,105.84 267,105.24 268.58,104.66Z"
|
||||
android:fillColor="#FF42C3"/>
|
||||
<path
|
||||
android:pathData="M377.15,144.94C365.06,135.07 350.86,131.56 336.23,129.43C319.28,126.96 302.65,127.92 286.16,135.08C287.11,133.34 287.88,131.47 289.04,129.88C304.69,108.48 323.97,91.12 347.4,78.68C350.95,76.8 355.77,76.91 360.01,76.84C373.45,76.62 386.9,76.67 400.35,76.83C402.37,76.86 404.87,77.49 406.3,78.77C413.31,85.06 420.04,91.67 426.84,98.19C427.23,98.56 427.39,99.17 428.02,100.36C425.81,100.36 424.18,100.36 422.55,100.36C391.63,100.36 360.71,100.48 329.8,100.25C324.58,100.21 321.7,102.85 317.82,107.22C320.62,107.22 322.36,107.22 324.11,107.22C359.2,107.21 394.29,107.28 429.39,107.13C433.39,107.11 436.12,108.31 438.38,111.49C442.11,116.74 446.02,121.86 450.61,128.06C419.7,128.06 390.05,128.06 360.41,128.06C360.36,128.43 360.3,128.81 360.25,129.19C366.83,131.63 372.64,135.53 380.43,135.37C403.61,134.91 426.8,135.29 449.99,135.13C453.74,135.1 456.04,136.3 457.71,139.61C460.69,145.49 463.92,151.25 467.42,157.76C465.12,157.91 463.67,158.09 462.22,158.09C439.81,158.1 417.39,158.05 394.98,158.16C391.79,158.18 389.44,157.36 387.27,154.95C384.18,151.51 380.71,148.41 377.15,144.94Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M267.63,255.46C265.37,255.47 263.12,255.48 260.45,255.48C262.5,228.88 264.77,202.27 272.66,176.53C273.83,172.72 275.12,171.05 278.9,173.76C282.66,176.45 287.01,178.5 290.25,181.69C312.32,203.43 333.13,226.21 346.6,255C342.97,255.36 339.23,255.41 335.05,255.09C333.83,250.51 331.69,248.73 327.03,248.81C309.33,249.09 291.63,248.93 273.93,248.93C271.98,248.93 270.02,248.93 267.63,248.93C267.63,251.54 267.63,253.5 267.63,255.46ZM269.8,224.5C284.75,224.5 299.69,224.5 314.64,224.5C314.81,223.95 314.98,223.38 315.15,222.83C313.33,221.92 311.52,220.26 309.68,220.23C297.21,219.99 284.74,220.13 272.27,220.09C269.44,220.08 268.16,221.08 269.8,224.5ZM280.18,193.19C276.89,192.97 273.97,193.18 274.53,197.77C280.15,197.77 285.65,197.77 291.32,197.77C289.11,192.69 285.02,193.05 280.18,193.19Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M239.14,255.27C235.93,255.51 232.92,255.47 229.57,254.97C229.36,252.92 229.48,251.32 229.65,249.02C218.18,249.02 207.32,249.02 196.46,249.03C190.55,249.03 189.75,249.79 188.89,256.1C187,256.2 185.11,256.3 182.83,256.4C187.38,246.66 191.64,236.49 197.43,227.29C207.73,210.92 219.41,195.53 235.05,183.63C242.26,178.14 250.14,174.04 258.89,171.65C260.02,171.35 261.23,171.31 263.73,170.96C253.3,198.93 244.82,226.55 239.14,255.27ZM213.42,218.5C208.98,218.06 207.96,221.38 206.1,225.12C215.98,225.12 225.19,224.99 234.4,225.18C238.59,225.27 239.74,223.41 239.18,218.58C230.78,218.58 222.49,218.58 213.42,218.5ZM247.27,195.58C246.16,194.92 245.09,193.8 243.93,193.69C241.03,193.41 238.07,193.72 235.15,193.54C231.39,193.32 229.31,195.29 227.22,199.05C233.42,199.05 238.9,199.18 244.37,198.93C245.32,198.89 246.2,197.27 247.27,195.58Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M343.76,41.06C361.68,48.39 378.24,57.41 393.47,69.59C362.8,67.56 333.58,72.99 304.89,85.39C305.74,80.72 307.29,77.83 311.3,76.58C317.16,74.77 322.97,72.82 328.77,70.1C323.73,70.1 318.69,70.1 312.29,70.1C318.16,58.59 323.45,48.06 329,37.66C329.4,36.92 331.81,36.69 333.03,37.06C336.57,38.13 339.97,39.62 343.76,41.06Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,39 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M304.46,255.4C304.89,255.4 305.31,255.4 306.14,255.43C308.29,255.44 310.04,255.44 311.78,255.43C329.71,255.44 347.63,255.44 365.56,255.47C369.95,255.48 374.33,255.62 378.72,255.58C380.38,255.57 381.19,255.99 381.06,257.81C380.9,260.05 380.89,262.29 380.92,264.53C380.95,266.66 380.25,267.51 377.87,267.5C351.65,267.41 325.42,267.46 299.2,267.47C287.33,267.47 275.46,267.47 263.59,267.47C262.69,267.47 261.79,267.47 260.68,267.47C260.68,268.76 260.68,269.87 260.68,271.29C300.35,271.29 340.05,271.29 380.4,271.29C379.57,275.72 378.85,279.75 378,283.75C377.91,284.18 377.1,284.62 376.56,284.76C375.85,284.93 375.07,284.81 374.33,284.81C337.48,284.81 300.63,284.81 263.78,284.81C262.8,284.81 261.82,284.81 260.65,284.81C260.65,286.05 260.65,287.08 260.65,288.4C299.24,288.4 337.78,288.4 376.97,288.4C376.11,291.32 375.42,293.81 374.62,296.27C373.14,300.86 373.12,300.85 368.42,300.85C333.56,300.85 298.7,300.86 263.85,300.83C262.02,300.83 260.52,300.96 261.29,303.33C261.48,303.9 262.3,304.41 262.94,304.66C263.52,304.89 264.25,304.71 264.91,304.71C299.19,304.71 333.46,304.71 367.74,304.71C368.79,304.71 369.85,304.71 371.59,304.71C369.69,308.63 368.15,312.08 366.31,315.36C365.96,315.98 364.4,316.14 363.39,316.14C348.37,316.19 333.35,316.17 318.33,316.17C301.32,316.17 284.3,316.17 267.29,316.17C265.89,316.17 264.49,316.1 262.71,316.16C261.04,316.25 259.75,316.25 258.46,316.25C258,312.48 257.23,308.71 257.15,304.93C256.85,291.18 256.73,277.42 256.69,263.66C256.69,261.04 257.35,258.42 258.05,255.65C259.59,255.49 260.8,255.48 262.24,255.51C274.31,255.52 286.16,255.5 298.23,255.48C300.45,255.45 302.46,255.42 304.46,255.4Z"
|
||||
android:fillColor="#BF42F6"/>
|
||||
<path
|
||||
android:pathData="M208.59,256.37C208.59,254.82 208.59,253.26 208.59,251.37C207.3,251.37 206.09,251.37 204.87,251.37C180.97,251.39 157.07,251.38 133.17,251.45C131.1,251.46 130.29,250.9 130.62,248.77C130.99,246.4 131.29,244 131.37,241.6C131.43,239.79 132.23,239.45 133.84,239.45C158.48,239.39 183.12,239.26 207.77,239.21C209.84,239.2 211.44,239.02 211,236.08C184.8,236.08 158.61,236.08 132.05,236.08C132.8,232.53 133.32,229.27 134.27,226.14C134.49,225.41 136.22,224.73 137.26,224.73C162.73,224.69 188.21,224.73 213.69,224.79C215.45,224.79 216.83,224.59 216.98,222.08C189.85,222.08 162.79,222.08 135.06,222.08C136.9,217.08 138.46,212.57 140.29,208.17C140.55,207.54 142.04,207.13 142.96,207.12C156.16,207.06 169.36,207.01 182.55,207.13C185.39,207.16 186.89,205.74 188.53,203.24C173.01,203.24 157.9,203.24 142.12,203.24C144.45,199.04 146.41,195.32 148.6,191.75C148.96,191.16 150.32,190.96 151.21,190.95C167.65,190.91 184.08,190.8 200.51,191.01C204.37,191.06 207.34,189.61 210.35,187.38C190.94,187.38 171.54,187.38 151.29,187.38C152.68,185.33 153.63,183.86 154.66,182.45C159.42,175.89 159.43,175.9 167.58,175.9C189.4,175.89 211.23,175.89 233.06,175.89C233.94,175.89 234.81,175.89 236.22,175.89C234.09,173.68 232.46,172.15 229.61,172.17C208.69,172.26 187.78,172.21 166.86,172.21C165.9,172.21 164.94,172.21 163.98,172.21C163.85,171.98 163.72,171.75 163.59,171.51C165.64,169.44 167.65,167.32 169.77,165.32C175.92,159.52 175.94,159.41 184.39,159.57C196.85,159.79 208.61,163.22 219.95,168.09C222.99,169.4 225.62,170.09 228.87,168.6C231.4,167.44 234.35,167.17 237.47,166.71C235.1,171.08 237.95,173.17 240.44,175.52C243.51,178.42 246.46,181.46 249.43,184.48C250.05,185.12 250.52,185.91 251.41,187.09C250.2,187.15 249.44,187.23 248.68,187.24C243.45,187.24 238.22,187.39 233,187.19C217.94,186.61 205.3,192.15 194.56,202.33C190.72,205.97 187.3,210.05 183.71,213.95C183.34,214.35 183.13,214.89 182.52,215.9C200.74,209.5 217.89,201.2 237.06,200.53C237.21,200.78 237.37,201.03 237.52,201.28C235.25,203.93 233.13,206.73 230.69,209.21C220.98,219.12 215.17,231.05 212.49,244.52C211.74,248.31 211.79,252.26 211.15,256.3C210.08,256.43 209.34,256.4 208.59,256.37ZM219.33,207.12C221.4,207.13 223.49,206.96 225.55,207.17C228.53,207.49 230.34,206 232.27,203.13C227.37,204.29 223.07,205.3 218.77,206.35C218.77,206.35 218.89,206.85 219.33,207.12Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M208.38,256.38C209.34,256.4 210.08,256.43 211.05,256.48C211.35,258.14 211.43,259.79 211.51,261.44C211.81,261.54 212.1,261.64 212.39,261.75C213.62,259.93 214.86,258.11 216.4,256.13C217.71,255.93 218.73,255.87 219.92,255.81C220.68,255.74 221.25,255.63 221.82,255.62C228.3,255.53 234.79,255.46 241.52,255.42C243.38,255.48 244.99,255.51 246.61,255.53C246.01,259.12 245.37,262.7 244.81,266.29C242.28,282.55 241.91,298.87 243.1,315.49C241.78,315.89 240.68,316.05 239.58,316.21C209.45,316.2 179.32,316.14 149.2,316.25C146.34,316.26 144.74,315.41 143.73,312.8C142.73,310.21 141.43,307.74 140.02,304.71C143.48,304.71 146.35,304.71 149.23,304.71C178.19,304.71 207.16,304.72 236.12,304.69C237.21,304.69 238.73,305.34 238.98,303.29C239.23,301.22 238.3,300.81 236.42,300.82C215.59,300.87 194.75,300.85 173.92,300.85C162.97,300.85 152.01,300.82 141.06,300.92C139.16,300.94 138.18,300.36 137.66,298.55C136.78,295.46 135.74,292.42 134.51,288.53C169.6,288.39 204.12,288.52 238.88,288.45C238.95,287.2 239.01,286.17 239.08,284.95C238.06,284.89 237.26,284.82 236.45,284.81C205.16,284.8 173.88,284.78 142.59,284.78C140.18,284.78 137.78,284.93 135.37,284.87C134.76,284.85 133.72,284.39 133.63,283.97C132.73,279.8 131.99,275.6 131.15,271.1C135.68,271.1 139.63,271.09 143.59,271.11C144.67,271.12 145.74,271.33 146.81,271.33C176.85,271.34 206.9,271.34 236.94,271.34C240.2,271.34 240.33,271.2 240.3,267.48C204,267.48 167.69,267.48 130.92,267.48C130.76,263.91 130.53,260.64 130.6,257.37C130.61,256.95 132.18,256.22 133.03,256.21C141.16,256.1 149.3,256.11 157.43,256.11C166.89,256.1 176.35,256.07 185.81,256.11C193.26,256.15 200.71,256.3 208.38,256.38Z"
|
||||
android:fillColor="#BF43F5"/>
|
||||
<path
|
||||
android:pathData="M239.59,316.44C240.68,316.05 241.78,315.89 243.11,315.72C244.54,325.3 245.35,334.96 247.05,344.47C249.22,356.62 252.3,368.59 257.05,380.06C257.2,380.44 257.32,380.83 257.45,381.21C243.82,386.82 190.54,369.07 178.57,354.66C189.83,354.66 200.72,354.66 211.61,354.66C222.54,354.66 233.47,354.66 244.42,354.66C244.59,352.08 243.97,350.95 241.28,350.96C219.87,351.07 198.46,350.99 177.05,351.06C174.66,351.07 172.73,350.61 171.03,348.82C167.34,344.95 163.52,341.22 159.75,337.42C159.88,337.19 160,336.95 160.12,336.72C187.18,336.72 214.24,336.72 241.61,336.72C241.36,335.23 241.17,334.13 240.95,332.8C239.83,332.8 238.85,332.8 237.87,332.8C214.88,332.8 191.9,332.81 168.91,332.8C165.59,332.8 162.26,332.57 158.96,332.7C156.97,332.79 155.66,332.13 154.6,330.52C152.4,327.14 150.11,323.81 147.49,319.91C178.55,319.91 208.93,319.91 239.61,319.91C239.61,318.61 239.61,317.64 239.59,316.44Z"
|
||||
android:fillColor="#985DED"/>
|
||||
<path
|
||||
android:pathData="M258.44,316.48C259.75,316.25 261.04,316.25 262.54,316.24C262.8,317.31 262.85,318.38 262.92,319.73C296.42,319.73 329.83,319.73 364.01,319.73C362.33,322.39 361.03,324.54 359.64,326.62C355.54,332.81 355.53,332.8 348.25,332.8C321.86,332.8 295.46,332.8 269.07,332.8C268.09,332.8 267.11,332.8 266.16,332.8C265.84,336.39 266.08,336.68 269.29,336.68C295.68,336.68 322.08,336.68 348.47,336.68C349.44,336.68 350.4,336.68 352.17,336.68C350,339.11 348.17,340.87 346.68,342.88C341.82,349.43 335.64,351.54 327.37,351.23C309.64,350.55 291.86,351.02 274.09,351.02C273.11,351.02 272.13,351.02 271.17,351.02C271.02,354.12 271.48,354.66 274.17,354.66C292.68,354.66 311.19,354.66 329.7,354.66C330.65,354.66 331.6,354.66 332.54,354.66C332.62,354.89 332.7,355.12 332.78,355.35C330.9,356.75 329.07,358.22 327.14,359.56C314.53,368.29 300.74,374.45 285.87,378.18C284.11,378.62 282.23,378.92 280.46,378.76C279.45,378.68 278.23,377.74 277.63,376.83C272.53,369.18 269.33,360.66 266.33,352.02C262.35,340.53 260.11,328.68 258.44,316.48Z"
|
||||
android:fillColor="#985DED"/>
|
||||
<path
|
||||
android:pathData="M311.77,255.22C310.04,255.44 308.29,255.44 306.3,255.42C307.7,247.72 307.53,240.1 305.68,232.49C303.13,222.06 297.19,214.1 288.23,208.31C287.89,208.09 287.55,207.86 287.23,207.16C296.64,207.16 306.04,207.16 315.44,207.16C315.48,206.9 315.52,206.63 315.56,206.36C311.79,204.93 308.05,203.27 303.89,203.23C295.6,203.16 287.3,203.26 279,203.17C277.34,203.15 275.68,202.61 274.06,201.88C283.92,197.91 294.01,198.34 304.15,199.94C314.42,201.56 323.36,206.9 333.47,211.01C332.66,209.46 332.18,208.57 331.51,207.28C332.5,207.2 333.25,207.09 334.01,207.09C345.54,207.08 357.08,207.11 368.61,207.04C370.36,207.03 371.33,207.5 371.9,209.25C373.14,213.07 374.59,216.83 376.13,221.13C352.97,221.13 330.46,221.13 307.83,221.13C307.91,223.56 308.96,224.24 311,224.23C326.6,224.18 342.2,224.17 357.8,224.21C363.6,224.23 369.4,224.38 375.2,224.59C375.91,224.61 377.07,225.22 377.21,225.77C378.05,228.87 378.63,232.04 379.37,235.53C356.71,235.53 334.45,235.53 312.2,235.53C311.91,238.9 312.07,239.08 315,239.08C335.91,239.11 356.82,239.16 377.73,239.16C379.27,239.16 379.99,239.52 380.09,241.18C380.25,243.91 380.6,246.63 380.95,249.34C381.17,251.05 380.61,251.72 378.8,251.66C375.24,251.54 371.67,251.6 368.11,251.6C350.51,251.6 332.92,251.6 315.33,251.6C311.97,251.6 311.97,251.61 311.77,255.22Z"
|
||||
android:fillColor="#FF43C4"/>
|
||||
<path
|
||||
android:pathData="M233.67,133.02C256.13,129.25 277.19,131.88 288.96,135.95C287.31,139.82 285.66,143.69 284.01,147.55C283.13,149.6 282.1,151.61 281.39,153.73C280.81,155.48 279.79,155.91 278.06,155.9C266.2,155.83 254.34,155.87 241.85,155.87C243.96,158.04 245.54,159.78 248.45,159.75C257.41,159.67 266.37,159.72 275.33,159.73C276.24,159.73 277.14,159.73 278.95,159.73C276.99,163 275.7,166.08 273.6,168.43C270.3,172.11 266.39,175.23 262.88,178.73C261.53,180.08 260.9,180.03 259.6,178.61C254.3,172.8 248.97,167.01 243.39,161.48C237.24,155.37 229.44,152.84 220.98,151.86C213.46,150.99 206.32,152.38 199.27,154.82C197.58,155.4 195.74,155.75 193.96,155.82C190.07,155.97 186.17,155.86 182.15,155.55C197.45,143.96 214.61,136.59 233.67,133.02ZM262.52,174.52C263.06,173.88 263.6,173.24 264.46,172.22C262.24,172.22 260.62,172.22 258.52,172.22C259.34,173.38 259.78,174.29 260.48,174.87C260.83,175.15 261.67,174.84 262.52,174.52Z"
|
||||
android:fillColor="#FF42C3"/>
|
||||
<path
|
||||
android:pathData="M320.81,196.15C314.32,190.85 306.7,188.96 298.84,187.82C289.74,186.5 280.81,187.01 271.96,190.85C272.47,189.92 272.88,188.91 273.51,188.06C281.91,176.57 292.26,167.25 304.84,160.58C306.74,159.57 309.33,159.62 311.6,159.59C318.82,159.47 326.04,159.5 333.26,159.59C334.35,159.6 335.69,159.93 336.45,160.63C340.22,164 343.83,167.55 347.48,171.05C347.69,171.25 347.78,171.57 348.11,172.21C346.93,172.21 346.05,172.21 345.18,172.21C328.58,172.21 311.98,172.28 295.39,172.15C292.59,172.13 291.04,173.55 288.95,175.9C290.46,175.9 291.4,175.9 292.33,175.9C311.17,175.9 330.01,175.93 348.85,175.85C351,175.84 352.47,176.48 353.68,178.19C355.68,181.01 357.78,183.76 360.24,187.08C343.65,187.08 327.73,187.08 311.82,187.08C311.79,187.29 311.76,187.49 311.74,187.69C315.27,189 318.39,191.09 322.57,191.01C335.01,190.76 347.46,190.96 359.91,190.88C361.92,190.87 363.16,191.51 364.06,193.28C365.66,196.45 367.39,199.54 369.27,203.03C368.03,203.11 367.26,203.21 366.48,203.21C354.44,203.21 342.41,203.18 330.38,203.24C328.66,203.25 327.4,202.81 326.24,201.52C324.58,199.67 322.72,198.01 320.81,196.15Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M262.01,255.48C260.8,255.48 259.59,255.49 258.15,255.49C259.26,241.21 260.47,226.92 264.71,213.11C265.34,211.06 266.03,210.16 268.06,211.62C270.08,213.06 272.41,214.16 274.15,215.88C286.01,227.55 297.17,239.78 304.4,255.23C302.46,255.42 300.45,255.45 298.21,255.28C297.55,252.82 296.4,251.87 293.9,251.91C284.4,252.06 274.9,251.97 265.39,251.98C264.34,251.98 263.3,251.98 262.01,251.98C262.01,253.37 262.01,254.43 262.01,255.48ZM263.18,238.86C271.2,238.86 279.22,238.86 287.25,238.86C287.34,238.56 287.43,238.26 287.52,237.96C286.55,237.47 285.57,236.58 284.58,236.57C277.89,236.44 271.2,236.51 264.5,236.49C262.98,236.48 262.3,237.02 263.18,238.86ZM268.75,222.05C266.99,221.93 265.42,222.05 265.71,224.51C268.73,224.51 271.68,224.51 274.73,224.51C273.54,221.78 271.35,221.98 268.75,222.05Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M246.72,255.38C244.99,255.51 243.38,255.48 241.58,255.22C241.46,254.11 241.53,253.25 241.62,252.02C235.47,252.02 229.64,252.02 223.81,252.02C220.63,252.03 220.2,252.43 219.74,255.82C218.73,255.87 217.71,255.93 216.49,255.98C218.93,250.76 221.21,245.3 224.33,240.35C229.86,231.57 236.13,223.3 244.52,216.92C248.39,213.97 252.62,211.77 257.32,210.49C257.93,210.32 258.57,210.3 259.92,210.12C254.32,225.13 249.77,239.96 246.72,255.38ZM232.91,235.63C230.52,235.4 229.98,237.18 228.98,239.19C234.28,239.19 239.23,239.12 244.17,239.22C246.42,239.27 247.04,238.27 246.74,235.68C242.23,235.68 237.78,235.68 232.91,235.63ZM251.08,223.33C250.49,222.98 249.91,222.38 249.29,222.32C247.73,222.17 246.14,222.34 244.57,222.24C242.56,222.12 241.44,223.18 240.32,225.2C243.65,225.2 246.59,225.26 249.52,225.13C250.03,225.11 250.51,224.24 251.08,223.33Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M302.88,140.38C312.51,144.32 321.39,149.16 329.57,155.7C313.1,154.61 297.42,157.52 282.02,164.18C282.47,161.67 283.3,160.12 285.45,159.45C288.6,158.48 291.72,157.43 294.83,155.97C292.13,155.97 289.42,155.97 285.99,155.97C289.14,149.79 291.98,144.13 294.96,138.55C295.17,138.15 296.47,138.03 297.12,138.23C299.02,138.8 300.85,139.61 302.88,140.38Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
</vector>
|
||||
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 256 KiB |
@@ -0,0 +1,39 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:pathData="M317.52,168.37C318.06,168.37 318.6,168.38 319.65,168.41C322.37,168.43 324.58,168.42 326.79,168.41C349.49,168.43 372.2,168.43 394.91,168.46C400.46,168.47 406.02,168.65 411.58,168.6C413.68,168.59 414.71,169.12 414.54,171.43C414.35,174.26 414.33,177.1 414.37,179.94C414.4,182.64 413.52,183.71 410.51,183.7C377.29,183.59 344.07,183.65 310.85,183.66C295.82,183.66 280.79,183.66 265.75,183.66C264.61,183.66 263.47,183.66 262.06,183.66C262.06,185.29 262.06,186.7 262.06,188.5C312.31,188.5 362.6,188.5 413.71,188.5C412.65,194.11 411.74,199.21 410.66,204.28C410.55,204.83 409.53,205.38 408.84,205.56C407.95,205.78 406.96,205.62 406.01,205.62C359.34,205.62 312.66,205.62 265.99,205.62C264.75,205.62 263.51,205.62 262.03,205.62C262.03,207.2 262.03,208.49 262.03,210.18C310.9,210.18 359.72,210.18 409.36,210.18C408.27,213.87 407.4,217.03 406.39,220.15C404.52,225.95 404.48,225.94 398.53,225.94C354.38,225.94 310.22,225.95 266.07,225.92C263.76,225.91 261.86,226.09 262.84,229.08C263.07,229.81 264.11,230.46 264.92,230.77C265.65,231.06 266.58,230.84 267.42,230.84C310.84,230.84 354.26,230.84 397.67,230.84C399.01,230.84 400.34,230.84 402.55,230.84C400.14,235.79 398.2,240.17 395.86,244.32C395.42,245.11 393.44,245.31 392.17,245.31C373.14,245.37 354.11,245.35 335.08,245.35C313.54,245.35 291.98,245.35 270.43,245.35C268.66,245.35 266.89,245.26 264.63,245.33C262.52,245.45 260.88,245.45 259.24,245.46C258.67,240.67 257.69,235.9 257.58,231.11C257.21,213.69 257.06,196.26 257.01,178.84C257,175.52 257.85,172.2 258.72,168.69C260.68,168.49 262.21,168.48 264.04,168.51C279.33,168.53 294.33,168.5 309.62,168.47C312.44,168.44 314.98,168.4 317.52,168.37Z"
|
||||
android:fillColor="#BF42F6"/>
|
||||
<path
|
||||
android:pathData="M196.08,169.6C196.08,167.63 196.08,165.67 196.08,163.27C194.45,163.27 192.91,163.27 191.37,163.27C161.1,163.29 130.82,163.28 100.54,163.37C97.92,163.38 96.9,162.67 97.32,159.97C97.78,156.97 98.17,153.93 98.27,150.9C98.34,148.6 99.36,148.17 101.4,148.17C132.61,148.1 163.82,147.94 195.04,147.86C197.66,147.86 199.69,147.63 199.14,143.9C165.95,143.9 132.78,143.9 99.13,143.9C100.08,139.41 100.73,135.27 101.94,131.31C102.23,130.39 104.41,129.53 105.72,129.53C137.99,129.47 170.27,129.52 202.54,129.6C204.76,129.61 206.52,129.34 206.71,126.17C172.35,126.17 138.07,126.17 102.94,126.17C105.27,119.84 107.26,114.13 109.56,108.55C109.89,107.76 111.78,107.23 112.96,107.22C129.67,107.14 146.39,107.08 163.1,107.23C166.69,107.27 168.59,105.48 170.67,102.31C151.01,102.31 131.87,102.31 111.88,102.31C114.84,96.98 117.32,92.27 120.09,87.75C120.55,87 122.27,86.74 123.4,86.74C144.22,86.68 165.04,86.54 185.85,86.82C190.74,86.88 194.5,85.04 198.31,82.21C173.73,82.21 149.15,82.21 123.5,82.21C125.26,79.62 126.46,77.76 127.76,75.97C133.8,67.66 133.81,67.67 144.13,67.67C171.78,67.67 199.43,67.67 227.08,67.67C228.19,67.67 229.29,67.67 231.08,67.67C228.38,64.86 226.32,62.93 222.7,62.94C196.21,63.06 169.72,63.01 143.22,63.01C142.01,63.01 140.79,63.01 139.58,63.01C139.41,62.71 139.24,62.41 139.08,62.12C141.68,59.5 144.22,56.8 146.91,54.27C154.7,46.92 154.72,46.79 165.43,46.98C181.21,47.26 196.1,51.61 210.47,57.78C214.32,59.44 217.65,60.31 221.76,58.43C224.98,56.95 228.71,56.61 232.67,56.03C229.67,61.57 233.27,64.22 236.42,67.19C240.32,70.87 244.05,74.72 247.81,78.54C248.6,79.35 249.19,80.35 250.32,81.84C248.78,81.93 247.82,82.03 246.87,82.03C240.24,82.04 233.61,82.23 227,81.97C207.93,81.24 191.92,88.26 178.31,101.15C173.45,105.76 169.11,110.93 164.57,115.87C164.1,116.38 163.83,117.06 163.06,118.34C186.14,110.23 207.86,99.73 232.14,98.87C232.34,99.18 232.53,99.5 232.73,99.82C229.85,103.18 227.16,106.72 224.07,109.87C211.77,122.42 204.42,137.53 201.03,154.6C200.07,159.39 200.14,164.4 199.32,169.51C197.97,169.68 197.03,169.64 196.08,169.6ZM209.68,107.22C212.31,107.23 214.96,107.01 217.56,107.29C221.34,107.69 223.62,105.8 226.08,102.17C219.87,103.64 214.42,104.92 208.98,106.24C208.98,106.24 209.12,106.87 209.68,107.22Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M195.81,169.61C197.03,169.64 197.97,169.68 199.2,169.74C199.58,171.84 199.68,173.93 199.79,176.02C200.15,176.15 200.52,176.28 200.89,176.41C202.45,174.11 204.02,171.8 205.97,169.3C207.64,169.04 208.92,168.97 210.44,168.9C211.39,168.81 212.11,168.66 212.84,168.65C221.05,168.54 229.27,168.45 237.79,168.4C240.14,168.48 242.19,168.51 244.24,168.54C243.48,173.08 242.67,177.61 241.96,182.16C238.76,202.76 238.29,223.44 239.8,244.49C238.12,244.99 236.72,245.2 235.33,245.4C197.17,245.39 159.01,245.31 120.85,245.45C117.22,245.46 115.21,244.38 113.93,241.08C112.65,237.8 111,234.67 109.23,230.84C113.61,230.84 117.25,230.84 120.89,230.84C157.58,230.84 194.27,230.85 230.96,230.81C232.33,230.8 234.26,231.63 234.58,229.04C234.9,226.41 233.71,225.89 231.33,225.9C204.94,225.97 178.55,225.94 152.17,225.95C138.29,225.95 124.42,225.9 110.54,226.03C108.13,226.05 106.9,225.32 106.24,223.03C105.12,219.12 103.81,215.26 102.24,210.34C146.69,210.16 190.42,210.32 234.45,210.24C234.54,208.65 234.62,207.35 234.7,205.8C233.41,205.73 232.39,205.63 231.38,205.63C191.74,205.61 152.11,205.59 112.48,205.59C109.43,205.59 106.38,205.78 103.34,205.7C102.57,205.68 101.25,205.09 101.13,204.56C99.99,199.28 99.05,193.95 97.99,188.26C103.72,188.26 108.74,188.24 113.75,188.28C115.11,188.29 116.47,188.55 117.83,188.55C155.88,188.57 193.94,188.57 231.99,188.56C236.12,188.56 236.28,188.39 236.25,183.67C190.27,183.67 144.28,183.67 97.69,183.67C97.5,179.15 97.2,175.01 97.29,170.87C97.3,170.33 99.29,169.41 100.37,169.4C110.67,169.26 120.97,169.28 131.28,169.27C143.26,169.26 155.24,169.22 167.23,169.28C176.66,169.33 186.1,169.51 195.81,169.61Z"
|
||||
android:fillColor="#BF43F5"/>
|
||||
<path
|
||||
android:pathData="M235.35,245.69C236.72,245.2 238.12,244.99 239.8,244.78C241.62,256.91 242.64,269.16 244.79,281.19C247.54,296.59 251.45,311.75 257.46,326.28C257.66,326.75 257.8,327.25 257.96,327.73C240.7,334.84 173.22,312.36 158.05,294.11C172.31,294.11 186.11,294.11 199.9,294.11C213.75,294.11 227.59,294.11 241.47,294.11C241.67,290.83 240.89,289.4 237.49,289.42C210.37,289.55 183.25,289.46 156.13,289.54C153.11,289.55 150.66,288.97 148.51,286.71C143.83,281.81 138.99,277.07 134.22,272.27C134.38,271.97 134.53,271.67 134.69,271.38C168.96,271.38 203.24,271.38 237.91,271.38C237.59,269.49 237.35,268.09 237.06,266.42C235.66,266.42 234.41,266.42 233.17,266.42C204.05,266.42 174.93,266.43 145.82,266.41C141.61,266.41 137.4,266.12 133.21,266.29C130.69,266.4 129.04,265.57 127.7,263.52C124.9,259.24 122.01,255.03 118.68,250.09C158.03,250.09 196.51,250.09 235.37,250.09C235.37,248.43 235.37,247.21 235.35,245.69Z"
|
||||
android:fillColor="#985DED"/>
|
||||
<path
|
||||
android:pathData="M259.22,245.74C260.88,245.45 262.52,245.45 264.42,245.44C264.74,246.79 264.81,248.15 264.9,249.86C307.33,249.86 349.65,249.86 392.94,249.86C390.82,253.23 389.17,255.95 387.42,258.59C382.22,266.42 382.21,266.42 372.98,266.42C339.55,266.42 306.12,266.42 272.68,266.42C271.45,266.42 270.21,266.42 269.01,266.42C268.6,270.97 268.9,271.32 272.97,271.32C306.4,271.33 339.83,271.33 373.27,271.33C374.49,271.33 375.71,271.33 377.95,271.33C375.2,274.41 372.88,276.64 370.99,279.18C364.84,287.47 357,290.15 346.54,289.75C324.07,288.9 301.55,289.49 279.05,289.49C277.81,289.49 276.57,289.49 275.34,289.49C275.16,293.42 275.74,294.1 279.15,294.1C302.59,294.11 326.04,294.1 349.48,294.11C350.69,294.11 351.89,294.11 353.09,294.11C353.19,294.39 353.29,294.68 353.39,294.97C351.01,296.75 348.69,298.61 346.25,300.3C330.27,311.36 312.8,319.17 293.96,323.9C291.74,324.45 289.36,324.83 287.12,324.64C285.84,324.52 284.3,323.33 283.54,322.19C277.07,312.49 273.01,301.7 269.22,290.75C264.17,276.21 261.34,261.2 259.22,245.74Z"
|
||||
android:fillColor="#985DED"/>
|
||||
<path
|
||||
android:pathData="M326.78,168.15C324.58,168.42 322.37,168.43 319.85,168.39C321.63,158.65 321.41,149 319.06,139.36C315.84,126.14 308.31,116.06 296.96,108.73C296.52,108.45 296.09,108.16 295.7,107.28C307.61,107.28 319.52,107.28 331.43,107.28C331.48,106.93 331.53,106.59 331.57,106.25C326.8,104.44 322.07,102.34 316.8,102.29C306.29,102.2 295.77,102.33 285.27,102.21C283.16,102.19 281.07,101.5 279.01,100.57C291.5,95.55 304.29,96.1 317.13,98.13C330.14,100.18 341.45,106.94 354.27,112.15C353.23,110.19 352.63,109.05 351.78,107.42C353.03,107.32 353.99,107.18 354.94,107.18C369.55,107.16 384.16,107.21 398.77,107.12C400.99,107.11 402.21,107.7 402.93,109.91C404.51,114.76 406.34,119.52 408.3,124.96C378.96,124.96 350.45,124.96 321.79,124.96C321.89,128.04 323.22,128.9 325.8,128.89C345.56,128.82 365.32,128.82 385.08,128.87C392.43,128.89 399.77,129.08 407.11,129.34C408.02,129.37 409.48,130.14 409.67,130.85C410.73,134.77 411.47,138.78 412.41,143.2C383.7,143.2 355.5,143.2 327.33,143.2C326.95,147.48 327.15,147.7 330.87,147.7C357.35,147.74 383.84,147.81 410.32,147.8C412.27,147.8 413.19,148.26 413.31,150.37C413.52,153.82 413.96,157.26 414.41,160.69C414.69,162.87 413.98,163.71 411.68,163.63C407.17,163.48 402.65,163.56 398.13,163.56C375.85,163.56 353.57,163.56 331.29,163.56C327.03,163.56 327.03,163.57 326.78,168.15Z"
|
||||
android:fillColor="#FF43C4"/>
|
||||
<path
|
||||
android:pathData="M227.85,13.36C256.3,8.58 282.98,11.91 297.89,17.06C295.79,21.98 293.7,26.87 291.61,31.76C290.5,34.37 289.2,36.91 288.3,39.59C287.56,41.8 286.27,42.35 284.07,42.34C269.05,42.26 254.03,42.3 238.21,42.3C240.88,45.05 242.88,47.26 246.57,47.22C257.92,47.11 269.27,47.18 280.62,47.19C281.77,47.19 282.91,47.19 285.21,47.19C282.72,51.33 281.09,55.24 278.43,58.21C274.25,62.87 269.29,66.82 264.85,71.26C263.14,72.97 262.34,72.9 260.7,71.1C253.98,63.75 247.23,56.42 240.16,49.4C232.38,41.67 222.49,38.46 211.78,37.23C202.25,36.13 193.21,37.88 184.27,40.97C182.14,41.71 179.81,42.15 177.55,42.24C172.62,42.42 167.68,42.29 162.59,41.89C181.97,27.22 203.7,17.88 227.85,13.36ZM264.4,65.93C265.08,65.12 265.76,64.31 266.85,63.01C264.04,63.01 261.99,63.01 259.33,63.01C260.37,64.48 260.92,65.63 261.81,66.37C262.25,66.73 263.32,66.32 264.4,65.93Z"
|
||||
android:fillColor="#FF42C3"/>
|
||||
<path
|
||||
android:pathData="M338.22,93.32C330,86.61 320.35,84.22 310.4,82.77C298.87,81.1 287.56,81.75 276.35,86.62C276.99,85.43 277.52,84.16 278.31,83.08C288.95,68.53 302.06,56.72 317.99,48.27C320.4,46.99 323.68,47.06 326.56,47.01C335.71,46.86 344.86,46.9 354,47.01C355.37,47.02 357.07,47.45 358.04,48.33C362.81,52.6 367.39,57.09 372.01,61.53C372.28,61.78 372.38,62.19 372.81,63.01C371.31,63.01 370.2,63.01 369.09,63.01C348.07,63.01 327.04,63.08 306.02,62.93C302.48,62.9 300.52,64.7 297.87,67.67C299.78,67.67 300.97,67.67 302.15,67.67C326.02,67.67 349.88,67.71 373.74,67.6C376.46,67.59 378.32,68.41 379.86,70.57C382.39,74.14 385.05,77.63 388.18,81.84C367.16,81.84 347,81.84 326.84,81.84C326.8,82.1 326.77,82.35 326.73,82.61C331.21,84.27 335.15,86.92 340.45,86.81C356.21,86.5 371.98,86.75 387.75,86.65C390.3,86.63 391.87,87.45 393.01,89.69C395.03,93.7 397.23,97.61 399.61,102.04C398.04,102.14 397.06,102.26 396.07,102.26C380.83,102.27 365.59,102.23 350.34,102.31C348.17,102.32 346.58,101.76 345.1,100.13C343,97.79 340.64,95.68 338.22,93.32Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M263.75,168.47C262.21,168.48 260.68,168.49 258.86,168.49C260.26,150.4 261.8,132.3 267.17,114.8C267.96,112.21 268.84,111.07 271.41,112.92C273.97,114.75 276.92,116.14 279.13,118.31C294.14,133.1 308.29,148.58 317.44,168.16C314.98,168.4 312.44,168.44 309.6,168.22C308.77,165.11 307.31,163.9 304.14,163.95C292.11,164.14 280.07,164.03 268.03,164.04C266.7,164.04 265.38,164.04 263.75,164.04C263.75,165.81 263.75,167.14 263.75,168.47ZM265.23,147.42C275.39,147.42 285.55,147.42 295.71,147.42C295.83,147.04 295.95,146.66 296.07,146.28C294.82,145.66 293.59,144.54 292.34,144.52C283.86,144.36 275.38,144.45 266.9,144.42C264.98,144.41 264.11,145.09 265.23,147.42ZM272.28,126.13C270.05,125.98 268.06,126.13 268.44,129.24C272.26,129.24 276,129.24 279.86,129.24C278.35,125.79 275.57,126.04 272.28,126.13Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M244.37,168.35C242.19,168.51 240.14,168.48 237.87,168.14C237.72,166.74 237.8,165.65 237.92,164.1C230.12,164.1 222.74,164.09 215.35,164.1C211.33,164.1 210.79,164.62 210.2,168.9C208.92,168.97 207.64,169.04 206.08,169.11C209.18,162.49 212.07,155.57 216.01,149.32C223.02,138.18 230.96,127.72 241.59,119.63C246.5,115.89 251.86,113.11 257.81,111.49C258.58,111.28 259.39,111.25 261.09,111.02C254,130.03 248.24,148.81 244.37,168.35ZM226.88,143.34C223.86,143.04 223.17,145.3 221.91,147.84C228.63,147.84 234.89,147.75 241.15,147.88C244,147.94 244.78,146.68 244.4,143.4C238.69,143.4 233.05,143.4 226.88,143.34ZM249.9,127.76C249.15,127.31 248.42,126.55 247.63,126.47C245.66,126.28 243.65,126.49 241.66,126.37C239.1,126.21 237.69,127.56 236.27,130.12C240.49,130.12 244.21,130.2 247.93,130.03C248.58,130 249.17,128.9 249.9,127.76Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
<path
|
||||
android:pathData="M315.52,22.68C327.71,27.67 338.96,33.8 349.32,42.08C328.46,40.7 308.6,44.4 289.08,52.83C289.67,49.65 290.71,47.68 293.44,46.84C297.43,45.61 301.38,44.27 305.32,42.43C301.9,42.43 298.47,42.43 294.12,42.43C298.11,34.6 301.71,27.44 305.48,20.37C305.75,19.86 307.39,19.71 308.22,19.96C310.62,20.69 312.94,21.7 315.52,22.68Z"
|
||||
android:fillColor="#FF44C4"/>
|
||||
</vector>
|
||||
@@ -48,7 +48,7 @@
|
||||
android:layout_height="200dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:src="@drawable/ic_yuzu_named" />
|
||||
android:src="@drawable/ic_yuzu_title" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
|
||||
@@ -44,11 +44,12 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_logo"
|
||||
android:layout_width="160dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_marginVertical="24dp"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="28dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:src="@drawable/ic_yuzu_named" />
|
||||
android:src="@drawable/ic_yuzu_title" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/EdenCard"
|
||||
|
||||