mirror of
https://git.citron-emu.org/Citron/Citron.git
synced 2025-03-15 03:14:50 +00:00
Compare commits
139 commits
v0.4-canar
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
21594b73aa | ||
|
d869045b77 | ||
|
f2931c7566 | ||
|
12c63997d2 | ||
|
1023125be5 | ||
|
dad8859679 | ||
|
834cc89548 | ||
|
38b259d099 | ||
|
e7e9453667 | ||
|
ae75413cc3 | ||
|
6a31da5905 | ||
|
a5125d008a | ||
|
b24dd921aa | ||
|
9a65205dba | ||
|
af4f08be33 | ||
|
0d0963d32f | ||
|
4491127f52 | ||
|
c304afe2b3 | ||
|
b8240b4214 | ||
|
91487f6d96 | ||
|
031c635095 | ||
|
90a8165f77 | ||
|
6565055865 | ||
|
ee3d858935 | ||
|
31694994f2 | ||
|
4197fa84a0 | ||
|
e4342324fe | ||
|
78b0080b96 | ||
|
644ed69285 | ||
|
3554f55fc9 | ||
|
dc9532b4d1 | ||
|
1308e2b935 | ||
|
5caecd8151 | ||
|
dc9fbcc893 | ||
|
b1d5d4e5be | ||
|
f0d8daf755 | ||
|
cbb9a35166 | ||
|
cfe437aacf | ||
|
9b293c3a98 | ||
|
84e5fbc089 | ||
|
a442078ee4 | ||
|
cc610ad9b6 | ||
|
5a65f9a094 | ||
|
5ca1f0e365 | ||
|
a36baad0f0 | ||
|
ed115d3f72 | ||
|
d9619b7eed | ||
|
dbe5bf1d18 | ||
|
7903415fa4 | ||
|
3bb4d97e9e | ||
|
a41f7b7a56 | ||
|
18f8a0f997 | ||
|
4d50d2ba16 | ||
|
0576d40bf0 | ||
|
6917530ba5 | ||
|
43495b6045 | ||
|
c5e480e55d | ||
|
1c9e17496b | ||
|
7730d14b4a | ||
|
677b8f476a | ||
|
5cbde61d3c | ||
|
33a1996ca4 | ||
|
a7af4d001b | ||
|
ef884ce39c | ||
|
1aad9fd4e3 | ||
|
f45f339ef9 | ||
|
298e797592 | ||
|
8bfafb4755 | ||
|
33d54e595f | ||
|
13ada2d705 | ||
|
8bf4660bac | ||
|
b07751ed43 | ||
|
b3c60b4cbe | ||
|
dcf6f9a071 | ||
|
b42a0fb227 | ||
|
5af4803e42 | ||
|
becaf850ab | ||
|
d4ad55ed21 | ||
|
6e16a8db1c | ||
|
384a18927b | ||
|
76716b5248 | ||
|
6917a22a2c | ||
|
646af3c143 | ||
|
d1b7aebe8c | ||
|
d783806b1e | ||
|
268d322d7f | ||
|
92b70b31e0 | ||
|
4792ba752e | ||
|
b8fe6b6f7c | ||
|
0acfbc5fa1 | ||
|
e3128c6e98 | ||
|
b89a85e228 | ||
|
cc48197448 | ||
|
0010882f36 | ||
|
28350f7af8 | ||
|
7ecb890a16 | ||
|
c31768ec15 | ||
|
227db142e2 | ||
|
3aa9c0d151 | ||
|
7b6495aced | ||
|
d4eca46bba | ||
|
df1ae19742 | ||
|
4cc01f6c71 | ||
|
89ecb641f1 | ||
|
3857e6afe9 | ||
|
42f44a0c09 | ||
|
94c4ef8946 | ||
|
14065ae7cb | ||
|
9eb32d2d85 | ||
|
71e652123b | ||
|
ddd5e7e887 | ||
|
6b9c239fbd | ||
|
cf43fd8038 | ||
|
a1cbcee7ab | ||
|
19ce9d695e | ||
|
44944c4d80 | ||
|
8bda64895f | ||
|
f4b9e54b22 | ||
|
70a9f20ae1 | ||
|
076d0e618d | ||
|
ecc32958ec | ||
|
e8bbdbce42 | ||
|
0216eaa071 | ||
|
137034ca2c | ||
|
8f76ef2579 | ||
|
4e8d00f034 | ||
|
f638922129 | ||
|
a96216ff35 | ||
|
6ab82e8eeb | ||
|
733721f0a1 | ||
|
613099703a | ||
|
9a3d4f0489 | ||
|
8c630a8bea | ||
|
2e4db14bc1 | ||
|
c36151d6e3 | ||
|
33f8cd0c7e | ||
|
c5a2689cef | ||
|
f380744c61 | ||
|
b7e11d3724 |
319 changed files with 5533 additions and 862 deletions
12
.gitmodules
vendored
12
.gitmodules
vendored
|
@ -9,22 +9,22 @@
|
||||||
url = https://github.com/mozilla/cubeb.git
|
url = https://github.com/mozilla/cubeb.git
|
||||||
[submodule "dynarmic"]
|
[submodule "dynarmic"]
|
||||||
path = externals/dynarmic
|
path = externals/dynarmic
|
||||||
url = https://github.com/yuzu-mirror/dynarmic.git
|
url = https://git.citron-emu.org/Citron/dynarmic.git
|
||||||
[submodule "libusb"]
|
[submodule "libusb"]
|
||||||
path = externals/libusb/libusb
|
path = externals/libusb/libusb
|
||||||
url = https://github.com/libusb/libusb.git
|
url = https://github.com/libusb/libusb.git
|
||||||
[submodule "discord-rpc"]
|
[submodule "discord-rpc"]
|
||||||
path = externals/discord-rpc
|
path = externals/discord-rpc
|
||||||
url = https://github.com/yuzu-mirror/discord-rpc.git
|
url = https://git.citron-emu.org/Citron/discord-rpc.git
|
||||||
[submodule "Vulkan-Headers"]
|
[submodule "Vulkan-Headers"]
|
||||||
path = externals/Vulkan-Headers
|
path = externals/Vulkan-Headers
|
||||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||||
[submodule "sirit"]
|
[submodule "sirit"]
|
||||||
path = externals/sirit
|
path = externals/sirit
|
||||||
url = https://github.com/yuzu-mirror/sirit.git
|
url = https://git.citron-emu.org/Citron/sirit.git
|
||||||
[submodule "mbedtls"]
|
[submodule "mbedtls"]
|
||||||
path = externals/mbedtls
|
path = externals/mbedtls
|
||||||
url = https://github.com/yuzu-mirror/mbedtls.git
|
url = https://git.citron-emu.org/Citron/mbedtls.git
|
||||||
[submodule "xbyak"]
|
[submodule "xbyak"]
|
||||||
path = externals/xbyak
|
path = externals/xbyak
|
||||||
url = https://github.com/herumi/xbyak.git
|
url = https://github.com/herumi/xbyak.git
|
||||||
|
@ -57,13 +57,13 @@
|
||||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||||
[submodule "breakpad"]
|
[submodule "breakpad"]
|
||||||
path = externals/breakpad
|
path = externals/breakpad
|
||||||
url = https://github.com/yuzu-mirror/breakpad.git
|
url = https://git.citron-emu.org/Citron/breakpad.git
|
||||||
[submodule "simpleini"]
|
[submodule "simpleini"]
|
||||||
path = externals/simpleini
|
path = externals/simpleini
|
||||||
url = https://github.com/brofield/simpleini.git
|
url = https://github.com/brofield/simpleini.git
|
||||||
[submodule "oaknut"]
|
[submodule "oaknut"]
|
||||||
path = externals/oaknut
|
path = externals/oaknut
|
||||||
url = https://github.com/yuzu-mirror/oaknut
|
url = https://git.citron-emu.org/Citron/oaknut.git
|
||||||
[submodule "Vulkan-Utility-Libraries"]
|
[submodule "Vulkan-Utility-Libraries"]
|
||||||
path = externals/Vulkan-Utility-Libraries
|
path = externals/Vulkan-Utility-Libraries
|
||||||
url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
|
url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
|
||||||
|
|
114
CMakeLists.txt
114
CMakeLists.txt
|
@ -17,6 +17,45 @@ if (MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# PGO Configuration
|
||||||
|
option(CITRON_ENABLE_PGO_INSTRUMENT "Enable Profile-Guided Optimization instrumentation build" OFF)
|
||||||
|
option(CITRON_ENABLE_PGO_OPTIMIZE "Enable Profile-Guided Optimization optimization build" OFF)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
if(CITRON_ENABLE_PGO_INSTRUMENT)
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_RELEASE " /GL /LTCG:PGINSTRUMENT")
|
||||||
|
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " /LTCG:PGINSTRUMENT")
|
||||||
|
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " /LTCG:PGINSTRUMENT")
|
||||||
|
elseif(CITRON_ENABLE_PGO_OPTIMIZE)
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_RELEASE " /GL /LTCG:PGOPTIMIZE")
|
||||||
|
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " /LTCG:PGOPTIMIZE")
|
||||||
|
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " /LTCG:PGOPTIMIZE")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# GCC and Clang PGO flags
|
||||||
|
if(CITRON_ENABLE_PGO_INSTRUMENT)
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -fprofile-instr-generate")
|
||||||
|
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -fprofile-instr-generate")
|
||||||
|
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " -fprofile-instr-generate")
|
||||||
|
else() # GCC
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -fprofile-generate")
|
||||||
|
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -fprofile-generate")
|
||||||
|
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " -fprofile-generate")
|
||||||
|
endif()
|
||||||
|
elseif(CITRON_ENABLE_PGO_OPTIMIZE)
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -fprofile-instr-use=default.profdata")
|
||||||
|
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -fprofile-instr-use=default.profdata")
|
||||||
|
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " -fprofile-instr-use=default.profdata")
|
||||||
|
else() # GCC
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_RELEASE " -fprofile-use")
|
||||||
|
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -fprofile-use")
|
||||||
|
string(APPEND CMAKE_SHARED_LINKER_FLAGS_RELEASE " -fprofile-use")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Check if SDL2::SDL2 target exists; if not, create an alias
|
# Check if SDL2::SDL2 target exists; if not, create an alias
|
||||||
if (TARGET SDL2::SDL2-static)
|
if (TARGET SDL2::SDL2-static)
|
||||||
add_library(SDL2::SDL2 ALIAS SDL2::SDL2-static)
|
add_library(SDL2::SDL2 ALIAS SDL2::SDL2-static)
|
||||||
|
@ -98,21 +137,22 @@ endif()
|
||||||
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
|
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
|
||||||
|
|
||||||
if (ANDROID AND CITRON_DOWNLOAD_ANDROID_VVL)
|
if (ANDROID AND CITRON_DOWNLOAD_ANDROID_VVL)
|
||||||
set(vvl_version "sdk-1.3.261.1")
|
set(vvl_version "1.4.304.1")
|
||||||
set(vvl_zip_file "${CMAKE_BINARY_DIR}/externals/vvl-android.zip")
|
set(vvl_zip_file "${CMAKE_BINARY_DIR}/externals/vvl-android.zip")
|
||||||
if (NOT EXISTS "${vvl_zip_file}")
|
|
||||||
# Download and extract validation layer release to externals directory
|
|
||||||
set(vvl_base_url "https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download")
|
|
||||||
file(DOWNLOAD "${vvl_base_url}/${vvl_version}/android-binaries-${vvl_version}-android.zip"
|
|
||||||
"${vvl_zip_file}" SHOW_PROGRESS)
|
|
||||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${vvl_zip_file}"
|
|
||||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Copy the arm64 binary to src/android/app/main/jniLibs only if it doesn't exist
|
|
||||||
set(vvl_lib_path "${CMAKE_CURRENT_SOURCE_DIR}/src/android/app/src/main/jniLibs/arm64-v8a/")
|
set(vvl_lib_path "${CMAKE_CURRENT_SOURCE_DIR}/src/android/app/src/main/jniLibs/arm64-v8a/")
|
||||||
set(vvl_lib_file "${vvl_lib_path}/libVkLayer_khronos_validation.so")
|
set(vvl_final_lib "${vvl_lib_path}/libVkLayer_khronos_validation.so")
|
||||||
if (NOT EXISTS "${vvl_lib_file}")
|
|
||||||
|
if (NOT EXISTS "${vvl_final_lib}")
|
||||||
|
# Download and extract validation layer release to externals directory
|
||||||
|
if (NOT EXISTS "${vvl_zip_file}")
|
||||||
|
set(vvl_base_url "https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download")
|
||||||
|
file(DOWNLOAD "${vvl_base_url}/vulkan-sdk-${vvl_version}/android-binaries-${vvl_version}.zip"
|
||||||
|
"${vvl_zip_file}" SHOW_PROGRESS)
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${vvl_zip_file}"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Copy the arm64 binary to src/android/app/main/jniLibs
|
||||||
file(COPY "${CMAKE_BINARY_DIR}/externals/android-binaries-${vvl_version}/arm64-v8a/libVkLayer_khronos_validation.so"
|
file(COPY "${CMAKE_BINARY_DIR}/externals/android-binaries-${vvl_version}/arm64-v8a/libVkLayer_khronos_validation.so"
|
||||||
DESTINATION "${vvl_lib_path}")
|
DESTINATION "${vvl_lib_path}")
|
||||||
endif()
|
endif()
|
||||||
|
@ -129,22 +169,29 @@ if (CITRON_USE_BUNDLED_VCPKG)
|
||||||
|
|
||||||
if (CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
|
if (CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
|
||||||
set(VCPKG_TARGET_TRIPLET "arm64-android")
|
set(VCPKG_TARGET_TRIPLET "arm64-android")
|
||||||
|
set(VCPKG_HOST_TRIPLET "x64-windows")
|
||||||
# this is to avoid CMake using the host pkg-config to find the host
|
# this is to avoid CMake using the host pkg-config to find the host
|
||||||
# libraries when building for Android targets
|
# libraries when building for Android targets
|
||||||
set(PKG_CONFIG_EXECUTABLE "aarch64-none-linux-android-pkg-config" CACHE FILEPATH "" FORCE)
|
set(PKG_CONFIG_EXECUTABLE "aarch64-none-linux-android-pkg-config" CACHE FILEPATH "" FORCE)
|
||||||
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")
|
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")
|
||||||
set(VCPKG_TARGET_TRIPLET "x64-android")
|
set(VCPKG_TARGET_TRIPLET "x64-android")
|
||||||
|
set(VCPKG_HOST_TRIPLET "x64-windows")
|
||||||
set(PKG_CONFIG_EXECUTABLE "x86_64-none-linux-android-pkg-config" CACHE FILEPATH "" FORCE)
|
set(PKG_CONFIG_EXECUTABLE "x86_64-none-linux-android-pkg-config" CACHE FILEPATH "" FORCE)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unsupported Android architecture ${CMAKE_ANDROID_ARCH_ABI}")
|
message(FATAL_ERROR "Unsupported Android architecture ${CMAKE_ANDROID_ARCH_ABI}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Add these lines to ensure proper Android toolchain setup
|
||||||
|
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${ANDROID_NDK}/build/cmake/android.toolchain.cmake")
|
||||||
|
set(VCPKG_CRT_LINKAGE "dynamic")
|
||||||
|
set(VCPKG_LIBRARY_LINKAGE "static")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set(VCPKG_DOWNLOADS_PATH ${PROJECT_SOURCE_DIR}/externals/vcpkg/downloads)
|
set(VCPKG_DOWNLOADS_PATH ${PROJECT_SOURCE_DIR}/externals/vcpkg/downloads)
|
||||||
set(NASM_VERSION "2.16.01")
|
set(NASM_VERSION "2.16.03")
|
||||||
set(NASM_DESTINATION_PATH ${VCPKG_DOWNLOADS_PATH}/nasm-${NASM_VERSION}-win64.zip)
|
set(NASM_DESTINATION_PATH ${VCPKG_DOWNLOADS_PATH}/nasm-${NASM_VERSION}-win64.zip)
|
||||||
set(NASM_DOWNLOAD_URL "https://github.com/yuzu-mirror/ext-windows-bin/raw/master/nasm/nasm-${NASM_VERSION}-win64.zip")
|
set(NASM_DOWNLOAD_URL "https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}/win64/nasm-${NASM_VERSION}-win64.zip")
|
||||||
|
|
||||||
if (NOT EXISTS ${NASM_DESTINATION_PATH})
|
if (NOT EXISTS ${NASM_DESTINATION_PATH})
|
||||||
file(DOWNLOAD ${NASM_DOWNLOAD_URL} ${NASM_DESTINATION_PATH} SHOW_PROGRESS STATUS NASM_STATUS)
|
file(DOWNLOAD ${NASM_DOWNLOAD_URL} ${NASM_DESTINATION_PATH} SHOW_PROGRESS STATUS NASM_STATUS)
|
||||||
|
@ -231,7 +278,7 @@ endif()
|
||||||
if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
|
if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
|
||||||
message(STATUS "Downloading compatibility list for citron...")
|
message(STATUS "Downloading compatibility list for citron...")
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
https://api.yuzu-mirror.org/gamedb/
|
https://api.citron-emu.org/gamedb/
|
||||||
"${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS)
|
"${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS)
|
||||||
endif()
|
endif()
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
|
if (NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
|
||||||
|
@ -312,7 +359,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||||
# Enforce the search mode of non-required packages for better and shorter failure messages
|
# Enforce the search mode of non-required packages for better and shorter failure messages
|
||||||
find_package(Boost REQUIRED context)
|
find_package(Boost REQUIRED context)
|
||||||
find_package(enet MODULE)
|
find_package(enet MODULE)
|
||||||
find_package(fmt 9 REQUIRED)
|
find_package(fmt 11 REQUIRED)
|
||||||
if (CITRON_USE_LLVM_DEMANGLE)
|
if (CITRON_USE_LLVM_DEMANGLE)
|
||||||
find_package(LLVM MODULE COMPONENTS Demangle)
|
find_package(LLVM MODULE COMPONENTS Demangle)
|
||||||
endif()
|
endif()
|
||||||
|
@ -327,7 +374,7 @@ find_package(ZLIB REQUIRED)
|
||||||
find_package(zstd REQUIRED)
|
find_package(zstd REQUIRED)
|
||||||
|
|
||||||
if (NOT CITRON_USE_EXTERNAL_VULKAN_HEADERS)
|
if (NOT CITRON_USE_EXTERNAL_VULKAN_HEADERS)
|
||||||
find_package(VulkanHeaders 1.4.304 REQUIRED)
|
find_package(VulkanHeaders 1.4.307 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT CITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
|
if (NOT CITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
|
||||||
|
@ -335,19 +382,19 @@ if (NOT CITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_LIBUSB)
|
if (ENABLE_LIBUSB)
|
||||||
find_package(libusb 1.0.24 MODULE)
|
find_package(libusb MODULE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||||
find_package(xbyak 6 CONFIG)
|
find_package(xbyak CONFIG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_arm64)
|
if (ARCHITECTURE_arm64)
|
||||||
find_package(oaknut 2.0.1 CONFIG)
|
find_package(oaknut CONFIG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||||
find_package(dynarmic 6.4.0 CONFIG)
|
find_package(dynarmic CONFIG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_CUBEB)
|
if (ENABLE_CUBEB)
|
||||||
|
@ -359,12 +406,12 @@ if (USE_DISCORD_PRESENCE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_WEB_SERVICE)
|
if (ENABLE_WEB_SERVICE)
|
||||||
find_package(cpp-jwt 1.4 CONFIG)
|
find_package(cpp-jwt CONFIG)
|
||||||
find_package(httplib 0.12 MODULE COMPONENTS OpenSSL)
|
find_package(httplib MODULE COMPONENTS OpenSSL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CITRON_TESTS)
|
if (CITRON_TESTS)
|
||||||
find_package(Catch2 3.0.1 REQUIRED)
|
find_package(Catch2 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# boost:asio has functions that require AcceptEx et al
|
# boost:asio has functions that require AcceptEx et al
|
||||||
|
@ -373,11 +420,11 @@ if (MINGW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_OPENSSL)
|
if(ENABLE_OPENSSL)
|
||||||
find_package(OpenSSL 1.1.1 REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
find_package(gamemode 1.7 MODULE)
|
find_package(gamemode MODULE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Please consider this as a stub
|
# Please consider this as a stub
|
||||||
|
@ -390,7 +437,7 @@ if (ENABLE_SDL2)
|
||||||
if (CITRON_USE_BUNDLED_SDL2)
|
if (CITRON_USE_BUNDLED_SDL2)
|
||||||
# Detect toolchain and platform
|
# Detect toolchain and platform
|
||||||
if ((MSVC_VERSION GREATER_EQUAL 1920) AND ARCHITECTURE_x86_64)
|
if ((MSVC_VERSION GREATER_EQUAL 1920) AND ARCHITECTURE_x86_64)
|
||||||
set(SDL2_VER "SDL2-2.28.2")
|
set(SDL2_VER "SDL2-2.32.0")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable CITRON_USE_BUNDLED_SDL2 and provide your own.")
|
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable CITRON_USE_BUNDLED_SDL2 and provide your own.")
|
||||||
endif()
|
endif()
|
||||||
|
@ -416,10 +463,13 @@ endif()
|
||||||
|
|
||||||
add_subdirectory(externals)
|
add_subdirectory(externals)
|
||||||
|
|
||||||
|
if (USE_DISCORD_PRESENCE)
|
||||||
|
target_compile_options(discord-rpc PRIVATE -fpermissive)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (ENABLE_QT)
|
if (ENABLE_QT)
|
||||||
if (NOT USE_SYSTEM_QT)
|
if (NOT USE_SYSTEM_QT)
|
||||||
download_qt(6.7.3)
|
download_qt(6.8.2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent Network)
|
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent Network)
|
||||||
|
@ -484,7 +534,7 @@ list(APPEND CITRON_QT_COMPONENTS2 Multimedia)
|
||||||
endif()
|
endif()
|
||||||
if (NOT CITRON_USE_BUNDLED_FFMPEG)
|
if (NOT CITRON_USE_BUNDLED_FFMPEG)
|
||||||
# Use system installed FFmpeg
|
# Use system installed FFmpeg
|
||||||
find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
|
find_package(FFmpeg REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_QT)
|
if(ENABLE_QT)
|
||||||
|
@ -534,7 +584,7 @@ endif()
|
||||||
# against all the src files. This should be used before making a pull request.
|
# against all the src files. This should be used before making a pull request.
|
||||||
# =======================================================================
|
# =======================================================================
|
||||||
|
|
||||||
set(CLANG_FORMAT_POSTFIX "-15")
|
set(CLANG_FORMAT_POSTFIX "-18")
|
||||||
find_program(CLANG_FORMAT
|
find_program(CLANG_FORMAT
|
||||||
NAMES clang-format${CLANG_FORMAT_POSTFIX}
|
NAMES clang-format${CLANG_FORMAT_POSTFIX}
|
||||||
clang-format
|
clang-format
|
||||||
|
@ -545,7 +595,7 @@ if (NOT CLANG_FORMAT)
|
||||||
message(STATUS "Clang format not found! Downloading...")
|
message(STATUS "Clang format not found! Downloading...")
|
||||||
set(CLANG_FORMAT "${PROJECT_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe")
|
set(CLANG_FORMAT "${PROJECT_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe")
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
https://github.com/yuzu-mirror/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe
|
https://git.citron-emu.org/Citron/ext-windows-bin/raw/master/clang-format${CLANG_FORMAT_POSTFIX}.exe
|
||||||
"${CLANG_FORMAT}" SHOW_PROGRESS
|
"${CLANG_FORMAT}" SHOW_PROGRESS
|
||||||
STATUS DOWNLOAD_SUCCESS)
|
STATUS DOWNLOAD_SUCCESS)
|
||||||
if (NOT DOWNLOAD_SUCCESS EQUAL 0)
|
if (NOT DOWNLOAD_SUCCESS EQUAL 0)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
set(CURRENT_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR})
|
set(CURRENT_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||||
function(download_bundled_external remote_path lib_name prefix_var)
|
function(download_bundled_external remote_path lib_name prefix_var)
|
||||||
|
|
||||||
set(package_base_url "https://github.com/yuzu-mirror/")
|
set(package_base_url "https://git.citron-emu.org/Citron/")
|
||||||
set(package_repo "no_platform")
|
set(package_repo "no_platform")
|
||||||
set(package_extension "no_platform")
|
set(package_extension "no_platform")
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
@ -68,18 +68,18 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
|
||||||
set(arch_path "mingw_64")
|
set(arch_path "mingw_64")
|
||||||
elseif (MSVC)
|
elseif (MSVC)
|
||||||
if ("arm64" IN_LIST ARCHITECTURE)
|
if ("arm64" IN_LIST ARCHITECTURE)
|
||||||
set(arch_path "msvc2019_arm64")
|
set(arch_path "msvc2022_arm64")
|
||||||
elseif ("x86_64" IN_LIST ARCHITECTURE)
|
elseif ("x86_64" IN_LIST ARCHITECTURE)
|
||||||
set(arch_path "msvc2019_64")
|
set(arch_path "msvc2022_64")
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.")
|
message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.")
|
||||||
endif()
|
endif()
|
||||||
set(arch "win64_${arch_path}")
|
set(arch "win64_${arch_path}")
|
||||||
|
|
||||||
if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64")
|
if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64")
|
||||||
set(host_arch_path "msvc2019_64")
|
set(host_arch_path "msvc2022_64")
|
||||||
elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||||
set(host_arch_path "msvc2019_64")
|
set(host_arch_path "msvc2022_64")
|
||||||
endif()
|
endif()
|
||||||
set(host_arch "win64_${host_arch_path}")
|
set(host_arch "win64_${host_arch_path}")
|
||||||
else()
|
else()
|
||||||
|
@ -134,12 +134,12 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
|
||||||
else()
|
else()
|
||||||
set(prefix "${base_path}/${target}/${arch_path}")
|
set(prefix "${base_path}/${target}/${arch_path}")
|
||||||
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch}
|
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch}
|
||||||
-m qtmultimedia --archives qttranslations qttools qtsvg qtbase)
|
-m all)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT EXISTS "${prefix}")
|
if (NOT EXISTS "${prefix}")
|
||||||
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
|
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
|
||||||
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.1.18")
|
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.2.0")
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(aqt_path "${base_path}/aqt.exe")
|
set(aqt_path "${base_path}/aqt.exe")
|
||||||
if (NOT EXISTS "${aqt_path}")
|
if (NOT EXISTS "${aqt_path}")
|
||||||
|
|
4
dist/languages/ar.ts
vendored
4
dist/languages/ar.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">موقعنا</span></a>|<a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">رماز المصدر</span></a>|<a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">المساهمون</span></a>|<a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">الرخصة</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">موقعنا</span></a>|<a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">رماز المصدر</span></a>|<a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">المساهمون</span></a>|<a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">الرخصة</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/ca.ts
vendored
4
dist/languages/ca.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Pàgina web</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Codi Font</span></a>|<a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuïdors</span></a>|<a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Llicència</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Pàgina web</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Codi Font</span></a>|<a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuïdors</span></a>|<a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Llicència</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/cs.ts
vendored
4
dist/languages/cs.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Webové stránky</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Zdrojový kód</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Přispěvatelé</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licence</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Webové stránky</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Zdrojový kód</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Přispěvatelé</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licence</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/da.ts
vendored
4
dist/languages/da.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/">Netsted<span style=" text-decoration: underline; color:#039be5;"></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Kildekode</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Bidragsydere</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licens</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/">Netsted<span style=" text-decoration: underline; color:#039be5;"></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Kildekode</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Bidragsydere</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licens</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/de.ts
vendored
4
dist/languages/de.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Webseite</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Quellcode</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Mitwirkende</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lizenz</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Webseite</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Quellcode</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Mitwirkende</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lizenz</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/el.ts
vendored
4
dist/languages/el.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Ιστοσελίδα</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Πηγαίος Κώδικας</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Συνεργάτες</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"></span>Άδεια</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Ιστοσελίδα</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Πηγαίος Κώδικας</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Συνεργάτες</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"></span>Άδεια</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/es.ts
vendored
4
dist/languages/es.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Página web</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Código fuente</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuidores</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licencia</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Página web</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Código fuente</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuidores</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licencia</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/fi.ts
vendored
4
dist/languages/fi.ts
vendored
|
@ -40,8 +40,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="118"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="118"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Nettisivu</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Lähdekoodi</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Lahjoittajat</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Lisenssi</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Nettisivu</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Lähdekoodi</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Lahjoittajat</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Lisenssi</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="134"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="134"/>
|
||||||
|
|
4
dist/languages/fr.ts
vendored
4
dist/languages/fr.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Site Web</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Code Source</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributeurs</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licence</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Site Web</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Code Source</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributeurs</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licence</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/hu.ts
vendored
4
dist/languages/hu.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Weboldal</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Forráskód</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Közreműködők</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licensz</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Weboldal</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Forráskód</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Közreműködők</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licensz</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/id.ts
vendored
4
dist/languages/id.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Situs web</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Kode Sumber</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Kontributor</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lisensi</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Situs web</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Kode Sumber</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Kontributor</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lisensi</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/it.ts
vendored
4
dist/languages/it.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Sito web</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Codice sorgente</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributori</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licenza</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Sito web</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Codice sorgente</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributori</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licenza</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/ja_JP.ts
vendored
4
dist/languages/ja_JP.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">ウェブサイト</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">ソースコード</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">貢献者</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">ライセンス</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">ウェブサイト</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">ソースコード</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">貢献者</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">ライセンス</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/ko_KR.ts
vendored
4
dist/languages/ko_KR.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">웹사이트</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">소스 코드</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">기여자</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">라이센스</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">웹사이트</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">소스 코드</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">기여자</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">라이센스</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/nb.ts
vendored
4
dist/languages/nb.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Nettside</span></a>|<a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Kildekode</span></a>|<a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Bidragsytere</span></a>|<a href="https://github.com/citron-emu/citron/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Lisens</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Nettside</span></a>|<a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Kildekode</span></a>|<a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Bidragsytere</span></a>|<a href="https://git.citron-emu.org/Citron/Citron/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Lisens</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/nl.ts
vendored
4
dist/languages/nl.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Broncode</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Bijdragers</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licentie</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Broncode</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Bijdragers</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licentie</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/pl.ts
vendored
4
dist/languages/pl.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Strona</span></a>I<a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Kod Źródłowy</span></a>I<a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Kontrybutorzy</span></a>I<a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licencja</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Strona</span></a>I<a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Kod Źródłowy</span></a>I<a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Kontrybutorzy</span></a>I<a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licencja</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/pt_BR.ts
vendored
4
dist/languages/pt_BR.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Site</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Código-fonte</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Colaboradores</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licença</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Site</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Código-fonte</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Colaboradores</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licença</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/pt_PT.ts
vendored
4
dist/languages/pt_PT.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation>Site | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Código fonte | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuidores</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licença</span></a></p></body></html></translation>
|
<translation>Site | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Código fonte | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contribuidores</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licença</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/ru_RU.ts
vendored
4
dist/languages/ru_RU.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Веб-сайт</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Исходный код</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Контрибьюторы</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Лицензия</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Веб-сайт</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Исходный код</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Контрибьюторы</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Лицензия</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/sv.ts
vendored
4
dist/languages/sv.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Hemsida</span></a>I<a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Källkod</span></a>I<a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Bidragsgivare</span></a>I<a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licens</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Hemsida</span></a>I<a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Källkod</span></a>I<a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Bidragsgivare</span></a>I<a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Licens</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/tr_TR.ts
vendored
4
dist/languages/tr_TR.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a>|<a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Kaynak Kodu</span></a>|<a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Katkıda Bulunanlar</span></a>|<a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lisans</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a>|<a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Kaynak Kodu</span></a>|<a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Katkıda Bulunanlar</span></a>|<a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Lisans</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/uk.ts
vendored
4
dist/languages/uk.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Веб-сайт</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Першокод</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Вкладники</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Ліцензія</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Веб-сайт</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Першокод</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Вкладники</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Ліцензія</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/vi.ts
vendored
4
dist/languages/vi.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Trang web</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Mã nguồn</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Người đóng góp</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Giấy phép</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Trang web</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Mã nguồn</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Người đóng góp</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">Giấy phép</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/vi_VN.ts
vendored
4
dist/languages/vi_VN.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Trang web</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Mã nguồn</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Đóng góp</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Giấy phép</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Trang web</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Mã nguồn</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Đóng góp</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/license.txt"><span style=" text-decoration: underline; color:#039be5;">Giấy phép</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/zh_CN.ts
vendored
4
dist/languages/zh_CN.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">官方网站</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">源代码</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">贡献者</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">许可证</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">官方网站</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">源代码</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">贡献者</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">许可证</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/languages/zh_TW.ts
vendored
4
dist/languages/zh_TW.ts
vendored
|
@ -35,8 +35,8 @@ p, li { white-space: pre-wrap; }
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="130"/>
|
||||||
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
<source><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">Website</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">Source Code</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">Contributors</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">License</span></a></p></body></html></source>
|
||||||
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">官網</span></a> | <a href="https://github.com/citron-emu"><span style=" text-decoration: underline; color:#039be5;">原始碼</span></a> | <a href="https://github.com/citron-emu/citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">貢獻者</span></a> | <a href="https://github.com/citron-emu/citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">許可證</span></a></p></body></html></translation>
|
<translation><html><head/><body><p><a href="https://citron-emu.org/"><span style=" text-decoration: underline; color:#039be5;">官網</span></a> | <a href="https://git.citron-emu.org"><span style=" text-decoration: underline; color:#039be5;">原始碼</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/graphs/contributors"><span style=" text-decoration: underline; color:#039be5;">貢獻者</span></a> | <a href="https://git.citron-emu.org/Citron/Citron/blob/master/LICENSE.txt"><span style=" text-decoration: underline; color:#039be5;">許可證</span></a></p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
<location filename="../../src/citron/aboutdialog.ui" line="146"/>
|
||||||
|
|
4
dist/org.citron_emu.citron.metainfo.xml
vendored
4
dist/org.citron_emu.citron.metainfo.xml
vendored
|
@ -25,13 +25,13 @@ SPDX-License-Identifier: CC0-1.0
|
||||||
<keyword>emulator</keyword>
|
<keyword>emulator</keyword>
|
||||||
</keywords>
|
</keywords>
|
||||||
<url type="homepage">https://citron-emu.org/</url>
|
<url type="homepage">https://citron-emu.org/</url>
|
||||||
<url type="bugtracker">https://github.com/citron-emu/citron/issues</url>
|
<url type="bugtracker">https://git.citron-emu.org/Citron/Citron/issues</url>
|
||||||
<url type="faq">https://citron-emu.org/wiki/faq/</url>
|
<url type="faq">https://citron-emu.org/wiki/faq/</url>
|
||||||
<url type="help">https://citron-emu.org/wiki/home/</url>
|
<url type="help">https://citron-emu.org/wiki/home/</url>
|
||||||
<url type="donation">https://citron-emu.org/donate/</url>
|
<url type="donation">https://citron-emu.org/donate/</url>
|
||||||
<url type="translate">https://www.transifex.com/projects/p/citron</url>
|
<url type="translate">https://www.transifex.com/projects/p/citron</url>
|
||||||
<url type="contact">https://community.citra-emu.org/</url>
|
<url type="contact">https://community.citra-emu.org/</url>
|
||||||
<url type="vcs-browser">https://github.com/citron-emu/citron</url>
|
<url type="vcs-browser">https://git.citron-emu.org/Citron/Citron</url>
|
||||||
<url type="contribute">https://citron-emu.org/wiki/contributing/</url>
|
<url type="contribute">https://citron-emu.org/wiki/contributing/</url>
|
||||||
<launchable type="desktop-id">org.citron_emu.citron.desktop</launchable>
|
<launchable type="desktop-id">org.citron_emu.citron.desktop</launchable>
|
||||||
<provides>
|
<provides>
|
||||||
|
|
BIN
dist/qt_themes/default/icons/256x256/citron.png
vendored
BIN
dist/qt_themes/default/icons/256x256/citron.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 12 KiB |
2
externals/Vulkan-Headers
vendored
2
externals/Vulkan-Headers
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit a03d2f6d5753b365d704d58161825890baad0755
|
Subproject commit cacef3039d277c448c89336290ec3937270b0996
|
2
externals/Vulkan-Utility-Libraries
vendored
2
externals/Vulkan-Utility-Libraries
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 7b23ba7a5f86936a8d783baf64a77c38977d6890
|
Subproject commit bc3a4d9fd9b46729651a3cec4f5226f6272b8684
|
2
externals/VulkanMemoryAllocator
vendored
2
externals/VulkanMemoryAllocator
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 7ab8483d10b665ba8d478e1502380c40e2374ac7
|
Subproject commit c788c52156f3ef7bc7ab769cb03c110a53ac8fcb
|
2
externals/cpp-httplib
vendored
2
externals/cpp-httplib
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit a609330e4c6374f741d3b369269f7848255e1954
|
Subproject commit 39a64fb4e7e42216f14f0ec51ccc5fa85e651432
|
2
externals/cpp-jwt
vendored
2
externals/cpp-jwt
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 10ef5735d842b31025f1257ae78899f50a40fb14
|
Subproject commit 4a970bc302d671476122cbc6b43cc89fbf4a96ec
|
2
externals/enet
vendored
2
externals/enet
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 39a72ab1990014eb399cee9d538fd529df99c6a0
|
Subproject commit 657eaf97d9d335917c58484a4a4b5e03838ebd8e
|
2
externals/ffmpeg/ffmpeg
vendored
2
externals/ffmpeg/ffmpeg
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 9c1294eaddb88cb0e044c675ccae059a85fc9c6c
|
Subproject commit 99e2af4e7837ca09b97d93a562dc12947179fc48
|
2
externals/libadrenotools
vendored
2
externals/libadrenotools
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 5cd3f5c5ceea6d9e9d435ccdd922d9b99e55d10b
|
Subproject commit 8fae8ce254dfc1344527e05301e43f37dea2df80
|
2
externals/libusb/libusb
vendored
2
externals/libusb/libusb
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit c060e9ce30ac2e3ffb49d94209c4dae77b6642f7
|
Subproject commit de38189e8014fa393f4d8c1d9d3fdf5e2a95899d
|
2
externals/oaknut
vendored
2
externals/oaknut
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 9d091109deb445bc6e9289c6195a282b7c993d49
|
Subproject commit 94c726ce0338b054eb8cb5ea91de8fe6c19f4392
|
2
externals/opus
vendored
2
externals/opus
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 101a71e03bbf860aaafb7090a0e440675cb27660
|
Subproject commit 734aed05d09af3d2690f8cb5aafa97f052746daf
|
2
externals/simpleini
vendored
2
externals/simpleini
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit 382ddbb4b92c0b26aa1b32cefba2002119a5b1f2
|
Subproject commit 6048871ea9ee0ec24be5bd099d161a10567d7dc2
|
2
externals/vcpkg
vendored
2
externals/vcpkg
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit cf035d9916a0a23042b41fcae7ee0386d245af08
|
Subproject commit e40d24cb149dd138e7c11d490834fa2c81298b32
|
|
@ -1,4 +1,5 @@
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: 2025 citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
@ -27,20 +28,20 @@ val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toIn
|
||||||
android {
|
android {
|
||||||
namespace = "org.citron.citron_emu"
|
namespace = "org.citron.citron_emu"
|
||||||
|
|
||||||
compileSdkVersion = "android-34"
|
compileSdkVersion = "android-35"
|
||||||
ndkVersion = "27.2.12479018" // "27.2.12479018" // "28.0.12433566 rc1"// "28.0.12674087 rc2" // "26.1.10909125"
|
ndkVersion = "29.0.13113456 rc1" // "26.1.10909125"
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_21
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_21
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "17"
|
jvmTarget = "21"
|
||||||
}
|
}
|
||||||
|
|
||||||
packaging {
|
packaging {
|
||||||
|
@ -54,9 +55,10 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO If this is ever modified, change application_id in strings.xml
|
// TODO If this is ever modified, change application_id in strings.xml
|
||||||
applicationId = "org.citron.citron_emu"
|
applicationId = "com.antutu.ABenchMark"
|
||||||
minSdk = 30
|
minSdk = 30
|
||||||
targetSdk = 34
|
//noinspection EditedTargetSdkVersion
|
||||||
|
targetSdk = 35
|
||||||
versionName = getGitVersion()
|
versionName = getGitVersion()
|
||||||
|
|
||||||
versionCode = if (System.getenv("AUTO_VERSIONED") == "true") {
|
versionCode = if (System.getenv("AUTO_VERSIONED") == "true") {
|
||||||
|
@ -103,10 +105,10 @@ android {
|
||||||
signingConfigs.getByName("default")
|
signingConfigs.getByName("default")
|
||||||
}
|
}
|
||||||
|
|
||||||
resValue("string", "app_name_suffixed", "citron")
|
resValue("string", "app_name_suffixed", "Citron")
|
||||||
isDefault = true
|
isDefault = true
|
||||||
isShrinkResources = true
|
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
|
isShrinkResources = true
|
||||||
isJniDebuggable = false
|
isJniDebuggable = false
|
||||||
isDebuggable = false
|
isDebuggable = false
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
|
@ -118,9 +120,8 @@ android {
|
||||||
// builds a release build that doesn't need signing
|
// builds a release build that doesn't need signing
|
||||||
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
||||||
register("relWithDebInfo") {
|
register("relWithDebInfo") {
|
||||||
resValue("string", "app_name_suffixed", "citron Debug Release")
|
resValue("string", "app_name_suffixed", "Citron Debug Release")
|
||||||
signingConfig = signingConfigs.getByName("default")
|
signingConfig = signingConfigs.getByName("default")
|
||||||
isMinifyEnabled = true
|
|
||||||
isDebuggable = true
|
isDebuggable = true
|
||||||
proguardFiles(
|
proguardFiles(
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
@ -135,7 +136,7 @@ android {
|
||||||
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
||||||
debug {
|
debug {
|
||||||
signingConfig = signingConfigs.getByName("default")
|
signingConfig = signingConfigs.getByName("default")
|
||||||
resValue("string", "app_name_suffixed", "citron Debug")
|
resValue("string", "app_name_suffixed", "Citron Debug")
|
||||||
isDebuggable = true
|
isDebuggable = true
|
||||||
isJniDebuggable = true
|
isJniDebuggable = true
|
||||||
versionNameSuffix = "-debug"
|
versionNameSuffix = "-debug"
|
||||||
|
@ -148,7 +149,7 @@ android {
|
||||||
create("mainline") {
|
create("mainline") {
|
||||||
isDefault = true
|
isDefault = true
|
||||||
dimension = "version"
|
dimension = "version"
|
||||||
buildConfigField("Boolean", "PREMIUM", "true") // Spoof EA Version
|
buildConfigField("Boolean", "PREMIUM", "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
create("ea") {
|
create("ea") {
|
||||||
|
@ -160,7 +161,7 @@ android {
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
version = "3.22.1"
|
version = "3.31.6"
|
||||||
path = file("../../../CMakeLists.txt")
|
path = file("../../../CMakeLists.txt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,23 +178,24 @@ android {
|
||||||
"-DCITRON_USE_BUNDLED_VCPKG=ON",
|
"-DCITRON_USE_BUNDLED_VCPKG=ON",
|
||||||
"-DCITRON_USE_BUNDLED_FFMPEG=ON",
|
"-DCITRON_USE_BUNDLED_FFMPEG=ON",
|
||||||
"-DCITRON_ENABLE_LTO=ON",
|
"-DCITRON_ENABLE_LTO=ON",
|
||||||
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
|
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
|
||||||
|
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
||||||
)
|
)
|
||||||
|
|
||||||
abiFilters("arm64-v8a")
|
abiFilters("arm64-v8a") // , "x86_64")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.create<Delete>("ktlintReset") { // Deprecated, Still Works.
|
tasks.create<Delete>("ktlintReset") {
|
||||||
delete(File(buildDir.path + File.separator + "intermediates/ktLint"))
|
delete(File(buildDir.path + File.separator + "intermediates/ktLint"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val showFormatHelp = {
|
val showFormatHelp = {
|
||||||
logger.lifecycle(
|
logger.lifecycle(
|
||||||
"If this check fails, please try running \"gradlew ktlintFormat\" for automatic " +
|
"If this check fails, please try running \"gradlew ktlintFormat\" for automatic " +
|
||||||
"codestyle fixes"
|
"codestyle fixes"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() }
|
tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() }
|
||||||
|
@ -204,7 +206,7 @@ ktlint {
|
||||||
version.set("0.47.1")
|
version.set("0.47.1")
|
||||||
android.set(true)
|
android.set(true)
|
||||||
ignoreFailures.set(false)
|
ignoreFailures.set(false)
|
||||||
disabledRules.set( // Deprecated, Still Works.
|
disabledRules.set(
|
||||||
setOf(
|
setOf(
|
||||||
"no-wildcard-imports",
|
"no-wildcard-imports",
|
||||||
"package-name",
|
"package-name",
|
||||||
|
@ -238,7 +240,6 @@ dependencies {
|
||||||
implementation("io.coil-kt:coil:2.2.2")
|
implementation("io.coil-kt:coil:2.2.2")
|
||||||
implementation("androidx.core:core-splashscreen:1.0.1")
|
implementation("androidx.core:core-splashscreen:1.0.1")
|
||||||
implementation("androidx.window:window:1.2.0-beta03")
|
implementation("androidx.window:window:1.2.0-beta03")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
|
||||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
|
implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
|
||||||
implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
|
implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
|
||||||
|
|
7
src/android/app/proguard-rules.pro
vendored
7
src/android/app/proguard-rules.pro
vendored
|
@ -22,3 +22,10 @@
|
||||||
-dontwarn java.beans.Introspector
|
-dontwarn java.beans.Introspector
|
||||||
-dontwarn java.beans.VetoableChangeListener
|
-dontwarn java.beans.VetoableChangeListener
|
||||||
-dontwarn java.beans.VetoableChangeSupport
|
-dontwarn java.beans.VetoableChangeSupport
|
||||||
|
|
||||||
|
# LicenseVerifier protection
|
||||||
|
-keep class org.citron.citron_emu.utils.LicenseVerifier { *; }
|
||||||
|
-keepnames class org.citron.citron_emu.utils.LicenseVerifier
|
||||||
|
-dontskipnonpubliclibraryclasses
|
||||||
|
-dontoptimize
|
||||||
|
-dontpreverify
|
||||||
|
|
|
@ -14,6 +14,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.NFC" />
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
|
|
@ -21,6 +21,8 @@ import org.citron.citron_emu.utils.Log
|
||||||
import org.citron.citron_emu.model.InstallResult
|
import org.citron.citron_emu.model.InstallResult
|
||||||
import org.citron.citron_emu.model.Patch
|
import org.citron.citron_emu.model.Patch
|
||||||
import org.citron.citron_emu.model.GameVerificationResult
|
import org.citron.citron_emu.model.GameVerificationResult
|
||||||
|
import org.citron.citron_emu.network.NetPlayManager
|
||||||
|
import java.net.NetworkInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class which contains methods that interact
|
* Class which contains methods that interact
|
||||||
|
@ -242,6 +244,27 @@ object NativeLibrary {
|
||||||
return coreErrorAlertResult
|
return coreErrorAlertResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
@JvmStatic
|
||||||
|
fun addNetPlayMessage(type: Int, message: String) {
|
||||||
|
val emulationActivity = sEmulationActivity.get()
|
||||||
|
if (emulationActivity != null) {
|
||||||
|
emulationActivity.addNetPlayMessages(type, message)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NetPlayManager.addNetPlayMessage(type, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
@JvmStatic
|
||||||
|
fun clearChat() {
|
||||||
|
NetPlayManager.clearChat()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
external fun netPlayInit()
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun exitEmulationActivity(resultCode: Int) {
|
fun exitEmulationActivity(resultCode: Int) {
|
||||||
|
@ -459,4 +482,29 @@ object NativeLibrary {
|
||||||
* Checks if all necessary keys are present for decryption
|
* Checks if all necessary keys are present for decryption
|
||||||
*/
|
*/
|
||||||
external fun areKeysPresent(): Boolean
|
external fun areKeysPresent(): Boolean
|
||||||
|
|
||||||
|
fun getNetworkInterfaces(): Array<String> {
|
||||||
|
val interfaceList = mutableListOf<String>()
|
||||||
|
try {
|
||||||
|
NetworkInterface.getNetworkInterfaces()?.toList()?.forEach { iface ->
|
||||||
|
if (iface.isUp && !iface.isLoopback) {
|
||||||
|
iface.inetAddresses.toList()
|
||||||
|
.filterNot { it.isLoopbackAddress }
|
||||||
|
.forEach { addr ->
|
||||||
|
interfaceList.add("${iface.name};${addr.hostAddress}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.error("[NativeLibrary] Failed to enumerate network interfaces: ${e.message}")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always ensure we have at least a loopback interface
|
||||||
|
if (interfaceList.isEmpty()) {
|
||||||
|
Log.warning("[NativeLibrary] No interfaces found, adding loopback fallback")
|
||||||
|
interfaceList.add("lo;127.0.0.1")
|
||||||
|
}
|
||||||
|
|
||||||
|
return interfaceList.toTypedArray()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package org.citron.citron_emu.activities
|
package org.citron.citron_emu.activities
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.AlertDialog
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.PictureInPictureParams
|
import android.app.PictureInPictureParams
|
||||||
import android.app.RemoteAction
|
import android.app.RemoteAction
|
||||||
|
@ -39,12 +40,14 @@ import org.citron.citron_emu.NativeLibrary
|
||||||
import org.citron.citron_emu.R
|
import org.citron.citron_emu.R
|
||||||
import org.citron.citron_emu.CitronApplication
|
import org.citron.citron_emu.CitronApplication
|
||||||
import org.citron.citron_emu.databinding.ActivityEmulationBinding
|
import org.citron.citron_emu.databinding.ActivityEmulationBinding
|
||||||
|
import org.citron.citron_emu.dialogs.NetPlayDialog
|
||||||
import org.citron.citron_emu.features.input.NativeInput
|
import org.citron.citron_emu.features.input.NativeInput
|
||||||
import org.citron.citron_emu.features.settings.model.BooleanSetting
|
import org.citron.citron_emu.features.settings.model.BooleanSetting
|
||||||
import org.citron.citron_emu.features.settings.model.IntSetting
|
import org.citron.citron_emu.features.settings.model.IntSetting
|
||||||
import org.citron.citron_emu.features.settings.model.Settings
|
import org.citron.citron_emu.features.settings.model.Settings
|
||||||
import org.citron.citron_emu.model.EmulationViewModel
|
import org.citron.citron_emu.model.EmulationViewModel
|
||||||
import org.citron.citron_emu.model.Game
|
import org.citron.citron_emu.model.Game
|
||||||
|
import org.citron.citron_emu.network.NetPlayManager
|
||||||
import org.citron.citron_emu.utils.InputHandler
|
import org.citron.citron_emu.utils.InputHandler
|
||||||
import org.citron.citron_emu.utils.Log
|
import org.citron.citron_emu.utils.Log
|
||||||
import org.citron.citron_emu.utils.MemoryUtil
|
import org.citron.citron_emu.utils.MemoryUtil
|
||||||
|
@ -52,6 +55,7 @@ import org.citron.citron_emu.utils.NativeConfig
|
||||||
import org.citron.citron_emu.utils.NfcReader
|
import org.citron.citron_emu.utils.NfcReader
|
||||||
import org.citron.citron_emu.utils.ParamPackage
|
import org.citron.citron_emu.utils.ParamPackage
|
||||||
import org.citron.citron_emu.utils.ThemeHelper
|
import org.citron.citron_emu.utils.ThemeHelper
|
||||||
|
import org.citron.citron_emu.utils.LicenseVerifier
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@ -79,6 +83,22 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
// Check if firmware is available
|
||||||
|
if (!NativeLibrary.isFirmwareAvailable()) {
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.firmware_missing_title)
|
||||||
|
.setMessage(R.string.firmware_missing_message)
|
||||||
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
.setCancelable(false)
|
||||||
|
.show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add license verification at the start
|
||||||
|
LicenseVerifier.verifyLicense(this)
|
||||||
|
|
||||||
InputHandler.updateControllerData()
|
InputHandler.updateControllerData()
|
||||||
val players = NativeConfig.getInputSettings(true)
|
val players = NativeConfig.getInputSettings(true)
|
||||||
var hasConfiguredControllers = false
|
var hasConfiguredControllers = false
|
||||||
|
@ -405,6 +425,16 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||||
setPictureInPictureParams(pictureInPictureParamsBuilder.build())
|
setPictureInPictureParams(pictureInPictureParamsBuilder.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun displayMultiplayerDialog() {
|
||||||
|
val dialog = NetPlayDialog(this)
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addNetPlayMessages(type: Int, msg: String) {
|
||||||
|
NetPlayManager.addNetPlayMessage(type, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private var pictureInPictureReceiver = object : BroadcastReceiver() {
|
private var pictureInPictureReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent) {
|
override fun onReceive(context: Context?, intent: Intent) {
|
||||||
if (intent.action == actionPlay) {
|
if (intent.action == actionPlay) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
|
||||||
override fun bind(model: SetupPage) {
|
override fun bind(model: SetupPage) {
|
||||||
if (model.stepCompleted.invoke() == StepState.COMPLETE) {
|
if (model.stepCompleted.invoke() == StepState.COMPLETE) {
|
||||||
binding.buttonAction.setVisible(visible = false, gone = false)
|
binding.buttonAction.setVisible(visible = false, gone = false)
|
||||||
binding.textConfirmation.setVisible(true)
|
binding.textConfirmation?.setVisible(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.icon.setImageDrawable(
|
binding.icon.setImageDrawable(
|
||||||
|
@ -68,7 +68,7 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
|
||||||
|
|
||||||
override fun onStepCompleted() {
|
override fun onStepCompleted() {
|
||||||
ViewUtils.hideView(binding.buttonAction, 200)
|
ViewUtils.hideView(binding.buttonAction, 200)
|
||||||
ViewUtils.showView(binding.textConfirmation, 200)
|
binding.textConfirmation?.let { ViewUtils.showView(it, 200) }
|
||||||
ViewModelProvider(activity)[HomeViewModel::class.java].setShouldPageForward(true)
|
ViewModelProvider(activity)[HomeViewModel::class.java].setShouldPageForward(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
package org.citron.citron_emu.dialogs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import org.citron.citron_emu.R
|
||||||
|
import org.citron.citron_emu.databinding.DialogChatBinding
|
||||||
|
import org.citron.citron_emu.databinding.ItemChatMessageBinding
|
||||||
|
import org.citron.citron_emu.network.NetPlayManager
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class ChatMessage(
|
||||||
|
val nickname: String, // This is the common name youll see on private servers
|
||||||
|
val username: String, // Username is the community/forum username
|
||||||
|
val message: String,
|
||||||
|
val timestamp: String = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date())
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChatDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
private lateinit var binding: DialogChatBinding
|
||||||
|
private lateinit var chatAdapter: ChatAdapter
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
binding = DialogChatBinding.inflate(LayoutInflater.from(context))
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
NetPlayManager.setChatOpen(true)
|
||||||
|
setupRecyclerView()
|
||||||
|
|
||||||
|
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
behavior.skipCollapsed = context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
|
||||||
|
|
||||||
|
handler.post {
|
||||||
|
chatAdapter.notifyDataSetChanged()
|
||||||
|
binding.chatRecyclerView.post {
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPlayManager.setOnMessageReceivedListener { type, message ->
|
||||||
|
handler.post {
|
||||||
|
chatAdapter.notifyDataSetChanged()
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.sendButton.setOnClickListener {
|
||||||
|
val message = binding.chatInput.text.toString()
|
||||||
|
if (message.isNotBlank()) {
|
||||||
|
sendMessage(message)
|
||||||
|
binding.chatInput.text?.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dismiss() {
|
||||||
|
NetPlayManager.setChatOpen(false)
|
||||||
|
super.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sendMessage(message: String) {
|
||||||
|
val username = NetPlayManager.getUsername(context)
|
||||||
|
NetPlayManager.netPlaySendMessage(message)
|
||||||
|
|
||||||
|
val chatMessage = ChatMessage(
|
||||||
|
nickname = username,
|
||||||
|
username = "",
|
||||||
|
message = message,
|
||||||
|
timestamp = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date())
|
||||||
|
)
|
||||||
|
|
||||||
|
NetPlayManager.addChatMessage(chatMessage)
|
||||||
|
chatAdapter.notifyDataSetChanged()
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupRecyclerView() {
|
||||||
|
chatAdapter = ChatAdapter(NetPlayManager.getChatMessages())
|
||||||
|
binding.chatRecyclerView.layoutManager = LinearLayoutManager(context).apply {
|
||||||
|
stackFromEnd = true
|
||||||
|
}
|
||||||
|
binding.chatRecyclerView.adapter = chatAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun scrollToBottom() {
|
||||||
|
binding.chatRecyclerView.scrollToPosition(chatAdapter.itemCount - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChatAdapter(private val messages: List<ChatMessage>) :
|
||||||
|
RecyclerView.Adapter<ChatAdapter.ChatViewHolder>() {
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder {
|
||||||
|
val binding = ItemChatMessageBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
return ChatViewHolder(binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = messages.size
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ChatViewHolder, position: Int) {
|
||||||
|
holder.bind(messages[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ChatViewHolder(private val binding: ItemChatMessageBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(message: ChatMessage) {
|
||||||
|
binding.usernameText.text = message.nickname
|
||||||
|
binding.messageText.text = message.message
|
||||||
|
binding.userIcon.setImageResource(when (message.nickname) {
|
||||||
|
"System" -> R.drawable.ic_system
|
||||||
|
else -> R.drawable.ic_user
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,397 @@
|
||||||
|
// Copyright 2024 Mandarine Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
package org.citron.citron_emu.dialogs
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.citron.citron_emu.R
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.PopupMenu
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.citron.citron_emu.CitronApplication
|
||||||
|
import org.citron.citron_emu.databinding.DialogMultiplayerConnectBinding
|
||||||
|
import org.citron.citron_emu.databinding.DialogMultiplayerLobbyBinding
|
||||||
|
import org.citron.citron_emu.databinding.DialogMultiplayerRoomBinding
|
||||||
|
import org.citron.citron_emu.databinding.ItemBanListBinding
|
||||||
|
import org.citron.citron_emu.databinding.ItemButtonNetplayBinding
|
||||||
|
import org.citron.citron_emu.databinding.ItemTextNetplayBinding
|
||||||
|
import org.citron.citron_emu.utils.CompatUtils
|
||||||
|
import org.citron.citron_emu.network.NetPlayManager
|
||||||
|
|
||||||
|
class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
private lateinit var adapter: NetPlayAdapter
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
behavior.skipCollapsed = context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
|
||||||
|
when {
|
||||||
|
NetPlayManager.netPlayIsJoined() -> DialogMultiplayerLobbyBinding.inflate(layoutInflater)
|
||||||
|
.apply {
|
||||||
|
setContentView(root)
|
||||||
|
adapter = NetPlayAdapter()
|
||||||
|
listMultiplayer.layoutManager = LinearLayoutManager(context)
|
||||||
|
listMultiplayer.adapter = adapter
|
||||||
|
adapter.loadMultiplayerMenu()
|
||||||
|
btnLeave.setOnClickListener {
|
||||||
|
NetPlayManager.netPlayLeaveRoom()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
btnChat.setOnClickListener {
|
||||||
|
ChatDialog(context).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshAdapterItems()
|
||||||
|
|
||||||
|
btnModeration.visibility = if (NetPlayManager.netPlayIsModerator()) View.VISIBLE else View.GONE
|
||||||
|
btnModeration.setOnClickListener {
|
||||||
|
showModerationDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
DialogMultiplayerConnectBinding.inflate(layoutInflater).apply {
|
||||||
|
setContentView(root)
|
||||||
|
btnCreate.setOnClickListener {
|
||||||
|
showNetPlayInputDialog(true)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
btnJoin.setOnClickListener {
|
||||||
|
showNetPlayInputDialog(false)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class NetPlayItems(
|
||||||
|
val option: Int,
|
||||||
|
val name: String,
|
||||||
|
val type: Int,
|
||||||
|
val id: Int = 0
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
const val MULTIPLAYER_ROOM_TEXT = 1
|
||||||
|
const val MULTIPLAYER_ROOM_MEMBER = 2
|
||||||
|
const val MULTIPLAYER_SEPARATOR = 3
|
||||||
|
const val MULTIPLAYER_ROOM_COUNT = 4
|
||||||
|
const val TYPE_BUTTON = 0
|
||||||
|
const val TYPE_TEXT = 1
|
||||||
|
const val TYPE_SEPARATOR = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class NetPlayAdapter : RecyclerView.Adapter<NetPlayAdapter.NetPlayViewHolder>() {
|
||||||
|
val netPlayItems = mutableListOf<NetPlayItems>()
|
||||||
|
|
||||||
|
abstract inner class NetPlayViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||||
|
init {
|
||||||
|
itemView.setOnClickListener(this)
|
||||||
|
}
|
||||||
|
abstract fun bind(item: NetPlayItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class TextViewHolder(private val binding: ItemTextNetplayBinding) : NetPlayViewHolder(binding.root) {
|
||||||
|
private lateinit var netPlayItem: NetPlayItems
|
||||||
|
|
||||||
|
override fun onClick(clicked: View) {}
|
||||||
|
|
||||||
|
override fun bind(item: NetPlayItems) {
|
||||||
|
netPlayItem = item
|
||||||
|
binding.itemTextNetplayName.text = item.name
|
||||||
|
binding.itemIcon.apply {
|
||||||
|
val iconRes = when (item.option) {
|
||||||
|
NetPlayItems.MULTIPLAYER_ROOM_TEXT -> R.drawable.ic_system
|
||||||
|
NetPlayItems.MULTIPLAYER_ROOM_COUNT -> R.drawable.ic_joined
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
visibility = if (iconRes != 0) {
|
||||||
|
setImageResource(iconRes)
|
||||||
|
View.VISIBLE
|
||||||
|
} else View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ButtonViewHolder(private val binding: ItemButtonNetplayBinding) : NetPlayViewHolder(binding.root) {
|
||||||
|
private lateinit var netPlayItems: NetPlayItems
|
||||||
|
private val isModerator = NetPlayManager.netPlayIsModerator()
|
||||||
|
|
||||||
|
init {
|
||||||
|
binding.itemButtonMore.apply {
|
||||||
|
visibility = View.VISIBLE
|
||||||
|
setOnClickListener { showPopupMenu(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(clicked: View) {}
|
||||||
|
|
||||||
|
|
||||||
|
private fun showPopupMenu(view: View) {
|
||||||
|
PopupMenu(view.context, view).apply {
|
||||||
|
menuInflater.inflate(R.menu.menu_netplay_member, menu)
|
||||||
|
menu.findItem(R.id.action_kick).isEnabled = isModerator &&
|
||||||
|
netPlayItems.name != NetPlayManager.getUsername(context)
|
||||||
|
menu.findItem(R.id.action_ban).isEnabled = isModerator &&
|
||||||
|
netPlayItems.name != NetPlayManager.getUsername(context)
|
||||||
|
setOnMenuItemClickListener { item ->
|
||||||
|
if (item.itemId == R.id.action_kick) {
|
||||||
|
NetPlayManager.netPlayKickUser(netPlayItems.name)
|
||||||
|
true
|
||||||
|
} else if (item.itemId == R.id.action_ban) {
|
||||||
|
NetPlayManager.netPlayBanUser(netPlayItems.name)
|
||||||
|
true
|
||||||
|
} else false
|
||||||
|
}
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bind(item: NetPlayItems) {
|
||||||
|
netPlayItems = item
|
||||||
|
binding.itemButtonNetplayName.text = netPlayItems.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadMultiplayerMenu() {
|
||||||
|
val infos = NetPlayManager.netPlayRoomInfo()
|
||||||
|
if (infos.isNotEmpty()) {
|
||||||
|
val roomInfo = infos[0].split("|")
|
||||||
|
netPlayItems.add(NetPlayItems(NetPlayItems.MULTIPLAYER_ROOM_TEXT, roomInfo[0], NetPlayItems.TYPE_TEXT))
|
||||||
|
netPlayItems.add(NetPlayItems(NetPlayItems.MULTIPLAYER_ROOM_COUNT, "${infos.size - 1}/${roomInfo[1]}", NetPlayItems.TYPE_TEXT))
|
||||||
|
netPlayItems.add(NetPlayItems(NetPlayItems.MULTIPLAYER_SEPARATOR, "", NetPlayItems.TYPE_SEPARATOR))
|
||||||
|
for (i in 1 until infos.size) {
|
||||||
|
netPlayItems.add(NetPlayItems(NetPlayItems.MULTIPLAYER_ROOM_MEMBER, infos[i], NetPlayItems.TYPE_BUTTON))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int) = netPlayItems[position].type
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NetPlayViewHolder {
|
||||||
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
|
return when (viewType) {
|
||||||
|
NetPlayItems.TYPE_TEXT -> TextViewHolder(ItemTextNetplayBinding.inflate(inflater, parent, false))
|
||||||
|
NetPlayItems.TYPE_BUTTON -> ButtonViewHolder(ItemButtonNetplayBinding.inflate(inflater, parent, false))
|
||||||
|
NetPlayItems.TYPE_SEPARATOR -> object : NetPlayViewHolder(inflater.inflate(R.layout.item_separator_netplay, parent, false)) {
|
||||||
|
override fun bind(item: NetPlayItems) {}
|
||||||
|
override fun onClick(clicked: View) {}
|
||||||
|
}
|
||||||
|
else -> throw IllegalStateException("Unsupported view type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: NetPlayViewHolder, position: Int) {
|
||||||
|
holder.bind(netPlayItems[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = netPlayItems.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refreshAdapterItems() {
|
||||||
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
NetPlayManager.setOnAdapterRefreshListener() { type, msg ->
|
||||||
|
handler.post {
|
||||||
|
adapter.netPlayItems.clear()
|
||||||
|
adapter.loadMultiplayerMenu()
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showNetPlayInputDialog(isCreateRoom: Boolean) {
|
||||||
|
val activity = CompatUtils.findActivity(context)
|
||||||
|
val dialog = BottomSheetDialog(activity)
|
||||||
|
|
||||||
|
dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
dialog.behavior.skipCollapsed = context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
|
||||||
|
|
||||||
|
val binding = DialogMultiplayerRoomBinding.inflate(LayoutInflater.from(activity))
|
||||||
|
dialog.setContentView(binding.root)
|
||||||
|
|
||||||
|
binding.textTitle.text = activity.getString(
|
||||||
|
if (isCreateRoom) R.string.multiplayer_create_room
|
||||||
|
else R.string.multiplayer_join_room
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.ipAddress.setText(
|
||||||
|
if (isCreateRoom) NetPlayManager.getIpAddressByWifi(activity)
|
||||||
|
else NetPlayManager.getRoomAddress(activity)
|
||||||
|
)
|
||||||
|
binding.ipPort.setText(NetPlayManager.getRoomPort(activity))
|
||||||
|
binding.username.setText(NetPlayManager.getUsername(activity))
|
||||||
|
|
||||||
|
binding.roomName.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
||||||
|
binding.maxPlayersContainer.visibility = if (isCreateRoom) View.VISIBLE else View.GONE
|
||||||
|
binding.maxPlayersLabel.text = context.getString(R.string.multiplayer_max_players_value, binding.maxPlayers.value.toInt())
|
||||||
|
|
||||||
|
binding.maxPlayers.addOnChangeListener { _, value, _ ->
|
||||||
|
binding.maxPlayersLabel.text = context.getString(R.string.multiplayer_max_players_value, value.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.btnConfirm.setOnClickListener {
|
||||||
|
binding.btnConfirm.isEnabled = false
|
||||||
|
binding.btnConfirm.text = activity.getString(R.string.disabled_button_text)
|
||||||
|
|
||||||
|
val ipAddress = binding.ipAddress.text.toString()
|
||||||
|
val username = binding.username.text.toString()
|
||||||
|
val portStr = binding.ipPort.text.toString()
|
||||||
|
val password = binding.password.text.toString()
|
||||||
|
val port = portStr.toIntOrNull() ?: run {
|
||||||
|
Toast.makeText(activity, R.string.multiplayer_port_invalid, Toast.LENGTH_LONG).show()
|
||||||
|
binding.btnConfirm.isEnabled = true
|
||||||
|
binding.btnConfirm.text = activity.getString(R.string.original_button_text)
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
val roomName = binding.roomName.text.toString()
|
||||||
|
val maxPlayers = binding.maxPlayers.value.toInt()
|
||||||
|
|
||||||
|
if (isCreateRoom && (roomName.length !in 3..20)) {
|
||||||
|
Toast.makeText(activity, R.string.multiplayer_room_name_invalid, Toast.LENGTH_LONG).show()
|
||||||
|
binding.btnConfirm.isEnabled = true
|
||||||
|
binding.btnConfirm.text = activity.getString(R.string.original_button_text)
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipAddress.length < 7 || username.length < 5) {
|
||||||
|
Toast.makeText(activity, R.string.multiplayer_input_invalid, Toast.LENGTH_LONG).show()
|
||||||
|
binding.btnConfirm.isEnabled = true
|
||||||
|
binding.btnConfirm.text = activity.getString(R.string.original_button_text)
|
||||||
|
} else {
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
val result = if (isCreateRoom) {
|
||||||
|
NetPlayManager.netPlayCreateRoom(ipAddress, port, username, password, roomName, maxPlayers)
|
||||||
|
} else {
|
||||||
|
NetPlayManager.netPlayJoinRoom(ipAddress, port, username, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
NetPlayManager.setUsername(activity, username)
|
||||||
|
NetPlayManager.setRoomPort(activity, portStr)
|
||||||
|
if (!isCreateRoom) NetPlayManager.setRoomAddress(activity, ipAddress)
|
||||||
|
Toast.makeText(
|
||||||
|
CitronApplication.appContext,
|
||||||
|
if (isCreateRoom) R.string.multiplayer_create_room_success
|
||||||
|
else R.string.multiplayer_join_room_success,
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
dialog.dismiss()
|
||||||
|
} else {
|
||||||
|
Toast.makeText(activity, R.string.multiplayer_could_not_connect, Toast.LENGTH_LONG).show()
|
||||||
|
binding.btnConfirm.isEnabled = true
|
||||||
|
binding.btnConfirm.text = activity.getString(R.string.original_button_text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showModerationDialog() {
|
||||||
|
val activity = CompatUtils.findActivity(context)
|
||||||
|
val dialog = MaterialAlertDialogBuilder(activity)
|
||||||
|
dialog.setTitle(R.string.multiplayer_moderation_title)
|
||||||
|
|
||||||
|
val banList = NetPlayManager.getBanList()
|
||||||
|
if (banList.isEmpty()) {
|
||||||
|
dialog.setMessage(R.string.multiplayer_no_bans)
|
||||||
|
dialog.setPositiveButton(R.string.ok, null)
|
||||||
|
dialog.show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val view = LayoutInflater.from(context).inflate(R.layout.dialog_ban_list, null)
|
||||||
|
val recyclerView = view.findViewById<RecyclerView>(R.id.ban_list_recycler)
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
|
||||||
|
lateinit var adapter: BanListAdapter
|
||||||
|
|
||||||
|
val onUnban: (String) -> Unit = { bannedItem ->
|
||||||
|
MaterialAlertDialogBuilder(activity)
|
||||||
|
.setTitle(R.string.multiplayer_unban_title)
|
||||||
|
.setMessage(activity.getString(R.string.multiplayer_unban_message, bannedItem))
|
||||||
|
.setPositiveButton(R.string.multiplayer_unban) { _, _ ->
|
||||||
|
NetPlayManager.netPlayUnbanUser(bannedItem)
|
||||||
|
adapter.removeBan(bannedItem)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter = BanListAdapter(banList, onUnban)
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
|
||||||
|
dialog.setView(view)
|
||||||
|
dialog.setPositiveButton(R.string.ok, null)
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BanListAdapter(
|
||||||
|
banList: List<String>,
|
||||||
|
private val onUnban: (String) -> Unit
|
||||||
|
) : RecyclerView.Adapter<BanListAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
private val usernameBans = banList.filter { !it.contains(".") }.toMutableList()
|
||||||
|
private val ipBans = banList.filter { it.contains(".") }.toMutableList()
|
||||||
|
|
||||||
|
class ViewHolder(val binding: ItemBanListBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val binding = ItemBanListBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return ViewHolder(binding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val isUsername = position < usernameBans.size
|
||||||
|
val item = if (isUsername) usernameBans[position] else ipBans[position - usernameBans.size]
|
||||||
|
|
||||||
|
holder.binding.apply {
|
||||||
|
banText.text = item
|
||||||
|
icon.setImageResource(if (isUsername) R.drawable.ic_user else R.drawable.ic_ip)
|
||||||
|
btnUnban.setOnClickListener { onUnban(item) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = usernameBans.size + ipBans.size
|
||||||
|
|
||||||
|
fun removeBan(bannedItem: String) {
|
||||||
|
val position = if (bannedItem.contains(".")) {
|
||||||
|
ipBans.indexOf(bannedItem).let { if (it >= 0) it + usernameBans.size else it }
|
||||||
|
} else {
|
||||||
|
usernameBans.indexOf(bannedItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position >= 0) {
|
||||||
|
if (bannedItem.contains(".")) {
|
||||||
|
ipBans.remove(bannedItem)
|
||||||
|
} else {
|
||||||
|
usernameBans.remove(bannedItem)
|
||||||
|
}
|
||||||
|
notifyItemRemoved(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: 2025 Citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
package org.citron.citron_emu.features.settings.model
|
package org.citron.citron_emu.features.settings.model
|
||||||
|
@ -27,6 +28,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||||
SHOW_INPUT_OVERLAY("show_input_overlay"),
|
SHOW_INPUT_OVERLAY("show_input_overlay"),
|
||||||
TOUCHSCREEN("touchscreen"),
|
TOUCHSCREEN("touchscreen"),
|
||||||
SHOW_THERMAL_OVERLAY("show_thermal_overlay"),
|
SHOW_THERMAL_OVERLAY("show_thermal_overlay"),
|
||||||
|
SHOW_RAM_OVERLAY("show_ram_overlay"),
|
||||||
USE_AUTO_STUB("use_auto_stub");
|
USE_AUTO_STUB("use_auto_stub");
|
||||||
|
|
||||||
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: 2025 Citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
package org.citron.citron_emu.fragments
|
package org.citron.citron_emu.fragments
|
||||||
|
@ -11,9 +12,11 @@ import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.BatteryManager
|
import android.os.BatteryManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Debug
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
|
@ -68,6 +71,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
private var emulationActivity: EmulationActivity? = null
|
private var emulationActivity: EmulationActivity? = null
|
||||||
private var perfStatsUpdater: (() -> Unit)? = null
|
private var perfStatsUpdater: (() -> Unit)? = null
|
||||||
private var thermalStatsUpdater: (() -> Unit)? = null
|
private var thermalStatsUpdater: (() -> Unit)? = null
|
||||||
|
private var ramStatsUpdater: (() -> Unit)? = null
|
||||||
|
|
||||||
private var _binding: FragmentEmulationBinding? = null
|
private var _binding: FragmentEmulationBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
@ -83,6 +87,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
|
||||||
private lateinit var powerManager: PowerManager
|
private lateinit var powerManager: PowerManager
|
||||||
|
|
||||||
|
private val ramStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
if (context is EmulationActivity) {
|
if (context is EmulationActivity) {
|
||||||
|
@ -265,6 +271,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
R.id.menu_multiplayer -> {
|
||||||
|
emulationActivity?.displayMultiplayerDialog()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
R.id.menu_controls -> {
|
R.id.menu_controls -> {
|
||||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||||
null,
|
null,
|
||||||
|
@ -376,6 +389,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
// Setup overlays
|
// Setup overlays
|
||||||
updateShowFpsOverlay()
|
updateShowFpsOverlay()
|
||||||
updateThermalOverlay()
|
updateThermalOverlay()
|
||||||
|
updateRamOverlay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
|
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
|
||||||
|
@ -470,6 +484,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
|
if (ramStatsUpdater != null) {
|
||||||
|
ramStatsUpdateHandler.removeCallbacks(ramStatsUpdater!!)
|
||||||
|
}
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,8 +569,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
emulationViewModel.emulationStarted.value &&
|
emulationViewModel.emulationStarted.value &&
|
||||||
!emulationViewModel.isEmulationStopping.value
|
!emulationViewModel.isEmulationStopping.value
|
||||||
) {
|
) {
|
||||||
// Get thermal status
|
// Get thermal status for color
|
||||||
val thermalStatus = when (powerManager.currentThermalStatus) {
|
val thermalStatus = when (powerManager.currentThermalStatus) {
|
||||||
|
PowerManager.THERMAL_STATUS_NONE -> 0f
|
||||||
PowerManager.THERMAL_STATUS_LIGHT -> 0.25f
|
PowerManager.THERMAL_STATUS_LIGHT -> 0.25f
|
||||||
PowerManager.THERMAL_STATUS_MODERATE -> 0.5f
|
PowerManager.THERMAL_STATUS_MODERATE -> 0.5f
|
||||||
PowerManager.THERMAL_STATUS_SEVERE -> 0.75f
|
PowerManager.THERMAL_STATUS_SEVERE -> 0.75f
|
||||||
|
@ -563,34 +581,57 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
else -> 0f
|
else -> 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to Fahrenheit for additional info
|
// Convert to Fahrenheit
|
||||||
val fahrenheit = (temperature * 9f / 5f) + 32f
|
val fahrenheit = (temperature * 9f / 5f) + 32f
|
||||||
|
|
||||||
// Create progress bar using block elements
|
// Color based on thermal status (green to red)
|
||||||
val progressBarLength = 12
|
val red = (thermalStatus * 255).toInt()
|
||||||
val filledBars = (thermalStatus * progressBarLength).toInt()
|
val green = ((1f - thermalStatus) * 255).toInt()
|
||||||
val progressBar = buildString {
|
|
||||||
append("│") // Left border
|
|
||||||
repeat(filledBars) { append("█") }
|
|
||||||
repeat(progressBarLength - filledBars) { append("░") }
|
|
||||||
append("│") // Right border
|
|
||||||
append(" ")
|
|
||||||
append(String.format("%3d%%", (thermalStatus * 100).toInt()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Color interpolation based on temperature (green at 30°C, red at 45°C)
|
|
||||||
val normalizedTemp = ((temperature - 30f) / 15f).coerceIn(0f, 1f)
|
|
||||||
val red = (normalizedTemp * 255).toInt()
|
|
||||||
val green = ((1f - normalizedTemp) * 255).toInt()
|
|
||||||
val color = android.graphics.Color.rgb(red, green, 0)
|
val color = android.graphics.Color.rgb(red, green, 0)
|
||||||
|
|
||||||
binding.showThermalsText.setTextColor(color)
|
binding.showThermalsText.setTextColor(color)
|
||||||
binding.showThermalsText.text = String.format(
|
binding.showThermalsText.text = String.format("%.1f°C • %.1f°F", temperature, fahrenheit)
|
||||||
"%s\n%.1f°C • %.1f°F",
|
}
|
||||||
progressBar,
|
}
|
||||||
temperature,
|
|
||||||
fahrenheit
|
private fun updateRamOverlay() {
|
||||||
)
|
val showOverlay = BooleanSetting.SHOW_RAM_OVERLAY.getBoolean()
|
||||||
|
binding.showRamText.setVisible(showOverlay)
|
||||||
|
if (showOverlay) {
|
||||||
|
ramStatsUpdater = {
|
||||||
|
if (emulationViewModel.emulationStarted.value &&
|
||||||
|
!emulationViewModel.isEmulationStopping.value
|
||||||
|
) {
|
||||||
|
val runtime = Runtime.getRuntime()
|
||||||
|
val nativeHeapSize = Debug.getNativeHeapSize()
|
||||||
|
val nativeHeapFreeSize = Debug.getNativeHeapFreeSize()
|
||||||
|
val nativeHeapUsed = nativeHeapSize - nativeHeapFreeSize
|
||||||
|
|
||||||
|
val usedMemInMB = nativeHeapUsed / 1048576L
|
||||||
|
val maxMemInMB = nativeHeapSize / 1048576L
|
||||||
|
val percentUsed = (nativeHeapUsed.toFloat() / nativeHeapSize.toFloat() * 100f)
|
||||||
|
|
||||||
|
// Color interpolation from green to red based on usage percentage
|
||||||
|
val normalizedUsage = (percentUsed / 100f).coerceIn(0f, 1f)
|
||||||
|
val red = (normalizedUsage * 255).toInt()
|
||||||
|
val green = ((1f - normalizedUsage) * 255).toInt()
|
||||||
|
val color = Color.rgb(red, green, 0)
|
||||||
|
|
||||||
|
binding.showRamText.setTextColor(color)
|
||||||
|
binding.showRamText.text = String.format(
|
||||||
|
"\nRAM: %d/%d MB (%.1f%%)",
|
||||||
|
usedMemInMB,
|
||||||
|
maxMemInMB,
|
||||||
|
percentUsed
|
||||||
|
)
|
||||||
|
ramStatsUpdateHandler.postDelayed(ramStatsUpdater!!, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ramStatsUpdateHandler.post(ramStatsUpdater!!)
|
||||||
|
} else {
|
||||||
|
if (ramStatsUpdater != null) {
|
||||||
|
ramStatsUpdateHandler.removeCallbacks(ramStatsUpdater!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,6 +764,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
|
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
|
||||||
findItem(R.id.thermal_indicator).isChecked =
|
findItem(R.id.thermal_indicator).isChecked =
|
||||||
BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
|
BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
|
||||||
|
findItem(R.id.ram_meter).apply {
|
||||||
|
isChecked = BooleanSetting.SHOW_RAM_OVERLAY.getBoolean()
|
||||||
|
isEnabled = false // This grays out the option
|
||||||
|
}
|
||||||
findItem(R.id.menu_rel_stick_center).isChecked =
|
findItem(R.id.menu_rel_stick_center).isChecked =
|
||||||
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
|
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
|
||||||
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
|
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
|
||||||
|
@ -749,6 +794,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.ram_meter -> {
|
||||||
|
// Do nothing since it's disabled
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
R.id.menu_edit_overlay -> {
|
R.id.menu_edit_overlay -> {
|
||||||
binding.drawerLayout.close()
|
binding.drawerLayout.close()
|
||||||
binding.surfaceInputOverlay.requestFocus()
|
binding.surfaceInputOverlay.requestFocus()
|
||||||
|
|
|
@ -119,6 +119,16 @@ class HomeSettingsFragment : Fragment() {
|
||||||
driverViewModel.selectedDriverTitle
|
driverViewModel.selectedDriverTitle
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
add(
|
||||||
|
HomeSetting(
|
||||||
|
R.string.multiplayer,
|
||||||
|
R.string.multiplayer_description,
|
||||||
|
R.drawable.ic_multiplayer,
|
||||||
|
{
|
||||||
|
val action = mainActivity.displayMultiplayerDialog()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
add(
|
add(
|
||||||
HomeSetting(
|
HomeSetting(
|
||||||
R.string.applets,
|
R.string.applets,
|
||||||
|
|
|
@ -180,6 +180,62 @@ class SetupFragment : Fragment() {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Add title.keys installation page
|
||||||
|
add(
|
||||||
|
SetupPage(
|
||||||
|
R.drawable.ic_key,
|
||||||
|
R.string.install_title_keys,
|
||||||
|
R.string.install_title_keys_description,
|
||||||
|
R.drawable.ic_add,
|
||||||
|
true,
|
||||||
|
R.string.select_keys,
|
||||||
|
{
|
||||||
|
titleKeyCallback = it
|
||||||
|
getTitleKey.launch(arrayOf("*/*"))
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
R.string.install_title_keys_warning,
|
||||||
|
R.string.install_title_keys_warning_description,
|
||||||
|
R.string.install_title_keys_warning_help,
|
||||||
|
{
|
||||||
|
val file = File(DirectoryInitialization.userDirectory + "/keys/title.keys")
|
||||||
|
if (file.exists()) {
|
||||||
|
StepState.COMPLETE
|
||||||
|
} else {
|
||||||
|
StepState.INCOMPLETE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add firmware installation page (mandatory)
|
||||||
|
add(
|
||||||
|
SetupPage(
|
||||||
|
R.drawable.ic_key,
|
||||||
|
R.string.install_firmware,
|
||||||
|
R.string.install_firmware_description,
|
||||||
|
R.drawable.ic_add,
|
||||||
|
true,
|
||||||
|
R.string.select_firmware,
|
||||||
|
{
|
||||||
|
firmwareCallback = it
|
||||||
|
getFirmware.launch(arrayOf("application/zip"))
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
R.string.install_firmware_warning,
|
||||||
|
R.string.install_firmware_warning_description,
|
||||||
|
R.string.install_firmware_warning_help,
|
||||||
|
{
|
||||||
|
if (NativeLibrary.isFirmwareAvailable()) {
|
||||||
|
StepState.COMPLETE
|
||||||
|
} else {
|
||||||
|
StepState.INCOMPLETE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
add(
|
add(
|
||||||
SetupPage(
|
SetupPage(
|
||||||
R.drawable.ic_controller,
|
R.drawable.ic_controller,
|
||||||
|
@ -268,6 +324,18 @@ class SetupFragment : Fragment() {
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special handling for firmware page - don't allow skipping
|
||||||
|
if (currentPage.titleId == R.string.install_firmware && !NativeLibrary.isFirmwareAvailable()) {
|
||||||
|
SetupWarningDialogFragment.newInstance(
|
||||||
|
currentPage.warningTitleId,
|
||||||
|
currentPage.warningDescriptionId,
|
||||||
|
currentPage.warningHelpLinkId,
|
||||||
|
index,
|
||||||
|
allowSkip = false
|
||||||
|
).show(childFragmentManager, SetupWarningDialogFragment.TAG)
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasBeenWarned[index]) {
|
if (!hasBeenWarned[index]) {
|
||||||
SetupWarningDialogFragment.newInstance(
|
SetupWarningDialogFragment.newInstance(
|
||||||
currentPage.warningTitleId,
|
currentPage.warningTitleId,
|
||||||
|
@ -346,6 +414,30 @@ class SetupFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lateinit var titleKeyCallback: SetupCallback
|
||||||
|
|
||||||
|
val getTitleKey =
|
||||||
|
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
||||||
|
if (result != null) {
|
||||||
|
mainActivity.processTitleKey(result)
|
||||||
|
titleKeyCallback.onStepCompleted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var firmwareCallback: SetupCallback
|
||||||
|
|
||||||
|
val getFirmware =
|
||||||
|
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
||||||
|
if (result != null) {
|
||||||
|
mainActivity.getFirmware.launch(arrayOf("application/zip"))
|
||||||
|
binding.root.postDelayed({
|
||||||
|
if (NativeLibrary.isFirmwareAvailable()) {
|
||||||
|
firmwareCallback.onStepCompleted()
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private lateinit var gamesDirCallback: SetupCallback
|
private lateinit var gamesDirCallback: SetupCallback
|
||||||
|
|
||||||
val getGamesDirectory =
|
val getGamesDirectory =
|
||||||
|
|
|
@ -17,6 +17,7 @@ class SetupWarningDialogFragment : DialogFragment() {
|
||||||
private var descriptionId: Int = 0
|
private var descriptionId: Int = 0
|
||||||
private var helpLinkId: Int = 0
|
private var helpLinkId: Int = 0
|
||||||
private var page: Int = 0
|
private var page: Int = 0
|
||||||
|
private var allowSkip: Boolean = true
|
||||||
|
|
||||||
private lateinit var setupFragment: SetupFragment
|
private lateinit var setupFragment: SetupFragment
|
||||||
|
|
||||||
|
@ -26,17 +27,24 @@ class SetupWarningDialogFragment : DialogFragment() {
|
||||||
descriptionId = requireArguments().getInt(DESCRIPTION)
|
descriptionId = requireArguments().getInt(DESCRIPTION)
|
||||||
helpLinkId = requireArguments().getInt(HELP_LINK)
|
helpLinkId = requireArguments().getInt(HELP_LINK)
|
||||||
page = requireArguments().getInt(PAGE)
|
page = requireArguments().getInt(PAGE)
|
||||||
|
allowSkip = requireArguments().getBoolean(ALLOW_SKIP, true)
|
||||||
|
|
||||||
setupFragment = requireParentFragment() as SetupFragment
|
setupFragment = requireParentFragment() as SetupFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val builder = MaterialAlertDialogBuilder(requireContext())
|
val builder = MaterialAlertDialogBuilder(requireContext())
|
||||||
.setPositiveButton(R.string.warning_skip) { _: DialogInterface?, _: Int ->
|
|
||||||
|
if (allowSkip) {
|
||||||
|
builder.setPositiveButton(R.string.warning_skip) { _: DialogInterface?, _: Int ->
|
||||||
setupFragment.pageForward()
|
setupFragment.pageForward()
|
||||||
setupFragment.setPageWarned(page)
|
setupFragment.setPageWarned(page)
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.warning_cancel, null)
|
builder.setNegativeButton(R.string.warning_cancel, null)
|
||||||
|
} else {
|
||||||
|
// For mandatory steps, only show an OK button that dismisses the dialog
|
||||||
|
builder.setPositiveButton(R.string.ok, null)
|
||||||
|
}
|
||||||
|
|
||||||
if (titleId != 0) {
|
if (titleId != 0) {
|
||||||
builder.setTitle(titleId)
|
builder.setTitle(titleId)
|
||||||
|
@ -48,7 +56,7 @@ class SetupWarningDialogFragment : DialogFragment() {
|
||||||
}
|
}
|
||||||
if (helpLinkId != 0) {
|
if (helpLinkId != 0) {
|
||||||
builder.setNeutralButton(R.string.warning_help) { _: DialogInterface?, _: Int ->
|
builder.setNeutralButton(R.string.warning_help) { _: DialogInterface?, _: Int ->
|
||||||
val helpLink = resources.getString(R.string.install_prod_keys_warning_help)
|
val helpLink = resources.getString(helpLinkId)
|
||||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(helpLink))
|
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(helpLink))
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
@ -64,12 +72,14 @@ class SetupWarningDialogFragment : DialogFragment() {
|
||||||
private const val DESCRIPTION = "Description"
|
private const val DESCRIPTION = "Description"
|
||||||
private const val HELP_LINK = "HelpLink"
|
private const val HELP_LINK = "HelpLink"
|
||||||
private const val PAGE = "Page"
|
private const val PAGE = "Page"
|
||||||
|
private const val ALLOW_SKIP = "AllowSkip"
|
||||||
|
|
||||||
fun newInstance(
|
fun newInstance(
|
||||||
titleId: Int,
|
titleId: Int,
|
||||||
descriptionId: Int,
|
descriptionId: Int,
|
||||||
helpLinkId: Int,
|
helpLinkId: Int,
|
||||||
page: Int
|
page: Int,
|
||||||
|
allowSkip: Boolean = true
|
||||||
): SetupWarningDialogFragment {
|
): SetupWarningDialogFragment {
|
||||||
val dialog = SetupWarningDialogFragment()
|
val dialog = SetupWarningDialogFragment()
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
|
@ -78,6 +88,7 @@ class SetupWarningDialogFragment : DialogFragment() {
|
||||||
putInt(DESCRIPTION, descriptionId)
|
putInt(DESCRIPTION, descriptionId)
|
||||||
putInt(HELP_LINK, helpLinkId)
|
putInt(HELP_LINK, helpLinkId)
|
||||||
putInt(PAGE, page)
|
putInt(PAGE, page)
|
||||||
|
putBoolean(ALLOW_SKIP, allowSkip)
|
||||||
}
|
}
|
||||||
dialog.arguments = bundle
|
dialog.arguments = bundle
|
||||||
return dialog
|
return dialog
|
||||||
|
|
|
@ -0,0 +1,222 @@
|
||||||
|
// Copyright 2024 Mandarine Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
package org.citron.citron_emu.network
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.wifi.WifiManager
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.text.format.Formatter
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import org.citron.citron_emu.CitronApplication
|
||||||
|
import org.citron.citron_emu.R
|
||||||
|
import org.citron.citron_emu.dialogs.ChatMessage
|
||||||
|
|
||||||
|
object NetPlayManager {
|
||||||
|
external fun netPlayCreateRoom(ipAddress: String, port: Int, username: String, password: String, roomName: String, maxPlayers: Int): Int
|
||||||
|
external fun netPlayJoinRoom(ipAddress: String, port: Int, username: String, password: String): Int
|
||||||
|
external fun netPlayRoomInfo(): Array<String>
|
||||||
|
external fun netPlayIsJoined(): Boolean
|
||||||
|
external fun netPlayIsHostedRoom(): Boolean
|
||||||
|
external fun netPlaySendMessage(msg: String)
|
||||||
|
external fun netPlayKickUser(username: String)
|
||||||
|
external fun netPlayLeaveRoom()
|
||||||
|
external fun netPlayIsModerator(): Boolean
|
||||||
|
external fun netPlayGetBanList(): Array<String>
|
||||||
|
external fun netPlayBanUser(username: String)
|
||||||
|
external fun netPlayUnbanUser(username: String)
|
||||||
|
|
||||||
|
private var messageListener: ((Int, String) -> Unit)? = null
|
||||||
|
private var adapterRefreshListener: ((Int, String) -> Unit)? = null
|
||||||
|
|
||||||
|
fun setOnMessageReceivedListener(listener: (Int, String) -> Unit) {
|
||||||
|
messageListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnAdapterRefreshListener(listener: (Int, String) -> Unit) {
|
||||||
|
adapterRefreshListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUsername(activity: Context): String { val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
val name = "Citron${(Math.random() * 100).toInt()}"
|
||||||
|
return prefs.getString("NetPlayUsername", name) ?: name
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setUsername(activity: Activity, name: String) {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
prefs.edit().putString("NetPlayUsername", name).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRoomAddress(activity: Activity): String {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
val address = getIpAddressByWifi(activity)
|
||||||
|
return prefs.getString("NetPlayRoomAddress", address) ?: address
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setRoomAddress(activity: Activity, address: String) {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
prefs.edit().putString("NetPlayRoomAddress", address).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRoomPort(activity: Activity): String {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
return prefs.getString("NetPlayRoomPort", "24872") ?: "24872"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setRoomPort(activity: Activity, port: String) {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
prefs.edit().putString("NetPlayRoomPort", port).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val chatMessages = mutableListOf<ChatMessage>()
|
||||||
|
private var isChatOpen = false
|
||||||
|
|
||||||
|
fun addChatMessage(message: ChatMessage) {
|
||||||
|
chatMessages.add(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getChatMessages(): List<ChatMessage> = chatMessages
|
||||||
|
|
||||||
|
fun clearChat() {
|
||||||
|
chatMessages.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setChatOpen(isOpen: Boolean) {
|
||||||
|
isChatOpen = isOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addNetPlayMessage(type: Int, msg: String) {
|
||||||
|
val context = CitronApplication.appContext
|
||||||
|
val message = formatNetPlayStatus(context, type, msg)
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
NetPlayStatus.CHAT_MESSAGE -> {
|
||||||
|
val parts = msg.split(":", limit = 2)
|
||||||
|
if (parts.size == 2) {
|
||||||
|
val nickname = parts[0].trim()
|
||||||
|
val chatMessage = parts[1].trim()
|
||||||
|
addChatMessage(ChatMessage(
|
||||||
|
nickname = nickname,
|
||||||
|
username = "",
|
||||||
|
message = chatMessage
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NetPlayStatus.MEMBER_JOIN,
|
||||||
|
NetPlayStatus.MEMBER_LEAVE,
|
||||||
|
NetPlayStatus.MEMBER_KICKED,
|
||||||
|
NetPlayStatus.MEMBER_BANNED -> {
|
||||||
|
addChatMessage(ChatMessage(
|
||||||
|
nickname = "System",
|
||||||
|
username = "",
|
||||||
|
message = message
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
if (!isChatOpen) {
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
messageListener?.invoke(type, msg)
|
||||||
|
adapterRefreshListener?.invoke(type, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun formatNetPlayStatus(context: Context, type: Int, msg: String): String {
|
||||||
|
return when (type) {
|
||||||
|
NetPlayStatus.NETWORK_ERROR -> context.getString(R.string.multiplayer_network_error)
|
||||||
|
NetPlayStatus.LOST_CONNECTION -> context.getString(R.string.multiplayer_lost_connection)
|
||||||
|
NetPlayStatus.NAME_COLLISION -> context.getString(R.string.multiplayer_name_collision)
|
||||||
|
NetPlayStatus.MAC_COLLISION -> context.getString(R.string.multiplayer_mac_collision)
|
||||||
|
NetPlayStatus.CONSOLE_ID_COLLISION -> context.getString(R.string.multiplayer_console_id_collision)
|
||||||
|
NetPlayStatus.WRONG_VERSION -> context.getString(R.string.multiplayer_wrong_version)
|
||||||
|
NetPlayStatus.WRONG_PASSWORD -> context.getString(R.string.multiplayer_wrong_password)
|
||||||
|
NetPlayStatus.COULD_NOT_CONNECT -> context.getString(R.string.multiplayer_could_not_connect)
|
||||||
|
NetPlayStatus.ROOM_IS_FULL -> context.getString(R.string.multiplayer_room_is_full)
|
||||||
|
NetPlayStatus.HOST_BANNED -> context.getString(R.string.multiplayer_host_banned)
|
||||||
|
NetPlayStatus.PERMISSION_DENIED -> context.getString(R.string.multiplayer_permission_denied)
|
||||||
|
NetPlayStatus.NO_SUCH_USER -> context.getString(R.string.multiplayer_no_such_user)
|
||||||
|
NetPlayStatus.ALREADY_IN_ROOM -> context.getString(R.string.multiplayer_already_in_room)
|
||||||
|
NetPlayStatus.CREATE_ROOM_ERROR -> context.getString(R.string.multiplayer_create_room_error)
|
||||||
|
NetPlayStatus.HOST_KICKED -> context.getString(R.string.multiplayer_host_kicked)
|
||||||
|
NetPlayStatus.UNKNOWN_ERROR -> context.getString(R.string.multiplayer_unknown_error)
|
||||||
|
NetPlayStatus.ROOM_UNINITIALIZED -> context.getString(R.string.multiplayer_room_uninitialized)
|
||||||
|
NetPlayStatus.ROOM_IDLE -> context.getString(R.string.multiplayer_room_idle)
|
||||||
|
NetPlayStatus.ROOM_JOINING -> context.getString(R.string.multiplayer_room_joining)
|
||||||
|
NetPlayStatus.ROOM_JOINED -> context.getString(R.string.multiplayer_room_joined)
|
||||||
|
NetPlayStatus.ROOM_MODERATOR -> context.getString(R.string.multiplayer_room_moderator)
|
||||||
|
NetPlayStatus.MEMBER_JOIN -> context.getString(R.string.multiplayer_member_join, msg)
|
||||||
|
NetPlayStatus.MEMBER_LEAVE -> context.getString(R.string.multiplayer_member_leave, msg)
|
||||||
|
NetPlayStatus.MEMBER_KICKED -> context.getString(R.string.multiplayer_member_kicked, msg)
|
||||||
|
NetPlayStatus.MEMBER_BANNED -> context.getString(R.string.multiplayer_member_banned, msg)
|
||||||
|
NetPlayStatus.ADDRESS_UNBANNED -> context.getString(R.string.multiplayer_address_unbanned)
|
||||||
|
NetPlayStatus.CHAT_MESSAGE -> msg
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getIpAddressByWifi(activity: Activity): String {
|
||||||
|
var ipAddress = 0
|
||||||
|
val wifiManager = activity.getSystemService(WifiManager::class.java)
|
||||||
|
val wifiInfo = wifiManager.connectionInfo
|
||||||
|
if (wifiInfo != null) {
|
||||||
|
ipAddress = wifiInfo.ipAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipAddress == 0) {
|
||||||
|
val dhcpInfo = wifiManager.dhcpInfo
|
||||||
|
if (dhcpInfo != null) {
|
||||||
|
ipAddress = dhcpInfo.ipAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (ipAddress == 0) {
|
||||||
|
"192.168.0.1"
|
||||||
|
} else {
|
||||||
|
Formatter.formatIpAddress(ipAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getBanList(): List<String> {
|
||||||
|
return netPlayGetBanList().toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
object NetPlayStatus {
|
||||||
|
const val NO_ERROR = 0
|
||||||
|
const val NETWORK_ERROR = 1
|
||||||
|
const val LOST_CONNECTION = 2
|
||||||
|
const val NAME_COLLISION = 3
|
||||||
|
const val MAC_COLLISION = 4
|
||||||
|
const val CONSOLE_ID_COLLISION = 5
|
||||||
|
const val WRONG_VERSION = 6
|
||||||
|
const val WRONG_PASSWORD = 7
|
||||||
|
const val COULD_NOT_CONNECT = 8
|
||||||
|
const val ROOM_IS_FULL = 9
|
||||||
|
const val HOST_BANNED = 10
|
||||||
|
const val PERMISSION_DENIED = 11
|
||||||
|
const val NO_SUCH_USER = 12
|
||||||
|
const val ALREADY_IN_ROOM = 13
|
||||||
|
const val CREATE_ROOM_ERROR = 14
|
||||||
|
const val HOST_KICKED = 15
|
||||||
|
const val UNKNOWN_ERROR = 16
|
||||||
|
const val ROOM_UNINITIALIZED = 17
|
||||||
|
const val ROOM_IDLE = 18
|
||||||
|
const val ROOM_JOINING = 19
|
||||||
|
const val ROOM_JOINED = 20
|
||||||
|
const val ROOM_MODERATOR = 21
|
||||||
|
const val MEMBER_JOIN = 22
|
||||||
|
const val MEMBER_LEAVE = 23
|
||||||
|
const val MEMBER_KICKED = 24
|
||||||
|
const val MEMBER_BANNED = 25
|
||||||
|
const val ADDRESS_UNBANNED = 26
|
||||||
|
const val CHAT_MESSAGE = 27
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import org.citron.citron_emu.HomeNavigationDirections
|
||||||
import org.citron.citron_emu.NativeLibrary
|
import org.citron.citron_emu.NativeLibrary
|
||||||
import org.citron.citron_emu.R
|
import org.citron.citron_emu.R
|
||||||
import org.citron.citron_emu.databinding.ActivityMainBinding
|
import org.citron.citron_emu.databinding.ActivityMainBinding
|
||||||
|
import org.citron.citron_emu.dialogs.NetPlayDialog
|
||||||
import org.citron.citron_emu.features.settings.model.Settings
|
import org.citron.citron_emu.features.settings.model.Settings
|
||||||
import org.citron.citron_emu.fragments.AddGameFolderDialogFragment
|
import org.citron.citron_emu.fragments.AddGameFolderDialogFragment
|
||||||
import org.citron.citron_emu.fragments.ProgressDialogFragment
|
import org.citron.citron_emu.fragments.ProgressDialogFragment
|
||||||
|
@ -68,6 +69,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
|
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
|
||||||
|
|
||||||
ThemeHelper.setTheme(this)
|
ThemeHelper.setTheme(this)
|
||||||
|
NativeLibrary.netPlayInit()
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
@ -157,6 +159,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
setInsets()
|
setInsets()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun displayMultiplayerDialog() {
|
||||||
|
val dialog = NetPlayDialog(this)
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun checkKeys() {
|
private fun checkKeys() {
|
||||||
if (!NativeLibrary.areKeysPresent()) {
|
if (!NativeLibrary.areKeysPresent()) {
|
||||||
MessageDialogFragment.newInstance(
|
MessageDialogFragment.newInstance(
|
||||||
|
@ -370,6 +377,57 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val getTitleKey =
|
||||||
|
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
||||||
|
if (result != null) {
|
||||||
|
processTitleKey(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun processTitleKey(result: Uri): Boolean {
|
||||||
|
if (FileUtil.getExtension(result) != "keys") {
|
||||||
|
MessageDialogFragment.newInstance(
|
||||||
|
this,
|
||||||
|
titleId = R.string.reading_keys_failure,
|
||||||
|
descriptionId = R.string.install_title_keys_failure_extension_description
|
||||||
|
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
contentResolver.takePersistableUriPermission(
|
||||||
|
result,
|
||||||
|
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
)
|
||||||
|
|
||||||
|
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
|
||||||
|
if (FileUtil.copyUriToInternalStorage(
|
||||||
|
result,
|
||||||
|
dstPath,
|
||||||
|
"title.keys"
|
||||||
|
) != null
|
||||||
|
) {
|
||||||
|
if (NativeLibrary.reloadKeys()) {
|
||||||
|
Toast.makeText(
|
||||||
|
applicationContext,
|
||||||
|
R.string.install_keys_success,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
homeViewModel.setCheckKeys(true)
|
||||||
|
gamesViewModel.reloadGames(true)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
MessageDialogFragment.newInstance(
|
||||||
|
this,
|
||||||
|
titleId = R.string.invalid_keys_error,
|
||||||
|
descriptionId = R.string.install_keys_failure_description,
|
||||||
|
helpLinkId = R.string.dumping_keys_quickstart_link
|
||||||
|
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
val getFirmware =
|
val getFirmware =
|
||||||
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2024 Mandarine Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
package org.citron.citron_emu.utils
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
|
||||||
|
object CompatUtils {
|
||||||
|
fun findActivity(context: Context): Activity {
|
||||||
|
return when (context) {
|
||||||
|
is Activity -> context
|
||||||
|
is ContextWrapper -> findActivity(context.baseContext)
|
||||||
|
else -> throw IllegalArgumentException("Context is not an Activity")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package org.citron.citron_emu.utils
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.Signature
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Process
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
object LicenseVerifier {
|
||||||
|
private const val EXPECTED_PACKAGE = "org.citron.citron_emu"
|
||||||
|
private const val ALTERNATE_PACKAGE = "com.miHoYo.Yuanshen"
|
||||||
|
private const val ALTERNATE_PACKAGE_2 = "com.antutu.ABenchMark"
|
||||||
|
private const val OFFICIAL_HASH = "308202e4308201cc020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b30090603550406130255533020170d3231303831383138303335305a180f32303531303831313138303335305a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330820122300d06092a864886f70d01010105000382010f003082010a0282010100803b4ba8d352ed0475a8442032eadb75ea0a865a0c310c59970bc5f011f162733941a17bac932e060a7f6b00e1d87e640d87951753ee396893769a6e4a60baddc2bf896cd46d5a08c8321879b955eeb6d9f43908029ec6e938433432c5a1ba19da26d8b3dba39f919695626fba5c412b4aba03d85f0246e79af54d6d57347aa6b5095fe916a34262e7060ef4d3f436e7ce03093757fb719b7e72267402289b0fd819673ee44b5aee23237be8e46be08df64b42de09be6090c49d6d0d7d301f0729e25c67eae2d862a87db0aa19db25ba291aae60c7740e0b745af0f1f236dadeb81fe29104a0731eb9091249a94bb56a90239b6496977ebaf1d98b6fa9f679cd0203010001300d06092a864886f70d01010505000382010100784d8e8d28b11bbdb09b5d9e7b8b4fac0d6defd2703d43da63ad4702af76f6ac700f5dcc2f480fbbf6fb664daa64132b36eb7a7880ade5be12919a14c8816b5c1da06870344902680e8ace430705d0a08158d44a3dc710fff6d60b6eb5eff4056bb7d462dafed5b8533c815988805c9f529ef1b70c7c10f1e225eded6db08f847ae805d8b37c174fa0b42cbab1053acb629711e60ce469de383173e714ae2ea76a975169785d1dbe330f803f7f12dd6616703dbaae4d4c327c5174bee83f83635e06f8634cf49d63ba5c3a4f865572740cf9e720e7df1d48fd7a4a2a651d7bb9f40d1cc6b6680b384827a6ea2a44cc1e5168218637fc5da0c3739caca8d21a1d"
|
||||||
|
|
||||||
|
fun verifyLicense(activity: Activity) {
|
||||||
|
val currentPackage = activity.packageName
|
||||||
|
val isDebugBuild = currentPackage.endsWith(".debug")
|
||||||
|
val isEaBuild = currentPackage.endsWith(".ea")
|
||||||
|
|
||||||
|
// Check package name
|
||||||
|
if (!isDebugBuild && !isEaBuild &&
|
||||||
|
currentPackage != EXPECTED_PACKAGE &&
|
||||||
|
currentPackage != ALTERNATE_PACKAGE &&
|
||||||
|
currentPackage != ALTERNATE_PACKAGE_2) {
|
||||||
|
showViolationDialog(activity)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
activity.packageManager.getPackageInfo(
|
||||||
|
currentPackage,
|
||||||
|
PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNATURES.toLong())
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
activity.packageManager.getPackageInfo(currentPackage, PackageManager.GET_SIGNATURES)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verifySignature(packageInfo.signatures)) {
|
||||||
|
showViolationDialog(activity)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
showViolationDialog(activity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifySignature(signatures: Array<Signature>?): Boolean {
|
||||||
|
if (signatures == null || signatures.isEmpty()) return false
|
||||||
|
val currentSignature = signatures[0].toCharsString()
|
||||||
|
return currentSignature == OFFICIAL_HASH
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showViolationDialog(activity: Activity) {
|
||||||
|
AlertDialog.Builder(activity)
|
||||||
|
.setTitle("License Violation")
|
||||||
|
.setMessage("This appears to be a modified version of Citron Emulator. " +
|
||||||
|
"Redistributing modified versions without source code violates the GPLv3 License. " +
|
||||||
|
"The application will now close.")
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton("Exit") { _, _ ->
|
||||||
|
activity.finish()
|
||||||
|
Process.killProcess(Process.myPid())
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: 2025 Citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
@ -51,7 +52,7 @@ struct Values {
|
||||||
|
|
||||||
Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android};
|
Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android};
|
||||||
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
|
Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android};
|
||||||
Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds",
|
Settings::Setting<bool> black_backgrounds{linkage, true, "black_backgrounds",
|
||||||
Settings::Category::Android};
|
Settings::Category::Android};
|
||||||
|
|
||||||
// Input/performance overlay settings
|
// Input/performance overlay settings
|
||||||
|
@ -67,8 +68,10 @@ struct Values {
|
||||||
Settings::Category::Overlay};
|
Settings::Category::Overlay};
|
||||||
Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",
|
Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",
|
||||||
Settings::Category::Overlay};
|
Settings::Category::Overlay};
|
||||||
Settings::Setting<bool> show_thermal_overlay{linkage, false, "show_thermal_overlay",
|
Settings::Setting<bool> show_thermal_overlay{linkage, true, "show_thermal_overlay",
|
||||||
Settings::Category::Overlay};
|
Settings::Category::Overlay};
|
||||||
|
Settings::Setting<bool> show_ram_overlay{linkage, false, "show_ram_overlay",
|
||||||
|
Settings::Category::Overlay};
|
||||||
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
|
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
|
||||||
Settings::Category::Overlay};
|
Settings::Category::Overlay};
|
||||||
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
|
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <frontend_common/content_manager.h>
|
#include <frontend_common/content_manager.h>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include "common/android/multiplayer/multiplayer.h"
|
||||||
#include "common/android/android_common.h"
|
#include "common/android/android_common.h"
|
||||||
#include "common/android/id_cache.h"
|
#include "common/android/id_cache.h"
|
||||||
#include "common/detached_tasks.h"
|
#include "common/detached_tasks.h"
|
||||||
|
@ -870,4 +871,83 @@ jboolean Java_org_citron_citron_1emu_NativeLibrary_areKeysPresent(JNIEnv* env, j
|
||||||
return ContentManager::AreKeysPresent();
|
return ContentManager::AreKeysPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayCreateRoom(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj, jstring ipaddress, jint port,
|
||||||
|
jstring username, jstring password, jstring room_name, jint max_players) {
|
||||||
|
return static_cast<jint>(
|
||||||
|
NetPlayCreateRoom(Common::Android::GetJString(env, ipaddress), port,
|
||||||
|
Common::Android::GetJString(env, username), Common::Android::GetJString(env, password),
|
||||||
|
Common::Android::GetJString(env, room_name), max_players));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayJoinRoom(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj, jstring ipaddress, jint port,
|
||||||
|
jstring username, jstring password) {
|
||||||
|
return static_cast<jint>(
|
||||||
|
NetPlayJoinRoom(Common::Android::GetJString(env, ipaddress), port,
|
||||||
|
Common::Android::GetJString(env, username), Common::Android::GetJString(env, password)));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL
|
||||||
|
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayRoomInfo(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||||
|
return Common::Android::ToJStringArray(env, NetPlayRoomInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayIsJoined(
|
||||||
|
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||||
|
return NetPlayIsJoined();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayIsHostedRoom(
|
||||||
|
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||||
|
return NetPlayIsHostedRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_citron_citron_1emu_network_NetPlayManager_netPlaySendMessage(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj, jstring msg) {
|
||||||
|
NetPlaySendMessage(Common::Android::GetJString(env, msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayKickUser(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj, jstring username) {
|
||||||
|
NetPlayKickUser(Common::Android::GetJString(env, username));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayLeaveRoom(
|
||||||
|
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||||
|
NetPlayLeaveRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL
|
||||||
|
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayIsModerator(
|
||||||
|
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||||
|
return NetPlayIsModerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jobjectArray JNICALL
|
||||||
|
Java_org_citron_citron_1emu_network_NetPlayManager_netPlayGetBanList(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||||
|
return Common::Android::ToJStringArray(env, NetPlayGetBanList());
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayBanUser(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj, jstring username) {
|
||||||
|
NetPlayBanUser(Common::Android::GetJString(env, username));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_citron_citron_1emu_network_NetPlayManager_netPlayUnbanUser(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj, jstring username) {
|
||||||
|
NetPlayUnbanUser(Common::Android::GetJString(env, username));
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_citron_citron_1emu_NativeLibrary_netPlayInit(
|
||||||
|
JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||||
|
NetworkInit(&EmulationSession::GetInstance().System().GetRoomNetwork());
|
||||||
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
31
src/android/app/src/main/jni/native_library.cpp
Normal file
31
src/android/app/src/main/jni/native_library.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include "core/crypto/key_manager.h"
|
||||||
|
#include "core/hle/service/am/am.h"
|
||||||
|
#include "core/file_sys/registered_cache.h"
|
||||||
|
#include "core/file_sys/content_archive.h"
|
||||||
|
#include "core/system.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL Java_org_citron_citron_1emu_NativeLibrary_isFirmwareAvailable(
|
||||||
|
JNIEnv* env, jobject obj) {
|
||||||
|
return Core::Crypto::KeyManager::Instance().IsFirmwareAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL Java_org_citron_citron_1emu_NativeLibrary_checkFirmwarePresence(
|
||||||
|
JNIEnv* env, jobject obj) {
|
||||||
|
constexpr u64 MiiEditId = 0x0100000000001009; // Mii Edit applet ID
|
||||||
|
constexpr u64 QLaunchId = 0x0100000000001000; // Home Menu applet ID
|
||||||
|
|
||||||
|
auto& system = Core::System::GetInstance();
|
||||||
|
auto bis_system = system.GetFileSystemController().GetSystemNANDContents();
|
||||||
|
if (!bis_system) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mii_applet_nca = bis_system->GetEntry(MiiEditId, FileSys::ContentRecordType::Program);
|
||||||
|
auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
|
||||||
|
|
||||||
|
return (mii_applet_nca != nullptr && qlaunch_nca != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
10
src/android/app/src/main/res/drawable/ic_chat.xml
Normal file
10
src/android/app/src/main/res/drawable/ic_chat.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
|
||||||
|
</vector>
|
9
src/android/app/src/main/res/drawable/ic_ip.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_ip.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z"/>
|
||||||
|
</vector>
|
10
src/android/app/src/main/res/drawable/ic_joined.xml
Normal file
10
src/android/app/src/main/res/drawable/ic_joined.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
|
||||||
|
</vector>
|
9
src/android/app/src/main/res/drawable/ic_multiplayer.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_multiplayer.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
|
||||||
|
</vector>
|
10
src/android/app/src/main/res/drawable/ic_network.xml
Normal file
10
src/android/app/src/main/res/drawable/ic_network.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorPrimary"
|
||||||
|
android:pathData="M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z"/>
|
||||||
|
</vector>
|
9
src/android/app/src/main/res/drawable/ic_send.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_send.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
|
||||||
|
</vector>
|
10
src/android/app/src/main/res/drawable/ic_system.xml
Normal file
10
src/android/app/src/main/res/drawable/ic_system.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z"/>
|
||||||
|
</vector>
|
9
src/android/app/src/main/res/drawable/ic_user.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_user.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||||
|
</vector>
|
|
@ -34,28 +34,41 @@
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:textColor="?attr/colorOnSurface"
|
android:textColor="?attr/colorOnSurface"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/text_description"
|
app:layout_constraintBottom_toTopOf="@+id/scroll_description"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_weight="2"
|
app:layout_constraintVertical_weight="2"
|
||||||
tools:text="@string/welcome" />
|
tools:text="@string/welcome" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<ScrollView
|
||||||
android:id="@+id/text_description"
|
android:id="@+id/scroll_description"
|
||||||
style="@style/TextAppearance.Material3.TitleLarge"
|
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:gravity="center"
|
android:fillViewport="true"
|
||||||
android:textSize="20sp"
|
android:scrollbars="vertical"
|
||||||
android:paddingHorizontal="16dp"
|
android:fadeScrollbars="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:scrollbarStyle="outsideOverlay"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/button_action"
|
app:layout_constraintBottom_toTopOf="@+id/button_action"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/text_title"
|
app:layout_constraintTop_toBottomOf="@+id/text_title"
|
||||||
app:layout_constraintVertical_weight="2"
|
app:layout_constraintVertical_weight="2">
|
||||||
app:lineHeight="30sp"
|
|
||||||
tools:text="@string/welcome_description" />
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/text_description"
|
||||||
|
style="@style/TextAppearance.Material3.TitleLarge"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="16dp"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:lineHeight="30sp"
|
||||||
|
tools:text="@string/welcome_description" />
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_confirmation"
|
android:id="@+id/text_confirmation"
|
||||||
|
@ -72,7 +85,7 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/text_description"
|
app:layout_constraintTop_toBottomOf="@+id/scroll_description"
|
||||||
app:layout_constraintVertical_weight="1"
|
app:layout_constraintVertical_weight="1"
|
||||||
app:lineHeight="30sp" />
|
app:lineHeight="30sp" />
|
||||||
|
|
||||||
|
@ -88,7 +101,7 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/text_description"
|
app:layout_constraintTop_toBottomOf="@+id/scroll_description"
|
||||||
tools:text="Get started" />
|
tools:text="Get started" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
7
src/android/app/src/main/res/layout/dialog_ban_list.xml
Normal file
7
src/android/app/src/main/res/layout/dialog_ban_list.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/ban_list_recycler"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"/>
|
38
src/android/app/src/main/res/layout/dialog_bottom_sheet.xml
Normal file
38
src/android/app/src/main/res/layout/dialog_bottom_sheet.xml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
app:strokeWidth="0dp"
|
||||||
|
app:cardCornerRadius="24dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="?colorSurface">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="128dp"
|
||||||
|
android:layout_height="4dp"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
android:backgroundTint="?colorSurfaceVariant" />
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" />
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
55
src/android/app/src/main/res/layout/dialog_chat.xml
Normal file
55
src/android/app/src/main/res/layout/dialog_chat.xml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/chat"
|
||||||
|
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginBottom="16dp" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/chat_recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:transcriptMode="alwaysScroll" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/type_message">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/chat_input"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text"
|
||||||
|
android:imeOptions="actionSend" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/send_button"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_send"
|
||||||
|
android:contentDescription="@string/send_message" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||||
|
android:id="@+id/drag_handle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_title"
|
||||||
|
android:text="@string/multiplayer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:textColor="?attr/colorOnSurface" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="140dp"
|
||||||
|
android:layout_height="140dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:src="@drawable/ic_network"
|
||||||
|
app:tint="?attr/colorPrimary" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_join"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/multiplayer_join_room"
|
||||||
|
app:icon="@drawable/ic_install"
|
||||||
|
app:cornerRadius="16dp" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="16dp"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_create"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/multiplayer_create_room"
|
||||||
|
app:icon="@drawable/ic_add"
|
||||||
|
app:cornerRadius="16dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,75 @@
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||||
|
android:id="@+id/drag_handle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_title"
|
||||||
|
android:text="@string/multiplayer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:textColor="?attr/colorOnSurface" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/list_multiplayer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_chat"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:enabled="true"
|
||||||
|
android:text="@string/multiplayer_chat"
|
||||||
|
app:icon="@drawable/ic_chat"
|
||||||
|
app:cornerRadius="16dp" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_moderation"
|
||||||
|
style="@style/Widget.Material3.Button.TonalButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:enabled="true"
|
||||||
|
android:text="@string/multiplayer_moderation"
|
||||||
|
app:cornerRadius="16dp"
|
||||||
|
app:icon="@drawable/ic_user" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_leave"
|
||||||
|
style="@style/Widget.Material3.Button"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:text="@string/multiplayer_exit_room"
|
||||||
|
app:icon="@drawable/ic_exit"
|
||||||
|
app:cornerRadius="16dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
119
src/android/app/src/main/res/layout/dialog_multiplayer_room.xml
Normal file
119
src/android/app/src/main/res/layout/dialog_multiplayer_room.xml
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:elevation="4dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?attr/textAppearanceHeadline6"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:textColor="?attr/colorOnSurface" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/multiplayer_ip_address"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/ip_address"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/multiplayer_ip_port"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/ip_port"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="number" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/multiplayer_username"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/username"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/multiplayer_password"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/password"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textPassword" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/multiplayer_room_name"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/room_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/max_players_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.slider.Slider
|
||||||
|
android:id="@+id/max_players"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:value="8"
|
||||||
|
android:valueFrom="2"
|
||||||
|
android:valueTo="16"
|
||||||
|
android:stepSize="1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/max_players_label"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/multiplayer_max_players_value" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_confirm"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@android:string/ok"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
|
@ -171,6 +171,21 @@
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/show_ram_text"
|
||||||
|
style="@style/TextAppearance.Material3.BodySmall"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:focusable="false"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:shadowColor="@android:color/black"
|
||||||
|
android:shadowRadius="3"
|
||||||
|
android:layout_below="@id/show_fps_text"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<com.google.android.material.navigation.NavigationView
|
<com.google.android.material.navigation.NavigationView
|
||||||
|
|
28
src/android/app/src/main/res/layout/item_ban_list.xml
Normal file
28
src/android/app/src/main/res/layout/item_ban_list.xml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@drawable/ic_user"
|
||||||
|
android:layout_marginEnd="16dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ban_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"/>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btn_unban"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/multiplayer_unban"/>
|
||||||
|
</LinearLayout>
|
25
src/android/app/src/main/res/layout/item_button_netplay.xml
Normal file
25
src/android/app/src/main/res/layout/item_button_netplay.xml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/item_button_netplay_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/item_button_more"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/multiplayer_more_options"
|
||||||
|
android:src="@drawable/ic_more_vert"
|
||||||
|
android:padding="12dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
36
src/android/app/src/main/res/layout/item_chat_message.xml
Normal file
36
src/android/app/src/main/res/layout/item_chat_message.xml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/user_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/username_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/message_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/timestamp_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
25
src/android/app/src/main/res/layout/item_netplay_button.xml
Normal file
25
src/android/app/src/main/res/layout/item_netplay_button.xml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/item_button_netplay_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/item_button_netplay"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/multiplayer_kick_member"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/item_button_more"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:src="@drawable/ic_more_vert"/>
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<View xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?android:attr/listDivider"/>
|
18
src/android/app/src/main/res/layout/item_netplay_text.xml
Normal file
18
src/android/app/src/main/res/layout/item_netplay_text.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/item_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="16dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/item_text_netplay_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"/>
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.divider.MaterialDivider
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginVertical="8dp" />
|
24
src/android/app/src/main/res/layout/item_text_netplay.xml
Normal file
24
src/android/app/src/main/res/layout/item_text_netplay.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/item_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:tint="?attr/colorPrimary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/item_text_netplay_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -18,7 +18,7 @@
|
||||||
app:layout_constraintHeight_min="110dp"
|
app:layout_constraintHeight_min="110dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_chainStyle="spread"
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
app:layout_constraintWidth_max="220dp"
|
app:layout_constraintWidth_max="220dp"
|
||||||
app:layout_constraintWidth_min="110dp"
|
app:layout_constraintWidth_min="110dp"
|
||||||
app:layout_constraintVertical_weight="3"
|
app:layout_constraintVertical_weight="3"
|
||||||
|
@ -28,65 +28,56 @@
|
||||||
android:id="@+id/text_title"
|
android:id="@+id/text_title"
|
||||||
style="@style/TextAppearance.Material3.DisplaySmall"
|
style="@style/TextAppearance.Material3.DisplaySmall"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="?attr/colorOnSurface"
|
android:textColor="?attr/colorOnSurface"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/text_description"
|
android:layout_marginBottom="16dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/scroll_description"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/icon"
|
app:layout_constraintTop_toBottomOf="@+id/icon"
|
||||||
app:layout_constraintVertical_weight="1.3"
|
|
||||||
tools:text="@string/welcome" />
|
tools:text="@string/welcome" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<ScrollView
|
||||||
android:id="@+id/text_description"
|
android:id="@+id/scroll_description"
|
||||||
style="@style/TextAppearance.Material3.TitleLarge"
|
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:textAlignment="center"
|
android:fillViewport="true"
|
||||||
android:textSize="20sp"
|
android:scrollbars="vertical"
|
||||||
android:paddingHorizontal="16dp"
|
android:fadeScrollbars="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:scrollbarStyle="outsideOverlay"
|
||||||
|
android:paddingVertical="8dp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/button_action"
|
app:layout_constraintBottom_toTopOf="@+id/button_action"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/text_title"
|
app:layout_constraintTop_toBottomOf="@+id/text_title"
|
||||||
app:layout_constraintVertical_weight="2"
|
app:layout_constraintVertical_weight="2">
|
||||||
app:lineHeight="30sp"
|
|
||||||
tools:text="@string/welcome_description" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_confirmation"
|
android:id="@+id/text_description"
|
||||||
style="@style/TextAppearance.Material3.TitleLarge"
|
style="@style/TextAppearance.Material3.TitleLarge"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="16dp"
|
||||||
android:paddingTop="24dp"
|
android:textAlignment="center"
|
||||||
android:textAlignment="center"
|
android:textSize="20sp"
|
||||||
android:textSize="30sp"
|
app:lineHeight="30sp"
|
||||||
android:visibility="invisible"
|
tools:text="@string/welcome_description" />
|
||||||
android:text="@string/step_complete"
|
|
||||||
android:textStyle="bold"
|
</ScrollView>
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/text_description"
|
|
||||||
app:layout_constraintVertical_weight="1"
|
|
||||||
app:lineHeight="30sp" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_action"
|
android:id="@+id/button_action"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginBottom="48dp"
|
android:layout_marginBottom="48dp"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
app:iconGravity="end"
|
app:iconGravity="end"
|
||||||
app:iconSize="24sp"
|
app:iconSize="24sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
app:layout_constraintTop_toBottomOf="@+id/text_description"
|
|
||||||
tools:text="Get started" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
24
src/android/app/src/main/res/menu/item_text_netplay.xml
Normal file
24
src/android/app/src/main/res/menu/item_text_netplay.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/item_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:tint="?attr/colorPrimary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/item_text_netplay_name"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textAppearance="?attr/textAppearanceBodyLarge" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -1,5 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
tools:ignore="ExtraText">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_pause_emulation"
|
android:id="@+id/menu_pause_emulation"
|
||||||
|
@ -21,6 +23,12 @@
|
||||||
android:icon="@drawable/ic_controller"
|
android:icon="@drawable/ic_controller"
|
||||||
android:title="@string/preferences_controls" />
|
android:title="@string/preferences_controls" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_multiplayer"
|
||||||
|
android:icon="@drawable/ic_multiplayer"
|
||||||
|
android:title="@string/multiplayer" />
|
||||||
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_overlay_controls"
|
android:id="@+id/menu_overlay_controls"
|
||||||
android:icon="@drawable/ic_overlay"
|
android:icon="@drawable/ic_overlay"
|
||||||
|
|
13
src/android/app/src/main/res/menu/menu_netplay_member.xml
Normal file
13
src/android/app/src/main/res/menu/menu_netplay_member.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_kick"
|
||||||
|
android:title="@string/multiplayer_kick_member"
|
||||||
|
android:enabled="false" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_ban"
|
||||||
|
android:title="@string/multiplayer_ban"
|
||||||
|
android:enabled="false" />
|
||||||
|
|
||||||
|
</menu>
|
|
@ -11,6 +11,11 @@
|
||||||
android:title="@string/emulation_thermal_indicator"
|
android:title="@string/emulation_thermal_indicator"
|
||||||
android:checkable="true" />
|
android:checkable="true" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/ram_meter"
|
||||||
|
android:title="@string/emulation_ram_meter"
|
||||||
|
android:checkable="true" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_edit_overlay"
|
android:id="@+id/menu_edit_overlay"
|
||||||
android:title="@string/emulation_touch_overlay_edit" />
|
android:title="@string/emulation_touch_overlay_edit" />
|
||||||
|
|
|
@ -137,7 +137,7 @@
|
||||||
<string name="about_app_description">محاكي سويتش مفتوح المصدر</string>
|
<string name="about_app_description">محاكي سويتش مفتوح المصدر</string>
|
||||||
<string name="contributors">المساهمين</string>
|
<string name="contributors">المساهمين</string>
|
||||||
<string name="contributors_description">مصنوع من فريق يوزو</string>
|
<string name="contributors_description">مصنوع من فريق يوزو</string>
|
||||||
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
|
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
|
||||||
<string name="licenses_description">المشاريع التي تجعل تطبيق يوزو لنظام أندرويد ممكنًا</string>
|
<string name="licenses_description">المشاريع التي تجعل تطبيق يوزو لنظام أندرويد ممكنًا</string>
|
||||||
<string name="build">البناء</string>
|
<string name="build">البناء</string>
|
||||||
<string name="user_data">بيانات المستخدم</string>
|
<string name="user_data">بيانات المستخدم</string>
|
||||||
|
@ -151,7 +151,7 @@
|
||||||
<string name="user_data_export_cancelled">تم إلغاء التصدير</string>
|
<string name="user_data_export_cancelled">تم إلغاء التصدير</string>
|
||||||
<string name="support_link">https://discord.gg/u77vRWY</string>
|
<string name="support_link">https://discord.gg/u77vRWY</string>
|
||||||
<string name="website_link">https://citron-emu.org/</string>
|
<string name="website_link">https://citron-emu.org/</string>
|
||||||
<string name="github_link">https://github.com/citron-emu</string>
|
<string name="github_link">https://git.citron-emu.org</string>
|
||||||
|
|
||||||
<!-- Early access upgrade strings -->
|
<!-- Early access upgrade strings -->
|
||||||
<string name="early_access">الوصول المبكر</string>
|
<string name="early_access">الوصول المبكر</string>
|
||||||
|
|
|
@ -103,12 +103,12 @@
|
||||||
<string name="about_app_description">ئیمۆلیتەرێکی سەرچاوە-کراوەی سویچ</string>
|
<string name="about_app_description">ئیمۆلیتەرێکی سەرچاوە-کراوەی سویچ</string>
|
||||||
<string name="contributors">بەشداربووان</string>
|
<string name="contributors">بەشداربووان</string>
|
||||||
<string name="contributors_description">دروستکراوە لەگەڵ \u2764 لەلایەن تیمەکەی یوزو</string>
|
<string name="contributors_description">دروستکراوە لەگەڵ \u2764 لەلایەن تیمەکەی یوزو</string>
|
||||||
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
|
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
|
||||||
<string name="licenses_description">ئەو پڕۆژانەی کە یوزوی بۆ ئەندرۆید ڕەخساند</string>
|
<string name="licenses_description">ئەو پڕۆژانەی کە یوزوی بۆ ئەندرۆید ڕەخساند</string>
|
||||||
<string name="build">بونیات</string>
|
<string name="build">بونیات</string>
|
||||||
<string name="support_link">https://discord.gg/u77vRWY</string>
|
<string name="support_link">https://discord.gg/u77vRWY</string>
|
||||||
<string name="website_link">https://citron-emu.org/</string>
|
<string name="website_link">https://citron-emu.org/</string>
|
||||||
<string name="github_link">https://github.com/citron-emu</string>
|
<string name="github_link">https://git.citron-emu.org</string>
|
||||||
|
|
||||||
<!-- Early access upgrade strings -->
|
<!-- Early access upgrade strings -->
|
||||||
<string name="early_access">بەزوویی دەسپێگەشتن</string>
|
<string name="early_access">بەزوویی دەسپێگەشتن</string>
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
<string name="about_app_description">Open-source Switch emulátor</string>
|
<string name="about_app_description">Open-source Switch emulátor</string>
|
||||||
<string name="contributors">Přispěvatelé</string>
|
<string name="contributors">Přispěvatelé</string>
|
||||||
<string name="contributors_description">Vyrobeno s \u2764 od citron týmu</string>
|
<string name="contributors_description">Vyrobeno s \u2764 od citron týmu</string>
|
||||||
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
|
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
|
||||||
<string name="build">Číslo sestavení</string>
|
<string name="build">Číslo sestavení</string>
|
||||||
<string name="user_data">Uživatelská data</string>
|
<string name="user_data">Uživatelská data</string>
|
||||||
<string name="exporting_user_data">Exportování uživatelských dat...</string>
|
<string name="exporting_user_data">Exportování uživatelských dat...</string>
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
<string name="user_data_export_cancelled">Export zrušen</string>
|
<string name="user_data_export_cancelled">Export zrušen</string>
|
||||||
<string name="support_link">https://discord.gg/u77vRWY</string>
|
<string name="support_link">https://discord.gg/u77vRWY</string>
|
||||||
<string name="website_link">https://citron-emu.org/</string>
|
<string name="website_link">https://citron-emu.org/</string>
|
||||||
<string name="github_link">https://github.com/citron-emu</string>
|
<string name="github_link">https://git.citron-emu.org</string>
|
||||||
|
|
||||||
<string name="play_store_link">https://play.google.com/store/apps/details?id=org.citron.citron_emu.ea</string>
|
<string name="play_store_link">https://play.google.com/store/apps/details?id=org.citron.citron_emu.ea</string>
|
||||||
<string name="no_manual_installation">Žádná manuální instalace</string>
|
<string name="no_manual_installation">Žádná manuální instalace</string>
|
||||||
|
|
|
@ -122,7 +122,7 @@ Wirklich fortfahren?</string>
|
||||||
<string name="about_app_description">Ein quelloffener Switch-Emulator</string>
|
<string name="about_app_description">Ein quelloffener Switch-Emulator</string>
|
||||||
<string name="contributors">Beitragende</string>
|
<string name="contributors">Beitragende</string>
|
||||||
<string name="contributors_description">Gemacht mit \u2764 vom citron Team</string>
|
<string name="contributors_description">Gemacht mit \u2764 vom citron Team</string>
|
||||||
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
|
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
|
||||||
<string name="licenses_description">Projekte, die citron für Android möglich machen </string>
|
<string name="licenses_description">Projekte, die citron für Android möglich machen </string>
|
||||||
<string name="build">Build</string>
|
<string name="build">Build</string>
|
||||||
<string name="user_data">Nutzerdaten</string>
|
<string name="user_data">Nutzerdaten</string>
|
||||||
|
@ -133,7 +133,7 @@ Wirklich fortfahren?</string>
|
||||||
<string name="user_data_export_cancelled">Export abgebrochen</string>
|
<string name="user_data_export_cancelled">Export abgebrochen</string>
|
||||||
<string name="support_link">https://discord.gg/u77vRWY</string>
|
<string name="support_link">https://discord.gg/u77vRWY</string>
|
||||||
<string name="website_link">https://citron-emu.org/</string>
|
<string name="website_link">https://citron-emu.org/</string>
|
||||||
<string name="github_link">https://github.com/citron-emu</string>
|
<string name="github_link">https://git.citron-emu.org</string>
|
||||||
|
|
||||||
<!-- Early access upgrade strings -->
|
<!-- Early access upgrade strings -->
|
||||||
<string name="early_access">Early Access</string>
|
<string name="early_access">Early Access</string>
|
||||||
|
|
|
@ -167,7 +167,7 @@
|
||||||
<string name="about_app_description">Un emulador de Switch de código abierto</string>
|
<string name="about_app_description">Un emulador de Switch de código abierto</string>
|
||||||
<string name="contributors">Contribuidores</string>
|
<string name="contributors">Contribuidores</string>
|
||||||
<string name="contributors_description">Hecho con \u2764 del equipo citron</string>
|
<string name="contributors_description">Hecho con \u2764 del equipo citron</string>
|
||||||
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
|
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
|
||||||
<string name="licenses_description">Proyectos que hacen que citron para Android sea una realidad</string>
|
<string name="licenses_description">Proyectos que hacen que citron para Android sea una realidad</string>
|
||||||
<string name="build">Versión</string>
|
<string name="build">Versión</string>
|
||||||
<string name="user_data">Datos de usuario</string>
|
<string name="user_data">Datos de usuario</string>
|
||||||
|
@ -182,7 +182,7 @@
|
||||||
<string name="user_data_import_failed_description">Asegúrese de que las carpetas de datos de usuario estén en la raíz de la carpeta del zip y contengan un archivo config en config/config.ini e inténtelo de nuevo.</string>
|
<string name="user_data_import_failed_description">Asegúrese de que las carpetas de datos de usuario estén en la raíz de la carpeta del zip y contengan un archivo config en config/config.ini e inténtelo de nuevo.</string>
|
||||||
<string name="support_link">https://discord.gg/u77vRWY</string>
|
<string name="support_link">https://discord.gg/u77vRWY</string>
|
||||||
<string name="website_link">https://citron-emu.org/</string>
|
<string name="website_link">https://citron-emu.org/</string>
|
||||||
<string name="github_link">https://github.com/citron-emu</string>
|
<string name="github_link">https://git.citron-emu.org</string>
|
||||||
|
|
||||||
<!-- Early access upgrade strings -->
|
<!-- Early access upgrade strings -->
|
||||||
<string name="early_access">Early Access</string>
|
<string name="early_access">Early Access</string>
|
||||||
|
|
|
@ -165,7 +165,7 @@
|
||||||
<string name="about_app_description">یک شبیهساز سوئیچ منبع باز</string>
|
<string name="about_app_description">یک شبیهساز سوئیچ منبع باز</string>
|
||||||
<string name="contributors">مشارکت کنندگان</string>
|
<string name="contributors">مشارکت کنندگان</string>
|
||||||
<string name="contributors_description">Made with \u2764 from the citron team</string>
|
<string name="contributors_description">Made with \u2764 from the citron team</string>
|
||||||
<string name="contributors_link">https://github.com/citron-emu/citron/graphs/contributors</string>
|
<string name="contributors_link">https://git.citron-emu.org/Citron/Citron/graphs/contributors</string>
|
||||||
<string name="licenses_description">پروژههایی که citron را برای اندروید ممکن میسازند</string>
|
<string name="licenses_description">پروژههایی که citron را برای اندروید ممکن میسازند</string>
|
||||||
<string name="build">ساخت</string>
|
<string name="build">ساخت</string>
|
||||||
<string name="user_data">داده کاربر</string>
|
<string name="user_data">داده کاربر</string>
|
||||||
|
@ -180,7 +180,7 @@
|
||||||
<string name="user_data_import_failed_description">مطمئن شوید که پوشههای داده کاربر در ریشه پوشه zip و حاوی یک فایل پیکربندی در config/config.ini هستند سپس دوباره امتحان کنید.</string>
|
<string name="user_data_import_failed_description">مطمئن شوید که پوشههای داده کاربر در ریشه پوشه zip و حاوی یک فایل پیکربندی در config/config.ini هستند سپس دوباره امتحان کنید.</string>
|
||||||
<string name="support_link">https://discord.gg/u77vRWY</string>
|
<string name="support_link">https://discord.gg/u77vRWY</string>
|
||||||
<string name="website_link">https://citron-emu.org/</string>
|
<string name="website_link">https://citron-emu.org/</string>
|
||||||
<string name="github_link">https://github.com/citron-emu</string>
|
<string name="github_link">https://git.citron-emu.org</string>
|
||||||
|
|
||||||
<!-- Early access upgrade strings -->
|
<!-- Early access upgrade strings -->
|
||||||
<string name="early_access">دسترسی زودهنگام</string>
|
<string name="early_access">دسترسی زودهنگام</string>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue