diff options
| author | Producdevity <y.gherbi.dev@gmail.com> | 2025-08-03 17:03:53 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2025-08-03 17:03:53 +0200 |
| commit | f72783e01798da0e984b88f5cef583004d6950be (patch) | |
| tree | 8d79454dade4051f87ee059ceba30b23c61aa1fb /src/android | |
| parent | 3b72c2930361401723e431b31cc7204793ea8aba (diff) | |
[android]: (feat) emuready launch intent + redesign (#162)
feat: emuready intent support and slight redesign
Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/162
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Producdevity <y.gherbi.dev@gmail.com>
Co-committed-by: Producdevity <y.gherbi.dev@gmail.com>
Diffstat (limited to 'src/android')
106 files changed, 2293 insertions, 726 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 89d819d900..05d9fb039c 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -156,7 +156,6 @@ android { } } - externalNativeBuild { cmake { version = "3.22.1" diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index 353c2f722d..d31deaa355 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ SPDX-FileCopyrightText: Eden Emulator Project SPDX-License-Identifier: GPL-3.0-or-later --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android"> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-feature android:name="android.hardware.touchscreen" android:required="false" /> <uses-feature android:name="android.hardware.gamepad" android:required="false" /> <uses-feature android:name="android.software.leanback" android:required="false" /> @@ -42,6 +42,7 @@ SPDX-License-Identifier: GPL-3.0-or-later android:banner="@drawable/tv_banner" android:fullBackupContent="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules_api_31" + tools:targetApi="33" android:enableOnBackInvokedCallback="true"> <meta-data android:name="com.samsung.android.gamehub" android:value="true" /> @@ -85,6 +86,10 @@ SPDX-License-Identifier: GPL-3.0-or-later <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="application/octet-stream" android:scheme="content"/> </intent-filter> + <intent-filter> + <action android:name="dev.eden.eden_emulator.LAUNCH_WITH_CUSTOM_CONFIG" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> <meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" /> </activity> @@ -100,4 +105,4 @@ SPDX-License-Identifier: GPL-3.0-or-later </provider> </application> -</manifest>
\ No newline at end of file +</manifest> diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index c0e5983fc6..ba50bcad34 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -4,7 +4,6 @@ // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later - package org.yuzu.yuzu_emu import android.content.DialogInterface @@ -17,7 +16,6 @@ import android.widget.TextView import androidx.annotation.Keep import androidx.core.net.toUri import com.google.android.material.dialog.MaterialAlertDialogBuilder -import net.swiftzer.semver.SemVer import java.lang.ref.WeakReference import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment @@ -28,7 +26,6 @@ import org.yuzu.yuzu_emu.model.InstallResult import org.yuzu.yuzu_emu.model.Patch import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.network.NetPlayManager -import java.io.File /** * Class which contains methods that interact @@ -276,8 +273,7 @@ object NativeLibrary { val emulationActivity = sEmulationActivity.get() if (emulationActivity != null) { emulationActivity.addNetPlayMessages(type, message) - } - else { + } else { NetPlayManager.addNetPlayMessage(type, message) } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index 40200931b7..e01dc754eb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt @@ -4,7 +4,6 @@ // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later - package org.yuzu.yuzu_emu.activities import android.annotation.SuppressLint @@ -58,7 +57,6 @@ import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NfcReader import org.yuzu.yuzu_emu.utils.ParamPackage import org.yuzu.yuzu_emu.utils.ThemeHelper -import org.yuzu.yuzu_emu.utils.PowerStateUtils import java.text.NumberFormat import kotlin.math.roundToInt @@ -204,6 +202,12 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) + + // Reset navigation graph with new intent data to recreate EmulationFragment + val navHostFragment = + supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment + navHostFragment.navController.setGraph(R.navigation.emulation_navigation, intent.extras) + nfcReader.onNewIntent(intent) InputHandler.updateControllerData() } @@ -421,7 +425,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { NetPlayManager.addNetPlayMessage(type, msg) } - private var pictureInPictureReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent) { if (intent.action == actionPlay) { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index c4652f55e1..11b81a01a6 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -4,15 +4,10 @@ package org.yuzu.yuzu_emu.adapters import android.content.DialogInterface -import android.net.Uri import android.text.Html -import android.text.method.LinkMovementMethod import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup -import android.widget.LinearLayout import android.widget.ImageView -import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.content.pm.ShortcutInfoCompat @@ -37,7 +32,6 @@ import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.ViewUtils.marquee import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder -import androidx.recyclerview.widget.RecyclerView import androidx.core.net.toUri import androidx.core.content.edit import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -94,7 +88,7 @@ class GameAdapter(private val activity: AppCompatActivity) : } VIEW_TYPE_CAROUSEL -> { val carouselBinding = holder.binding as CardGameCarouselBinding - //soothens transient flickering + // soothens transient flickering carouselBinding.cardGameCarousel.scaleY = 0f carouselBinding.cardGameCarousel.alpha = 0f } @@ -103,9 +97,21 @@ class GameAdapter(private val activity: AppCompatActivity) : override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder { val binding = when (viewType) { - VIEW_TYPE_LIST -> CardGameListBinding.inflate(LayoutInflater.from(parent.context), parent, false) - VIEW_TYPE_GRID -> CardGameGridBinding.inflate(LayoutInflater.from(parent.context), parent, false) - VIEW_TYPE_CAROUSEL -> CardGameCarouselBinding.inflate(LayoutInflater.from(parent.context), parent, false) + VIEW_TYPE_LIST -> CardGameListBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + VIEW_TYPE_GRID -> CardGameGridBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + VIEW_TYPE_CAROUSEL -> CardGameCarouselBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) else -> throw IllegalArgumentException("Invalid view type") } return GameViewHolder(binding, viewType) @@ -212,7 +218,10 @@ class GameAdapter(private val activity: AppCompatActivity) : .setIcon(GameIconUtils.getShortcutIcon(activity, game)) .setIntent(game.launchIntent) .build() - ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) + ShortcutManagerCompat.pushDynamicShortcut( + YuzuApplication.appContext, + shortcut + ) } } @@ -232,7 +241,7 @@ class GameAdapter(private val activity: AppCompatActivity) : .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> launch() } - .setNegativeButton(android.R.string.cancel) { _,_ -> } + .setNegativeButton(android.R.string.cancel) { _, _ -> } .show() } else { launch() diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt index 5d72efa350..9e1dc7709e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -6,10 +9,8 @@ package org.yuzu.yuzu_emu.adapters import android.view.LayoutInflater import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.lifecycle.LifecycleOwner -import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.model.HomeSetting diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/ChatDialog.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/ChatDialog.kt index 2ae0377a95..5d6679bd28 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/ChatDialog.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/ChatDialog.kt @@ -28,8 +28,7 @@ class ChatMessage( 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 @@ -50,7 +49,8 @@ class ChatDialog(context: Context) : BottomSheetDialog(context) { behavior.state = BottomSheetBehavior.STATE_EXPANDED behavior.state = BottomSheetBehavior.STATE_EXPANDED - behavior.skipCollapsed = context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE + behavior.skipCollapsed = + context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE handler.post { chatAdapter.notifyDataSetChanged() @@ -133,10 +133,12 @@ class ChatAdapter(private val messages: List<ChatMessage>) : 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 - }) + binding.userIcon.setImageResource( + when (message.nickname) { + "System" -> R.drawable.ic_system + else -> R.drawable.ic_user + } + ) } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt index 39391d6e53..57fd551e02 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/LobbyBrowser.kt @@ -220,7 +220,7 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) { val baseList = NetPlayManager.getPublicRooms() val filteredList = baseList.filter { room -> (!binding.chipHideFull.isChecked || room.members.size < room.maxPlayers) && - (!binding.chipHideEmpty.isChecked || room.members.isNotEmpty()) + (!binding.chipHideEmpty.isChecked || room.members.isNotEmpty()) } if (binding.searchText.text.toString().isEmpty() && @@ -245,7 +245,6 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) { it.score }.map { it.item } adapter.updateRooms(sortedList) - } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt index cd3e9a4474..99ab3ebab2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/NetPlayDialog.kt @@ -16,7 +16,6 @@ import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.Button -import android.widget.EditText import android.widget.PopupMenu import android.widget.Toast import androidx.recyclerview.widget.LinearLayoutManager @@ -38,7 +37,6 @@ import org.yuzu.yuzu_emu.network.NetDataValidators import org.yuzu.yuzu_emu.network.NetPlayManager import org.yuzu.yuzu_emu.utils.CompatUtils import org.yuzu.yuzu_emu.utils.GameHelper -import java.net.InetAddress class NetPlayDialog(context: Context) : BottomSheetDialog(context) { private lateinit var adapter: NetPlayAdapter @@ -55,7 +53,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE when { - NetPlayManager.netPlayIsJoined() -> DialogMultiplayerLobbyBinding.inflate(layoutInflater) + NetPlayManager.netPlayIsJoined() -> DialogMultiplayerLobbyBinding.inflate( + layoutInflater + ) .apply { setContentView(root) adapter = NetPlayAdapter() @@ -77,7 +77,6 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { btnModeration.setOnClickListener { showModerationDialog() } - } else -> { @@ -140,7 +139,8 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { inner class NetPlayAdapter : RecyclerView.Adapter<NetPlayAdapter.NetPlayViewHolder>() { val netPlayItems = mutableListOf<NetPlayItems>() - abstract inner class NetPlayViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), + abstract inner class NetPlayViewHolder(itemView: View) : + RecyclerView.ViewHolder(itemView), View.OnClickListener { init { itemView.setOnClickListener(this) @@ -167,7 +167,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { visibility = if (iconRes != 0) { setImageResource(iconRes) View.VISIBLE - } else View.GONE + } else { + View.GONE + } } } } @@ -186,14 +188,13 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { 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 != StringSetting.WEB_USERNAME.getString() + netPlayItems.name != StringSetting.WEB_USERNAME.getString() menu.findItem(R.id.action_ban).isEnabled = isModerator && - netPlayItems.name != StringSetting.WEB_USERNAME.getString() + netPlayItems.name != StringSetting.WEB_USERNAME.getString() setOnMenuItemClickListener { item -> if (item.itemId == R.id.action_kick) { NetPlayManager.netPlayKickUser(netPlayItems.name) @@ -201,7 +202,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { } else if (item.itemId == R.id.action_ban) { NetPlayManager.netPlayBanUser(netPlayItems.name) true - } else false + } else { + false + } } show() } @@ -360,12 +363,15 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { val visibilityList: List<String> = listOf( context.getString(R.string.multiplayer_public_visibility), - context.getString(R.string.multiplayer_unlisted_visibility), + context.getString(R.string.multiplayer_unlisted_visibility) ) binding.textTitle.text = activity.getString( - if (isCreateRoom) R.string.multiplayer_create_room - else R.string.multiplayer_join_room + if (isCreateRoom) { + R.string.multiplayer_create_room + } else { + R.string.multiplayer_join_room + } ) // setup listeners etc @@ -446,7 +452,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { ) } - binding.dropdownLobbyVisibility.setText(context.getString(R.string.multiplayer_unlisted_visibility)) + binding.dropdownLobbyVisibility.setText( + context.getString(R.string.multiplayer_unlisted_visibility) + ) binding.dropdownLobbyVisibility.apply { setAdapter( @@ -501,8 +509,11 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { binding.btnConfirm.isEnabled = false binding.btnConfirm.text = activity.getString( - if (isCreateRoom) R.string.multiplayer_creating - else R.string.multiplayer_joining + if (isCreateRoom) { + R.string.multiplayer_creating + } else { + R.string.multiplayer_joining + } ) // We don't need to worry about validation because it's already been done. @@ -546,8 +557,11 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { Toast.makeText( YuzuApplication.appContext, - if (isCreateRoom) R.string.multiplayer_create_room_success - else R.string.multiplayer_join_room_success, + if (isCreateRoom) { + R.string.multiplayer_create_room_success + } else { + R.string.multiplayer_join_room_success + }, Toast.LENGTH_LONG ).show() @@ -619,7 +633,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val binding = ItemBanListBinding.inflate( - LayoutInflater.from(parent.context), parent, false + LayoutInflater.from(parent.context), + parent, + false ) return ViewHolder(binding) } @@ -654,6 +670,5 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) { notifyItemRemoved(position) } } - } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt index 14d69cb384..1607371cf5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt @@ -13,7 +13,6 @@ import org.yuzu.yuzu_emu.databinding.ItemDriverGroupBinding import org.yuzu.yuzu_emu.fragments.DriverFetcherFragment.DriverGroup import androidx.core.view.isVisible import androidx.fragment.app.FragmentActivity -import androidx.transition.AutoTransition import androidx.transition.ChangeBounds import androidx.transition.Fade import androidx.transition.TransitionManager @@ -89,7 +88,9 @@ class DriverGroupAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverGroupViewHolder { val binding = ItemDriverGroupBinding.inflate( - LayoutInflater.from(parent.context), parent, false + LayoutInflater.from(parent.context), + parent, + false ) return DriverGroupViewHolder(binding) } @@ -105,4 +106,4 @@ class DriverGroupAdapter( driverGroups = newDriverGroups notifyDataSetChanged() } -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/ReleaseAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/ReleaseAdapter.kt index 1dcec3c9f0..e35ef741fd 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/ReleaseAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/ReleaseAdapter.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + package org.yuzu.yuzu_emu.features.fetcher import android.animation.LayoutTransition @@ -71,7 +74,7 @@ class ReleaseAdapter( // truncates to 150 chars so it does not take up too much space. var bodyPreview = release.body.take(150) - bodyPreview = bodyPreview.replace("#", "").removeSurrounding(" "); + bodyPreview = bodyPreview.replace("#", "").removeSurrounding(" ") val body = bodyPreview.replace("\\r\\n", "\n").replace("\\n", "\n").replace("\n", "<br>") @@ -122,8 +125,11 @@ class ReleaseAdapter( binding.imageDownloadsArrow.rotation = if (isVisible) 0f else 180f binding.buttonToggleDownloads.text = - if (isVisible) activity.getString(R.string.show_downloads) - else activity.getString(R.string.hide_downloads) + if (isVisible) { + activity.getString(R.string.show_downloads) + } else { + activity.getString(R.string.hide_downloads) + } } binding.buttonToggleDownloads.setOnClickListener { @@ -139,9 +145,15 @@ class ReleaseAdapter( release.artifacts.forEach { artifact -> val button = MaterialButton(binding.root.context).apply { text = artifact.name - setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelLarge) + setTextAppearance( + com.google.android.material.R.style.TextAppearance_Material3_LabelLarge + ) textAlignment = MaterialButton.TEXT_ALIGNMENT_VIEW_START - setBackgroundColor(context.getColor(com.google.android.material.R.color.m3_button_background_color_selector)) + setBackgroundColor( + context.getColor( + com.google.android.material.R.color.m3_button_background_color_selector + ) + ) setIconResource(R.drawable.ic_import) iconTint = ColorStateList.valueOf( MaterialColors.getColor( @@ -199,7 +211,9 @@ class ReleaseAdapter( input.copyTo(output) } } - ?: throw IOException(context.getString(R.string.empty_response_body)) + ?: throw IOException( + context.getString(R.string.empty_response_body) + ) } } @@ -211,7 +225,9 @@ class ReleaseAdapter( val driverData = GpuDriverHelper.getMetadataFromZip(file) val driverPath = - "${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(file.toUri())}" + "${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename( + file.toUri() + )}" if (GpuDriverHelper.copyDriverToInternalStorage(file.toUri())) { driverViewModel.onDriverAdded(Pair(driverPath, driverData)) @@ -254,7 +270,9 @@ class ReleaseAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReleaseViewHolder { val binding = ItemReleaseBinding.inflate( - LayoutInflater.from(parent.context), parent, false + LayoutInflater.from(parent.context), + parent, + false ) return ReleaseViewHolder(binding) } @@ -264,4 +282,4 @@ class ReleaseAdapter( } override fun getItemCount(): Int = releases.size -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/SpacingItemDecoration.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/SpacingItemDecoration.kt index 8a8c025d8d..f3d000a739 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/SpacingItemDecoration.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/SpacingItemDecoration.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + package org.yuzu.yuzu_emu.features.fetcher import android.graphics.Rect @@ -16,4 +19,4 @@ class SpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecorat outRect.top = spacing } } -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index 4191bef781..fc6675ec63 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -64,13 +64,12 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { SHOW_SHADERS_BUILDING("show_shaders_building"), DEBUG_FLUSH_BY_LINE("flush_lines"), - USE_LRU_CACHE("use_lru_cache"),; + USE_LRU_CACHE("use_lru_cache"); external fun isRaiiEnabled(): Boolean // external fun isFrameSkippingEnabled(): Boolean external fun isFrameInterpolationEnabled(): Boolean - override fun getBoolean(needsGlobal: Boolean): Boolean = NativeConfig.getBoolean(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index a674857bc1..02950484ac 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -57,7 +57,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { OFFLINE_WEB_APPLET("offline_web_applet_mode"), LOGIN_SHARE_APPLET("login_share_applet_mode"), WIFI_WEB_AUTH_APPLET("wifi_web_auth_applet_mode"), - MY_PAGE_APPLET("my_page_applet_mode"), + MY_PAGE_APPLET("my_page_applet_mode") ; override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt index c7fb646e3a..55ddd5950c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt @@ -13,7 +13,7 @@ enum class StringSetting(override val key: String) : AbstractStringSetting { DEVICE_NAME("device_name"), WEB_TOKEN("eden_token"), - WEB_USERNAME("eden_username"), + WEB_USERNAME("eden_username") ; override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 1b7b1e2152..c2dc10b56c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -21,7 +21,6 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting import org.yuzu.yuzu_emu.features.settings.model.ShortSetting import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.network.NetDataValidators -import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.NativeConfig /** @@ -79,7 +78,7 @@ abstract class SettingsItem( val needsRuntimeGlobal: Boolean get() = NativeLibrary.isRunning() && !setting.global && - !NativeConfig.isPerGameConfigLoaded() + !NativeConfig.isPerGameConfigLoaded() val clearable: Boolean get() = !setting.global && NativeConfig.isPerGameConfigLoaded() @@ -516,7 +515,6 @@ abstract class SettingsItem( ) ) - put( SingleChoiceSetting( IntSetting.RENDERER_VSYNC, @@ -731,7 +729,7 @@ abstract class SettingsItem( val fastmem = object : AbstractBooleanSetting { override fun getBoolean(needsGlobal: Boolean): Boolean = BooleanSetting.FASTMEM.getBoolean() && - BooleanSetting.FASTMEM_EXCLUSIVES.getBoolean() + BooleanSetting.FASTMEM_EXCLUSIVES.getBoolean() override fun setBoolean(value: Boolean) { BooleanSetting.FASTMEM.setBoolean(value) @@ -746,7 +744,7 @@ abstract class SettingsItem( override var global: Boolean get() { return BooleanSetting.FASTMEM.global && - BooleanSetting.FASTMEM_EXCLUSIVES.global + BooleanSetting.FASTMEM_EXCLUSIVES.global } set(value) { BooleanSetting.FASTMEM.global = value diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt index aea72946f7..31d06c1891 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -18,7 +21,7 @@ class SingleChoiceSetting( @ArrayRes val choicesId: Int, @ArrayRes val valuesId: Int, val warnChoices: List<Int> = ArrayList(), - @StringRes val warningMessage: Int = 0, + @StringRes val warningMessage: Int = 0 ) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) { override val type = TYPE_SINGLE_CHOICE diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt index 85076e680d..1d6de233b8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt @@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.features.settings.model.view -import android.text.Editable import androidx.annotation.StringRes import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt index aa17d05e34..dc9f561eca 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt @@ -179,7 +179,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener override fun afterTextChanged(s: Editable?) { val isValid = validator(s.toString()) stringInputBinding.editTextLayout.isErrorEnabled = !isValid - stringInputBinding.editTextLayout.error = if (isValid) null else requireContext().getString(item.errorId) + stringInputBinding.editTextLayout.error = if (isValid) { + null + } else { + requireContext().getString( + item.errorId + ) + } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt index bac90eb4ef..b2fde638db 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -8,7 +11,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.content.edit import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding @@ -16,13 +18,11 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.navigation.findNavController import androidx.navigation.fragment.navArgs -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.transition.MaterialSharedAxis import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding import org.yuzu.yuzu_emu.features.input.NativeInput -import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 364e3b7ba6..3611e979f2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -4,8 +4,6 @@ package org.yuzu.yuzu_emu.features.settings.ui import android.annotation.SuppressLint -import android.app.Activity -import android.app.AlertDialog import android.os.Build import android.widget.Toast import androidx.preference.PreferenceManager @@ -1057,7 +1055,9 @@ class SettingsFragmentPresenter( } val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting { - val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) + val preferences = PreferenceManager.getDefaultSharedPreferences( + YuzuApplication.appContext + ) override fun getInt(needsGlobal: Boolean): Int = preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0) override fun setInt(value: Int) { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt index 2879310007..0ec9984607 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - package org.yuzu.yuzu_emu.fragments import android.content.ClipData diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt index cc95544d25..e2cb5f600d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt @@ -33,7 +33,10 @@ class AddGameFolderDialogFragment : DialogFragment() { .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked) homeViewModel.setGamesDirSelected(true) - val calledFromGameFragment = requireArguments().getBoolean("calledFromGameFragment", false) + val calledFromGameFragment = requireArguments().getBoolean( + "calledFromGameFragment", + false + ) gamesViewModel.addFolder(newGameDir, calledFromGameFragment) } .setNegativeButton(android.R.string.cancel, null) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt index 91670b207d..b8d0f2197e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt @@ -62,14 +62,14 @@ class DriverFetcherFragment : Fragment() { val path: String = "", val sort: Int = 0, val useTagName: Boolean = false, - val sortMode: SortMode = SortMode.Default, + val sortMode: SortMode = SortMode.Default ) private val repoList: List<DriverRepo> = listOf( DriverRepo("Mr. Purple Turnip", "MrPurple666/purple-turnip", 0), DriverRepo("GameHub Adreno 8xx", "crueter/GameHub-8Elite-Drivers", 1), DriverRepo("KIMCHI Turnip", "K11MCH1/AdrenoToolsDrivers", 2, true, SortMode.PublishTime), - DriverRepo("Weab-Chan Freedreno", "Weab-chan/freedreno_turnip-CI", 3), + DriverRepo("Weab-Chan Freedreno", "Weab-chan/freedreno_turnip-CI", 3) ) private val driverMap = listOf( @@ -81,7 +81,7 @@ class DriverFetcherFragment : Fragment() { IntRange(700, 710) to "KIMCHI 25.2.0_r5", IntRange(711, 799) to "Mr. Purple T21", IntRange(800, 899) to "GameHub Adreno 8xx", - IntRange(900, Int.MAX_VALUE) to "Unsupported", + IntRange(900, Int.MAX_VALUE) to "Unsupported" ) private lateinit var driverGroupAdapter: DriverGroupAdapter @@ -124,7 +124,9 @@ class DriverFetcherFragment : Fragment() { } override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? ): View { _binding = FragmentDriverFetcherBinding.inflate(inflater) binding.badgeRecommendedDriver.text = recommendedDriver @@ -178,8 +180,12 @@ class DriverFetcherFragment : Fragment() { } } catch (e: Exception) { withContext(Dispatchers.Main) { - MaterialAlertDialogBuilder(requireActivity()).setTitle(getString(R.string.error_during_fetch)) - .setMessage("${getString(R.string.failed_to_fetch)} ${name}:\n${e.message}") + MaterialAlertDialogBuilder(requireActivity()).setTitle( + getString(R.string.error_during_fetch) + ) + .setMessage( + "${getString(R.string.failed_to_fetch)} $name:\n${e.message}" + ) .setPositiveButton(getString(R.string.ok)) { dialog, _ -> dialog.cancel() } .show() @@ -188,7 +194,9 @@ class DriverFetcherFragment : Fragment() { } val group = DriverGroup( - name, releases, sort + name, + releases, + sort ) synchronized(driverGroups) { @@ -223,7 +231,9 @@ class DriverFetcherFragment : Fragment() { binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets) binding.listDrivers.updatePadding( - bottom = barInsets.bottom + resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab) + bottom = barInsets.bottom + resources.getDimensionPixelSize( + R.dimen.spacing_bottom_list_fab + ) ) windowInsets @@ -239,11 +249,13 @@ class DriverFetcherFragment : Fragment() { var artifacts: List<Artifact> = ArrayList(), var prerelease: Boolean = false, var latest: Boolean = false, - var publishTime: LocalDateTime = LocalDateTime.now(), + var publishTime: LocalDateTime = LocalDateTime.now() ) { companion object { fun fromJsonArray( - jsonString: String, useTagName: Boolean, sortMode: SortMode + jsonString: String, + useTagName: Boolean, + sortMode: SortMode ): ArrayList<Release> { val mapper = jacksonObjectMapper() @@ -310,7 +322,16 @@ class DriverFetcherFragment : Fragment() { } } - return Release(tagName, titleName, title, body, artifacts, prerelease, false, localTime) + return Release( + tagName, + titleName, + title, + body, + artifacts, + prerelease, + false, + localTime + ) } catch (e: Exception) { // TODO: handle malformed input. e.printStackTrace() @@ -324,6 +345,6 @@ class DriverFetcherFragment : Fragment() { data class DriverGroup( val name: String, val releases: ArrayList<Release>, - val sort: Int, + val sort: Int ) -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt index 47b84a403a..f521343272 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt @@ -25,7 +25,6 @@ import kotlinx.coroutines.withContext import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.adapters.DriverAdapter import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding -import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver @@ -108,7 +107,9 @@ class DriverManagerFragment : Fragment() { } binding.buttonFetch.setOnClickListener { - binding.root.findNavController().navigate(R.id.action_driverManagerFragment_to_driverFetcherFragment) + binding.root.findNavController().navigate( + R.id.action_driverManagerFragment_to_driverFetcherFragment + ) } binding.listDrivers.apply { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 6cce31a4eb..516ed22f6f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -45,6 +45,7 @@ import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout.DrawerListener import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import androidx.navigation.fragment.navArgs import androidx.window.layout.FoldingFeature @@ -52,7 +53,6 @@ import androidx.window.layout.WindowInfoTracker import androidx.window.layout.WindowLayoutInfo import com.google.android.material.color.MaterialColors import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.google.android.material.slider.Slider import com.google.android.material.textview.MaterialTextView import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.NativeLibrary @@ -81,6 +81,12 @@ import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.collect +import org.yuzu.yuzu_emu.utils.CustomSettingsHandler +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import kotlinx.coroutines.Dispatchers +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine import java.io.File class EmulationFragment : Fragment(), SurfaceHolder.Callback { @@ -90,24 +96,29 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { private var perfStatsUpdater: (() -> Unit)? = null private var socUpdater: (() -> Unit)? = null - private lateinit var cpuBackend: String - private lateinit var gpuDriver: String - private var _binding: FragmentEmulationBinding? = null + private val binding get() = _binding!! private val args by navArgs<EmulationFragmentArgs>() - private lateinit var game: Game + private var game: Game? = null private val emulationViewModel: EmulationViewModel by activityViewModels() private val driverViewModel: DriverViewModel by activityViewModels() private var isInFoldableLayout = false + private var emulationStarted = false private lateinit var gpuModel: String private lateinit var fwVersion: String + private var intentGame: Game? = null + private var isCustomSettingsIntent = false + + private var perfStatsRunnable: Runnable? = null + private var socRunnable: Runnable? = null + override fun onAttach(context: Context) { super.onAttach(context) if (context is EmulationActivity) { @@ -125,9 +136,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { super.onCreate(savedInstanceState) updateOrientation() - val intentUri: Uri? = requireActivity().intent.data - var intentGame: Game? = null - if (intentUri != null) { + val intent = requireActivity().intent + val intentUri: Uri? = intent.data + intentGame = null + isCustomSettingsIntent = false + + if (intent.action == CustomSettingsHandler.CUSTOM_CONFIG_ACTION) { + handleEmuReadyIntent(intent) + return + } else if (intentUri != null) { intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri))) { GameHelper.getGame(requireActivity().intent.data!!, false) } else { @@ -135,37 +152,308 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } } + finishGameSetup() + } + + /** + * Complete the game setup process (extracted for async custom settings handling) + */ + private fun finishGameSetup() { try { - game = if (args.game != null) { - args.game!! - } else { - intentGame!! + val gameToUse = args.game ?: intentGame + + if (gameToUse == null) { + Log.error("[EmulationFragment] No game found in arguments or intent") + Toast.makeText( + requireContext(), + R.string.no_game_present, + Toast.LENGTH_SHORT + ).show() + requireActivity().finish() + return } - } catch (e: NullPointerException) { + + game = gameToUse + + } catch (e: Exception) { + Log.error("[EmulationFragment] Error during game setup: ${e.message}") Toast.makeText( requireContext(), - R.string.no_game_present, + "Setup error: ${e.message?.take(30) ?: "Unknown"}", Toast.LENGTH_SHORT ).show() requireActivity().finish() return } - // Always load custom settings when launching a game from an intent - if (args.custom || intentGame != null) { - SettingsFile.loadCustomConfig(game) - NativeConfig.unloadPerGameConfig() + try { + when { + // Game launched via intent (check for existing custom config) + intentGame != null -> { + game?.let { gameInstance -> + val customConfigFile = SettingsFile.getCustomSettingsFile(gameInstance) + if (customConfigFile.exists()) { + Log.info("[EmulationFragment] Found existing custom settings for ${gameInstance.title}, loading them") + SettingsFile.loadCustomConfig(gameInstance) + } else { + Log.info("[EmulationFragment] No custom settings found for ${gameInstance.title}, using global settings") + NativeConfig.reloadGlobalConfig() + } + } ?: run { + Log.info("[EmulationFragment] No game available, using global settings") + NativeConfig.reloadGlobalConfig() + } + } + + // Normal game launch from arguments + else -> { + val shouldUseCustom = game?.let { it == args.game && args.custom } ?: false + + if (shouldUseCustom) { + SettingsFile.loadCustomConfig(game!!) + Log.info("[EmulationFragment] Loading custom settings for ${game!!.title}") + } else { + Log.info("[EmulationFragment] Using global settings") + NativeConfig.reloadGlobalConfig() + } + } + } + } catch (e: Exception) { + Log.error("[EmulationFragment] Error loading configuration: ${e.message}") + Log.info("[EmulationFragment] Falling back to global settings") + try { + NativeConfig.reloadGlobalConfig() + } catch (fallbackException: Exception) { + Log.error("[EmulationFragment] Critical error: could not load global config: ${fallbackException.message}") + throw fallbackException + } + } + + emulationState = EmulationState(game!!.path) { + return@EmulationState driverViewModel.isInteractionAllowed.value + } + + } + + /** + * Handle EmuReady intent for launching games with or without custom settings + */ + private fun handleEmuReadyIntent(intent: Intent) { + val titleId = intent.getStringExtra(CustomSettingsHandler.EXTRA_TITLE_ID) + val customSettings = intent.getStringExtra(CustomSettingsHandler.EXTRA_CUSTOM_SETTINGS) + + if (titleId != null) { + Log.info("[EmulationFragment] Received EmuReady intent for title: $titleId") + + lifecycleScope.launch { + try { + Toast.makeText( + requireContext(), + getString(R.string.searching_for_game), + Toast.LENGTH_SHORT + ).show() + val foundGame = CustomSettingsHandler.findGameByTitleId( + titleId, + requireContext() + ) + if (foundGame == null) { + Log.error("[EmulationFragment] Game not found for title ID: $titleId") + Toast.makeText( + requireContext(), + getString(R.string.game_not_found_for_title_id, titleId), + Toast.LENGTH_LONG + ).show() + requireActivity().finish() + return@launch + } + + val shouldLaunch = showLaunchConfirmationDialog( + foundGame.title, + customSettings != null + ) + if (!shouldLaunch) { + Log.info("[EmulationFragment] User cancelled EmuReady launch") + requireActivity().finish() + return@launch + } + + if (customSettings != null) { + intentGame = CustomSettingsHandler.applyCustomSettingsWithDriverCheck( + titleId, + customSettings, + requireContext(), + requireActivity(), + driverViewModel + ) + + if (intentGame == null) { + Log.error( + "[EmulationFragment] Custom settings processing failed for title ID: $titleId" + ) + Toast.makeText( + requireContext(), + getString(R.string.custom_settings_failed_title), + Toast.LENGTH_SHORT + ).show() + + val launchWithDefault = askUserToLaunchWithDefaultSettings( + foundGame.title, + getString(R.string.custom_settings_failure_reasons) + ) + + if (launchWithDefault) { + Log.info( + "[EmulationFragment] User chose to launch with default settings" + ) + Toast.makeText( + requireContext(), + getString(R.string.launch_with_default_settings), + Toast.LENGTH_SHORT + ).show() + intentGame = foundGame + isCustomSettingsIntent = false + } else { + Log.info( + "[EmulationFragment] User cancelled launch after custom settings failure" + ) + Toast.makeText( + requireContext(), + getString(R.string.launch_cancelled), + Toast.LENGTH_SHORT + ).show() + requireActivity().finish() + return@launch + } + } else { + isCustomSettingsIntent = true + } + } else { + Log.info("[EmulationFragment] Launching game with default settings") + + val customConfigFile = SettingsFile.getCustomSettingsFile(foundGame) + if (customConfigFile.exists()) { + Log.info("[EmulationFragment] Found existing custom settings for ${foundGame.title}, loading them") + SettingsFile.loadCustomConfig(foundGame) + } else { + Log.info("[EmulationFragment] No custom settings found for ${foundGame.title}, using global settings") + } + + Toast.makeText( + requireContext(), + getString(R.string.launching_game, foundGame.title), + Toast.LENGTH_SHORT + ).show() + intentGame = foundGame + isCustomSettingsIntent = false + } + + if (intentGame != null) { + withContext(Dispatchers.Main) { + try { + finishGameSetup() + Log.info("[EmulationFragment] Game setup complete for intent launch") + + if (_binding != null) { + // Hide loading indicator immediately for intent launches + binding.loadingIndicator.visibility = View.GONE + binding.surfaceEmulation.visibility = View.VISIBLE + + completeViewSetup() + + // For intent launches, check if surface is ready and start emulation + binding.root.post { + if (binding.surfaceEmulation.holder.surface?.isValid == true && !emulationStarted) { + emulationStarted = true + emulationState.newSurface(binding.surfaceEmulation.holder.surface) + } + } + } + } catch (e: Exception) { + Log.error("[EmulationFragment] Error in finishGameSetup: ${e.message}") + requireActivity().finish() + return@withContext + } + } + } else { + Log.error("[EmulationFragment] No valid game found after processing intent") + Toast.makeText( + requireContext(), + getString(R.string.failed_to_initialize_game), + Toast.LENGTH_SHORT + ).show() + requireActivity().finish() + } + } catch (e: Exception) { + Log.error("[EmulationFragment] Error processing EmuReady intent: ${e.message}") + Toast.makeText( + requireContext(), + "Error: ${e.message?.take(50) ?: "Unknown error"}", + Toast.LENGTH_LONG + ).show() + requireActivity().finish() + } + } } else { - NativeConfig.reloadGlobalConfig() + Log.error("[EmulationFragment] EmuReady intent missing title_id") + Toast.makeText( + requireContext(), + "Invalid request: missing title ID", + Toast.LENGTH_SHORT + ).show() + requireActivity().finish() } + } - // Install the selected driver asynchronously as the game starts - driverViewModel.onLaunchGame() + /** + * Show confirmation dialog for EmuReady game launches + */ + private suspend fun showLaunchConfirmationDialog(gameTitle: String, hasCustomSettings: Boolean): Boolean { + return suspendCoroutine { continuation -> + requireActivity().runOnUiThread { + val message = if (hasCustomSettings) { + getString( + R.string.custom_intent_launch_message_with_settings, + gameTitle + ) + } else { + getString(R.string.custom_intent_launch_message, gameTitle) + } - // So this fragment doesn't restart on configuration changes; i.e. rotation. - retainInstance = true - emulationState = EmulationState(game.path) { - return@EmulationState driverViewModel.isInteractionAllowed.value + MaterialAlertDialogBuilder(requireContext()) + .setTitle(getString(R.string.custom_intent_launch_title)) + .setMessage(message) + .setPositiveButton(getString(R.string.launch)) { _, _ -> + continuation.resume(true) + } + .setNegativeButton(getString(R.string.cancel)) { _, _ -> + continuation.resume(false) + } + .setCancelable(false) + .show() + } + } + } + + /** + * Ask user if they want to launch with default settings when custom settings fail + */ + private suspend fun askUserToLaunchWithDefaultSettings(gameTitle: String, errorMessage: String): Boolean { + return suspendCoroutine { continuation -> + requireActivity().runOnUiThread { + MaterialAlertDialogBuilder(requireContext()) + .setTitle(getString(R.string.custom_settings_failed_title)) + .setMessage( + getString(R.string.custom_settings_failed_message, gameTitle, errorMessage) + ) + .setPositiveButton(getString(R.string.launch_with_default_settings)) { _, _ -> + continuation.resume(true) + } + .setNegativeButton(getString(R.string.cancel)) { _, _ -> + continuation.resume(false) + } + .setCancelable(false) + .show() + } } } @@ -187,6 +475,20 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { return } + if (game == null) { + Log.warning("[EmulationFragment] Game not yet initialized in onViewCreated - will be set up by async intent handler") + return + } + + completeViewSetup() + } + + private fun completeViewSetup() { + if (_binding == null || game == null) { + return + } + Log.info("[EmulationFragment] Starting view setup for game: ${game?.title}") + gpuModel = GpuDriverHelper.getGpuModel().toString() fwVersion = NativeLibrary.firmwareVersion() @@ -223,10 +525,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } }) binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) - binding.inGameMenu.getHeaderView(0).apply { - val titleView = findViewById<TextView>(R.id.text_game_title) - titleView.text = game.title - } + + updateGameTitle() binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply { val lockMode = IntSetting.LOCK_DRAWER.getInt() @@ -293,13 +593,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { true } - R.id.menu_multiplayer -> { emulationActivity?.displayMultiplayerDialog() true } - R.id.menu_controls -> { val action = HomeNavigationDirections.actionGlobalSettingsActivity( null, @@ -368,8 +666,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } ) - GameIconUtils.loadGameIcon(game, binding.loadingImage) - binding.loadingTitle.text = game.title + GameIconUtils.loadGameIcon(game!!, binding.loadingImage) + binding.loadingTitle.text = game!!.title binding.loadingTitle.isSelected = true binding.loadingText.isSelected = true @@ -408,7 +706,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { emulationState.updateSurface() - // Setup overlays updateShowStatsOverlay() updateSocOverlay() @@ -418,7 +715,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { val cpuBackendLabel = findViewById<TextView>(R.id.cpu_backend) val vendorLabel = findViewById<TextView>(R.id.gpu_vendor) - titleView.text = game.title + titleView.text = game?.title ?: "" cpuBackendLabel.text = NativeLibrary.getCpuBackend() vendorLabel.text = NativeLibrary.getGpuDriver() } @@ -456,16 +753,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { ViewUtils.showView(binding.loadingIndicator) } } - emulationViewModel.emulationStopped.collect(viewLifecycleOwner) { - if (it && emulationViewModel.programChanged.value != -1) { - if (perfStatsUpdater != null) { - perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) - } - if (socUpdater != null) { - socUpdateHandler.removeCallbacks(socUpdater!!) + emulationViewModel.emulationStopped.collect(viewLifecycleOwner) { stopped -> + if (stopped && emulationViewModel.programChanged.value != -1) { + perfStatsRunnable?.let { runnable -> + perfStatsUpdateHandler.removeCallbacks( + runnable + ) } - + socRunnable?.let { runnable -> socUpdateHandler.removeCallbacks(runnable) } emulationState.changeProgram(emulationViewModel.programChanged.value) emulationViewModel.setProgramChanged(-1) emulationViewModel.setEmulationStopped(false) @@ -473,8 +769,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) { - if (it) startEmulation() + if (it && !NativeLibrary.isRunning() && !NativeLibrary.isPaused()) { + startEmulation() + } } + + driverViewModel.onLaunchGame() } private fun startEmulation(programIndex: Int = 0) { @@ -518,6 +818,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } } + private fun updateGameTitle() { + game?.let { + binding.inGameMenu.getHeaderView(0).apply { + val titleView = findViewById<TextView>(R.id.text_game_title) + titleView.text = it.title + } + } + } + override fun onPause() { if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) { emulationState.pause() @@ -634,7 +943,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { val batteryTemp = getBatteryTemperature() when (IntSetting.BAT_TEMPERATURE_UNIT.getInt(needsGlobal)) { 0 -> sb.append(String.format("%.1f°C", batteryTemp)) - 1 -> sb.append(String.format("%.1f°F", celsiusToFahrenheit(batteryTemp))) + 1 -> sb.append( + String.format( + "%.1f°F", + celsiusToFahrenheit(batteryTemp) + ) + ) } } @@ -643,8 +957,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { val battery: BatteryManager = requireContext().getSystemService(Context.BATTERY_SERVICE) as BatteryManager - val batteryIntent = requireContext().registerReceiver(null, - IntentFilter(Intent.ACTION_BATTERY_CHANGED)) + val batteryIntent = requireContext().registerReceiver( + null, + IntentFilter(Intent.ACTION_BATTERY_CHANGED) + ) val capacity = battery.getIntProperty(BATTERY_PROPERTY_CAPACITY) val nowUAmps = battery.getIntProperty(BATTERY_PROPERTY_CURRENT_NOW) @@ -653,7 +969,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { val status = batteryIntent?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || - status == BatteryManager.BATTERY_STATUS_FULL + status == BatteryManager.BATTERY_STATUS_FULL if (isCharging) { sb.append(" ${getString(R.string.charging)}") @@ -671,20 +987,21 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } if (BooleanSetting.PERF_OVERLAY_BACKGROUND.getBoolean(needsGlobal)) { - binding.showStatsOverlayText.setBackgroundResource(R.color.yuzu_transparent_black) + binding.showStatsOverlayText.setBackgroundResource( + R.color.yuzu_transparent_black + ) } else { binding.showStatsOverlayText.setBackgroundResource(0) } binding.showStatsOverlayText.text = sb.toString() } - perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800) + perfStatsUpdateHandler.postDelayed(perfStatsRunnable!!, 800) } - perfStatsUpdateHandler.post(perfStatsUpdater!!) + perfStatsRunnable = Runnable { perfStatsUpdater?.invoke() } + perfStatsUpdateHandler.post(perfStatsRunnable!!) } else { - if (perfStatsUpdater != null) { - perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) - } + perfStatsRunnable?.let { perfStatsUpdateHandler.removeCallbacks(it) } } } @@ -767,47 +1084,62 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { ) { sb.setLength(0) - if (BooleanSetting.SHOW_DEVICE_MODEL.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_DEVICE_MODEL.getBoolean( + NativeConfig.isPerGameConfigLoaded() + ) + ) { sb.append(Build.MODEL) } - if (BooleanSetting.SHOW_GPU_MODEL.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_GPU_MODEL.getBoolean( + NativeConfig.isPerGameConfigLoaded() + ) + ) { if (sb.isNotEmpty()) sb.append(" | ") sb.append(gpuModel) } if (Build.VERSION.SDK_INT >= 31) { - if (BooleanSetting.SHOW_SOC_MODEL.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_SOC_MODEL.getBoolean( + NativeConfig.isPerGameConfigLoaded() + ) + ) { if (sb.isNotEmpty()) sb.append(" | ") sb.append(Build.SOC_MODEL) } } - if (BooleanSetting.SHOW_FW_VERSION.getBoolean(NativeConfig.isPerGameConfigLoaded())) { + if (BooleanSetting.SHOW_FW_VERSION.getBoolean( + NativeConfig.isPerGameConfigLoaded() + ) + ) { if (sb.isNotEmpty()) sb.append(" | ") sb.append(fwVersion) } binding.showSocOverlayText.text = sb.toString() - if (BooleanSetting.SOC_OVERLAY_BACKGROUND.getBoolean(NativeConfig.isPerGameConfigLoaded())) { - binding.showSocOverlayText.setBackgroundResource(R.color.yuzu_transparent_black) + if (BooleanSetting.SOC_OVERLAY_BACKGROUND.getBoolean( + NativeConfig.isPerGameConfigLoaded() + ) + ) { + binding.showSocOverlayText.setBackgroundResource( + R.color.yuzu_transparent_black + ) } else { binding.showSocOverlayText.setBackgroundResource(0) } } - socUpdateHandler.postDelayed(socUpdater!!, 1000) + socUpdateHandler.postDelayed(socRunnable!!, 1000) } - socUpdateHandler.post(socUpdater!!) + socRunnable = Runnable { socUpdater?.invoke() } + socUpdateHandler.post(socRunnable!!) } else { - if (socUpdater != null) { - socUpdateHandler.removeCallbacks(socUpdater!!) - } + socRunnable?.let { socUpdateHandler.removeCallbacks(it) } } } - @SuppressLint("SourceLockedOrientationActivity") private fun updateOrientation() { emulationActivity?.let { @@ -919,11 +1251,34 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) { Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height) - emulationState.newSurface(holder.surface) + if (!emulationStarted) { + emulationStarted = true + + // For intent launches, wait for driver initialization to complete + if (isCustomSettingsIntent || intentGame != null) { + if (!driverViewModel.isInteractionAllowed.value) { + Log.info("[EmulationFragment] Intent launch: waiting for driver initialization") + // Driver is still initializing, wait for it + lifecycleScope.launch { + driverViewModel.isInteractionAllowed.collect { allowed -> + if (allowed && holder.surface.isValid) { + emulationState.newSurface(holder.surface) + } + } + } + return + } + } + + emulationState.newSurface(holder.surface) + } else { + emulationState.newSurface(holder.surface) + } } override fun surfaceDestroyed(holder: SurfaceHolder) { emulationState.clearSurface() + emulationStarted = false } private fun showOverlayOptions() { @@ -1096,22 +1451,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { inputScaleSlider.apply { valueTo = 150F value = IntSetting.OVERLAY_SCALE.getInt().toFloat() - addOnChangeListener( - Slider.OnChangeListener { _, value, _ -> - inputScaleValue.text = "${value.toInt()}%" - setControlScale(value.toInt()) - } - ) + addOnChangeListener { _, value, _ -> + inputScaleValue.text = "${value.toInt()}%" + setControlScale(value.toInt()) + } } inputOpacitySlider.apply { valueTo = 100F value = IntSetting.OVERLAY_OPACITY.getInt().toFloat() - addOnChangeListener( - Slider.OnChangeListener { _, value, _ -> - inputOpacityValue.text = "${value.toInt()}%" - setControlOpacity(value.toInt()) - } - ) + addOnChangeListener { _, value, _ -> + inputOpacityValue.text = "${value.toInt()}%" + setControlOpacity(value.toInt()) + } } inputScaleValue.text = "${inputScaleSlider.value.toInt()}%" inputOpacityValue.text = "${inputOpacitySlider.value.toInt()}%" @@ -1147,7 +1498,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { val cutInsets: Insets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) var left = 0 var right = 0 - if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR) { + if (v.layoutDirection == View.LAYOUT_DIRECTION_LTR) { left = cutInsets.left } else { right = cutInsets.right @@ -1168,7 +1519,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { lateinit var emulationThread: Thread init { - // Starting state is stopped. state = State.STOPPED } @@ -1176,7 +1526,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { val isStopped: Boolean get() = state == State.STOPPED - // Getters for the current state @get:Synchronized val isPaused: Boolean get() = state == State.PAUSED @@ -1196,7 +1545,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } } - // State changing methods @Synchronized fun pause() { if (state != State.PAUSED) { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt index 5fed99e0b0..5763f3120f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt @@ -27,7 +27,6 @@ import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.transition.MaterialSharedAxis -import org.yuzu.yuzu_emu.BuildConfig import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R @@ -35,15 +34,14 @@ import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding import org.yuzu.yuzu_emu.features.DocumentProvider +import org.yuzu.yuzu_emu.features.fetcher.SpacingItemDecoration import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.HomeSetting import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.ui.main.MainActivity import org.yuzu.yuzu_emu.utils.FileUtil -import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.Log -import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins class HomeSettingsFragment : Fragment() { private var _binding: FragmentHomeSettingsBinding? = null @@ -112,7 +110,7 @@ class HomeSettingsFragment : Fragment() { .actionHomeSettingsFragmentToDriverManagerFragment(null) binding.root.findNavController().navigate(action) }, - {true}, + { true }, R.string.custom_driver_not_supported, R.string.custom_driver_not_supported_description, driverViewModel.selectedDriverTitle @@ -125,7 +123,7 @@ class HomeSettingsFragment : Fragment() { R.drawable.ic_two_users, { mainActivity.displayMultiplayerDialog() - }, + } ) ) add( @@ -254,6 +252,8 @@ class HomeSettingsFragment : Fragment() { viewLifecycleOwner, optionsList ) + val spacing = resources.getDimensionPixelSize(R.dimen.spacing_small) + addItemDecoration(SpacingItemDecoration(spacing)) } setInsets() @@ -403,7 +403,7 @@ class HomeSettingsFragment : Fragment() { val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) binding.scrollViewSettings.updatePadding( - top = barInsets.top, + top = barInsets.top ) binding.homeSettingsList.updatePadding( diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt index 33146c82ca..c02411d1bb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt @@ -134,10 +134,10 @@ class InstallableFragment : Fragment() { install = { mainActivity.getFirmware.launch(arrayOf("application/zip")) } ), Installable( - R.string.uninstall_firmware, - R.string.uninstall_firmware_description, - install = { mainActivity.uninstallFirmware() } - ), + R.string.uninstall_firmware, + R.string.uninstall_firmware_description, + install = { mainActivity.uninstallFirmware() } + ), Installable( R.string.install_prod_keys, R.string.install_prod_keys_description, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt index 52d9ef43d4..aa18aa2482 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - package org.yuzu.yuzu_emu.fragments import android.os.Bundle diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt index 61797f75f5..b7c75c127f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt @@ -78,7 +78,6 @@ class SetupFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { mainActivity = requireActivity() as MainActivity - requireActivity().onBackPressedDispatcher.addCallback( viewLifecycleOwner, object : OnBackPressedCallback(true) { @@ -129,7 +128,7 @@ class SetupFragment : Fragment() { 0, { if (NotificationManagerCompat.from(requireContext()) - .areNotificationsEnabled() + .areNotificationsEnabled() ) { StepState.COMPLETE } else { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/MidScreenSwipeRefreshLayout.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/MidScreenSwipeRefreshLayout.kt index 649bea9d54..35d027567e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/MidScreenSwipeRefreshLayout.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/MidScreenSwipeRefreshLayout.kt @@ -22,7 +22,11 @@ class MidScreenSwipeRefreshLayout @JvmOverloads constructor( MotionEvent.ACTION_DOWN -> { startX = ev.x val width = width - val center_fraction = resources.getFraction(R.fraction.carousel_midscreenswipe_width_fraction, 1, 1).coerceIn(0f, 1f) + val center_fraction = resources.getFraction( + R.fraction.carousel_midscreenswipe_width_fraction, + 1, + 1 + ).coerceIn(0f, 1f) val leftBound = ((1 - center_fraction) / 2) * width val rightBound = leftBound + (width * center_fraction) allowRefresh = startX >= leftBound && startX <= rightBound @@ -30,4 +34,4 @@ class MidScreenSwipeRefreshLayout @JvmOverloads constructor( } return if (allowRefresh) super.onInterceptTouchEvent(ev) else false } -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt index 66f012d1af..72ce006a7e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt @@ -141,7 +141,7 @@ class GamesViewModel : ViewModel() { } } - fun addFolder(gameDir: GameDir, savedFromGameFragment: Boolean) = + fun addFolder(gameDir: GameDir, savedFromGameFragment: Boolean) = viewModelScope.launch { withContext(Dispatchers.IO) { NativeConfig.addGameDir(gameDir) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/network/NetDataValidators.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/network/NetDataValidators.kt index b3edf35d8e..c2ad475c95 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/network/NetDataValidators.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/network/NetDataValidators.kt @@ -27,7 +27,7 @@ object NetDataValidators { fun roomVisibility(s: String, context: Context): Boolean { if (s != context.getString(R.string.multiplayer_public_visibility)) { - return true; + return true } return token() @@ -53,4 +53,4 @@ object NetDataValidators { fun port(s: String): Boolean { return s.toIntOrNull() in 1..65535 } -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/network/NetPlayManager.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/network/NetPlayManager.kt index 478dea6bdd..1e8e9f97d0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/network/NetPlayManager.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/network/NetPlayManager.kt @@ -70,7 +70,6 @@ object NetPlayManager { val gameName: String ) - private var messageListener: ((Int, String) -> Unit)? = null private var adapterRefreshListener: ((Int, String) -> Unit)? = null @@ -199,7 +198,6 @@ object NetPlayManager { } } - Handler(Looper.getMainLooper()).post { if (!isChatOpen) { // TODO(alekpop, crueter): Improve this, potentially a drawer at the top? @@ -207,7 +205,6 @@ object NetPlayManager { } } - messageListener?.invoke(type, msg) adapterRefreshListener?.invoke(type, msg) } @@ -218,19 +215,29 @@ object NetPlayManager { 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.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.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.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.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_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) @@ -247,7 +254,9 @@ object NetPlayManager { msg ) - NetPlayStatus.ADDRESS_UNBANNED -> context.getString(R.string.multiplayer_address_unbanned) + NetPlayStatus.ADDRESS_UNBANNED -> context.getString( + R.string.multiplayer_address_unbanned + ) NetPlayStatus.CHAT_MESSAGE -> msg else -> "" } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt index 43b9085f50..db1f808017 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt @@ -7,20 +7,13 @@ import android.content.Context import android.content.Intent import android.content.res.Configuration import android.os.Bundle -import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.ViewTreeObserver import android.view.inputmethod.InputMethodManager -import android.widget.ImageButton import android.widget.PopupMenu -import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.toArgb -import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding @@ -111,7 +104,7 @@ class GamesFragment : Fragment() { } gameAdapter = GameAdapter( - requireActivity() as AppCompatActivity, + requireActivity() as AppCompatActivity ) applyGridGamesBinding() @@ -238,7 +231,9 @@ class GamesFragment : Fragment() { override fun onResume() { super.onResume() if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) { - (binding.gridGames as? CarouselRecyclerView)?.restoreScrollState(gamesViewModel.lastScrollPosition) + (binding.gridGames as? CarouselRecyclerView)?.restoreScrollState( + gamesViewModel.lastScrollPosition + ) } } @@ -389,7 +384,9 @@ class GamesFragment : Fragment() { val searchTerm = binding.searchText.text.toString().lowercase(Locale.getDefault()) if (searchTerm.isEmpty()) { - ((binding.gridGames as? RecyclerView)?.adapter as? GameAdapter)?.submitList(filteredList) + ((binding.gridGames as? RecyclerView)?.adapter as? GameAdapter)?.submitList( + filteredList + ) gamesViewModel.setFilteredGames(filteredList) return } @@ -464,7 +461,9 @@ class GamesFragment : Fragment() { // Always set margin as original + insets mlpHeader.leftMargin = (originalHeaderLeftMargin ?: 0) + leftInset mlpHeader.rightMargin = (originalHeaderRightMargin ?: 0) + rightInset - mlpHeader.topMargin = (originalHeaderTopMargin ?: 0) + topInset + resources.getDimensionPixelSize(R.dimen.spacing_med) + mlpHeader.topMargin = (originalHeaderTopMargin ?: 0) + topInset + resources.getDimensionPixelSize( + R.dimen.spacing_med + ) binding.header.layoutParams = mlpHeader binding.noticeText.updatePadding(bottom = spacingNavigation) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 6d9a2002f5..fffaa1e3ba 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -6,8 +6,6 @@ package org.yuzu.yuzu_emu.ui.main import android.content.Intent import android.net.Uri import android.os.Bundle -import android.os.ParcelFileDescriptor -import android.provider.OpenableColumns import android.view.View import android.view.ViewGroup.MarginLayoutParams import android.view.WindowManager @@ -49,7 +47,6 @@ import java.io.BufferedOutputStream import java.util.zip.ZipEntry import java.util.zip.ZipInputStream import androidx.core.content.edit -import androidx.core.net.toFile class MainActivity : AppCompatActivity(), ThemeProvider { private lateinit var binding: ActivityMainBinding @@ -69,7 +66,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider { private var checkedFirmware = false private val requestBluetoothPermissionsLauncher = - registerForActivityResult(androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions()) { permissions -> + registerForActivityResult( + androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions() + ) { permissions -> val granted = permissions.entries.all { it.value } if (granted) { // Permissions were granted. @@ -111,10 +110,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { binding = ActivityMainBinding.inflate(layoutInflater) - setContentView(binding.root) - checkAndRequestBluetoothPermissions() if (savedInstanceState != null) { @@ -151,16 +148,20 @@ class MainActivity : AppCompatActivity(), ThemeProvider { binding.statusBarShade.setBackgroundColor( ThemeHelper.getColorWithOpacity( MaterialColors.getColor( - binding.root, com.google.android.material.R.attr.colorSurface - ), ThemeHelper.SYSTEM_BAR_ALPHA + binding.root, + com.google.android.material.R.attr.colorSurface + ), + ThemeHelper.SYSTEM_BAR_ALPHA ) ) if (InsetsHelper.getSystemGestureType(applicationContext) != InsetsHelper.GESTURE_NAVIGATION) { binding.navigationBarShade.setBackgroundColor( ThemeHelper.getColorWithOpacity( MaterialColors.getColor( - binding.root, com.google.android.material.R.attr.colorSurface - ), ThemeHelper.SYSTEM_BAR_ALPHA + binding.root, + com.google.android.material.R.attr.colorSurface + ), + ThemeHelper.SYSTEM_BAR_ALPHA ) ) } @@ -171,7 +172,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider { homeViewModel.statusBarShadeVisible.collect(this) { showStatusBarShade(it) } homeViewModel.contentToInstall.collect( - this, resetState = { homeViewModel.setContentToInstall(null) }) { + this, + resetState = { homeViewModel.setContentToInstall(null) } + ) { if (it != null) { installContent(it) } @@ -181,7 +184,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } homeViewModel.checkFirmware.collect( - this, resetState = { homeViewModel.setCheckFirmware(false) }) { + this, + resetState = { homeViewModel.setCheckFirmware(false) } + ) { if (it) checkFirmware() } @@ -204,7 +209,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { PreferenceManager.getDefaultSharedPreferences(applicationContext).edit() { putBoolean(Settings.PREF_SHOULD_SHOW_PRE_ALPHA_WARNING, false) } - }).show(supportFragmentManager, MessageDialogFragment.TAG) + } + ).show(supportFragmentManager, MessageDialogFragment.TAG) } } @@ -225,7 +231,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { private fun checkFirmware() { val resultCode: Int = NativeLibrary.verifyFirmware() - if (resultCode == 0) return; + if (resultCode == 0) return val resultString: String = resources.getStringArray(R.array.verifyFirmwareResults)[resultCode] @@ -313,14 +319,17 @@ class MainActivity : AppCompatActivity(), ThemeProvider { fun processGamesDir(result: Uri, calledFromGameFragment: Boolean = false) { contentResolver.takePersistableUriPermission( - result, Intent.FLAG_GRANT_READ_URI_PERMISSION + result, + Intent.FLAG_GRANT_READ_URI_PERMISSION ) val uriString = result.toString() val folder = gamesViewModel.folders.value.firstOrNull { it.uriString == uriString } if (folder != null) { Toast.makeText( - applicationContext, R.string.folder_already_added, Toast.LENGTH_SHORT + applicationContext, + R.string.folder_already_added, + Toast.LENGTH_SHORT ).show() return } @@ -343,16 +352,19 @@ class MainActivity : AppCompatActivity(), ThemeProvider { fun processKey(result: Uri, extension: String = "keys") { contentResolver.takePersistableUriPermission( - result, Intent.FLAG_GRANT_READ_URI_PERMISSION + result, + Intent.FLAG_GRANT_READ_URI_PERMISSION ) - val resultCode: Int = NativeLibrary.installKeys(result.toString(), extension); + val resultCode: Int = NativeLibrary.installKeys(result.toString(), extension) if (resultCode == 0) { // TODO(crueter): It may be worth it to switch some of these Toasts to snackbars, // since most of it is foreground-only anyways. Toast.makeText( - applicationContext, R.string.keys_install_success, Toast.LENGTH_SHORT + applicationContext, + R.string.keys_install_success, + Toast.LENGTH_SHORT ).show() gamesViewModel.reloadGames(true) @@ -384,12 +396,15 @@ class MainActivity : AppCompatActivity(), ThemeProvider { val cacheFirmwareDir = File("${cacheDir.path}/registered/") ProgressDialogFragment.newInstance( - this, R.string.firmware_installing + this, + R.string.firmware_installing ) { progressCallback, _ -> var messageToShow: Any try { FileUtil.unzipToInternalStorage( - result.toString(), cacheFirmwareDir, progressCallback + result.toString(), + cacheFirmwareDir, + progressCallback ) val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1 val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2 @@ -423,7 +438,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { val firmwarePath = File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/") ProgressDialogFragment.newInstance( - this, R.string.firmware_uninstalling + this, + R.string.firmware_uninstalling ) { progressCallback, _ -> var messageToShow: Any try { @@ -459,12 +475,15 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } ProgressDialogFragment.newInstance( - this@MainActivity, R.string.verifying_content, false + this@MainActivity, + R.string.verifying_content, + false ) { _, _ -> var updatesMatchProgram = true for (document in documents) { val valid = NativeLibrary.doesUpdateMatchProgram( - addonViewModel.game!!.programId, document.toString() + addonViewModel.game!!.programId, + document.toString() ) if (!valid) { updatesMatchProgram = false @@ -480,14 +499,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider { titleId = R.string.content_install_notice, descriptionId = R.string.content_install_notice_description, positiveAction = { homeViewModel.setContentToInstall(documents) }, - negativeAction = {}) + negativeAction = {} + ) } }.show(supportFragmentManager, ProgressDialogFragment.TAG) } private fun installContent(documents: List<Uri>) { ProgressDialogFragment.newInstance( - this@MainActivity, R.string.installing_game_content + this@MainActivity, + R.string.installing_game_content ) { progressCallback, messageCallback -> var installSuccess = 0 var installOverwrite = 0 @@ -495,11 +516,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider { var error = 0 documents.forEach { messageCallback.invoke(FileUtil.getFilename(it)) - when (InstallResult.from( - NativeLibrary.installFileToNand( - it.toString(), progressCallback + when ( + InstallResult.from( + NativeLibrary.installFileToNand( + it.toString(), + progressCallback + ) ) - )) { + ) { InstallResult.Success -> { installSuccess += 1 } @@ -525,7 +549,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { if (installSuccess > 0) { installResult.append( getString( - R.string.install_game_content_success_install, installSuccess + R.string.install_game_content_success_install, + installSuccess ) ) installResult.append(separator) @@ -533,7 +558,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { if (installOverwrite > 0) { installResult.append( getString( - R.string.install_game_content_success_overwrite, installOverwrite + R.string.install_game_content_success_overwrite, + installOverwrite ) ) installResult.append(separator) @@ -543,7 +569,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { installResult.append(separator) installResult.append( getString( - R.string.install_game_content_failed_count, errorTotal + R.string.install_game_content_failed_count, + errorTotal ) ) installResult.append(separator) @@ -584,7 +611,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } ProgressDialogFragment.newInstance( - this, R.string.exporting_user_data, true + this, + R.string.exporting_user_data, + true ) { progressCallback, _ -> val zipResult = FileUtil.zipFromInternalStorage( File(DirectoryInitialization.userDirectory!!), @@ -608,7 +637,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } ProgressDialogFragment.newInstance( - this, R.string.importing_user_data + this, + R.string.importing_user_data ) { progressCallback, _ -> val checkStream = ZipInputStream(BufferedInputStream(contentResolver.openInputStream(result))) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/CustomSettingsHandler.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/CustomSettingsHandler.kt new file mode 100644 index 0000000000..508f9de463 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/CustomSettingsHandler.kt @@ -0,0 +1,314 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.utils + +import android.content.Context +import android.widget.Toast +import androidx.fragment.app.FragmentActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.model.DriverViewModel +import org.yuzu.yuzu_emu.model.Game +import java.io.File +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine +import android.net.Uri +import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile + +object CustomSettingsHandler { + const val CUSTOM_CONFIG_ACTION = "dev.eden.eden_emulator.LAUNCH_WITH_CUSTOM_CONFIG" + const val EXTRA_TITLE_ID = "title_id" + const val EXTRA_CUSTOM_SETTINGS = "custom_settings" + + /** + * Apply custom settings from a string instead of loading from file + * @param titleId The game title ID (16-digit hex string) + * @param customSettings The complete INI file content as string + * @param context Application context + * @return Game object created from title ID, or null if not found + */ + fun applyCustomSettings(titleId: String, customSettings: String, context: Context): Game? { + // For synchronous calls without driver checking + Log.info("[CustomSettingsHandler] Applying custom settings for title ID: $titleId") + // Find the game by title ID + val game = findGameByTitleId(titleId, context) + if (game == null) { + Log.error("[CustomSettingsHandler] Game not found for title ID: $titleId") + return null + } + + // Check if config already exists - this should be handled by the caller + val configFile = getConfigFile(game) + if (configFile.exists()) { + Log.warning("[CustomSettingsHandler] Config file already exists for game: ${game.title}") + } + + // Write the config file + if (!writeConfigFile(game, customSettings)) { + Log.error("[CustomSettingsHandler] Failed to write config file") + return null + } + + // Initialize per-game config + try { + val fileName = FileUtil.getFilename(Uri.parse(game.path)) + NativeConfig.initializePerGameConfig(game.programId, fileName) + Log.info("[CustomSettingsHandler] Successfully applied custom settings") + return game + } catch (e: Exception) { + Log.error("[CustomSettingsHandler] Failed to apply custom settings: ${e.message}") + return null + } + } + + /** + * Apply custom settings with automatic driver checking and installation + * @param titleId The game title ID (16-digit hex string) + * @param customSettings The complete INI file content as string + * @param context Application context + * @param activity Fragment activity for driver installation dialogs (optional) + * @param driverViewModel DriverViewModel for driver management (optional) + * @return Game object created from title ID, or null if not found + */ + suspend fun applyCustomSettingsWithDriverCheck( + titleId: String, + customSettings: String, + context: Context, + activity: FragmentActivity?, + driverViewModel: DriverViewModel? + ): Game? { + Log.info("[CustomSettingsHandler] Applying custom settings for title ID: $titleId") + // Find the game by title ID + val game = findGameByTitleId(titleId, context) + if (game == null) { + Log.error("[CustomSettingsHandler] Game not found for title ID: $titleId") + // This will be handled by the caller to show appropriate error message + return null + } + + // Check if config already exists + val configFile = getConfigFile(game) + if (configFile.exists() && activity != null) { + Log.info( + "[CustomSettingsHandler] Config file already exists, asking user for confirmation" + ) + Toast.makeText( + activity, + activity.getString(R.string.config_exists_prompt), + Toast.LENGTH_SHORT + ).show() + val shouldOverwrite = askUserToOverwriteConfig(activity, game.title) + if (!shouldOverwrite) { + Log.info("[CustomSettingsHandler] User chose not to overwrite existing config") + Toast.makeText( + activity, + activity.getString(R.string.overwrite_cancelled), + Toast.LENGTH_SHORT + ).show() + return null + } + } + + // Check for driver requirements if activity and driverViewModel are provided + if (activity != null && driverViewModel != null) { + val driverPath = extractDriverPath(customSettings) + if (driverPath != null) { + Log.info("[CustomSettingsHandler] Custom settings specify driver: $driverPath") + // Check if driver exists in the driver storage + val driverFile = File(driverPath) + if (!driverFile.exists()) { + Log.error("[CustomSettingsHandler] Required driver not found: $driverPath") + Toast.makeText( + activity, + activity.getString( + R.string.custom_settings_failed_message, + game.title, + activity.getString(R.string.driver_not_found, driverFile.name) + ), + Toast.LENGTH_LONG + ).show() + // Don't write config if driver is missing + return null + } + + // Verify it's a valid driver + val metadata = GpuDriverHelper.getMetadataFromZip(driverFile) + if (metadata.name == null) { + Log.error("[CustomSettingsHandler] Invalid driver file: $driverPath") + Toast.makeText( + activity, + activity.getString( + R.string.custom_settings_failed_message, + game.title, + activity.getString(R.string.invalid_driver_file, driverFile.name) + ), + Toast.LENGTH_LONG + ).show() + return null + } + + Log.info("[CustomSettingsHandler] Driver verified: ${metadata.name}") + } + } + + // Only write the config file after all checks pass + if (!writeConfigFile(game, customSettings)) { + Log.error("[CustomSettingsHandler] Failed to write config file") + activity?.let { + Toast.makeText( + it, + it.getString(R.string.config_write_failed), + Toast.LENGTH_SHORT + ).show() + } + return null + } + + // Initialize per-game config + try { + SettingsFile.loadCustomConfig(game) + Log.info("[CustomSettingsHandler] Successfully applied custom settings") + activity?.let { + Toast.makeText( + it, + it.getString(R.string.custom_settings_applied), + Toast.LENGTH_SHORT + ).show() + } + return game + } catch (e: Exception) { + Log.error("[CustomSettingsHandler] Failed to apply custom settings: ${e.message}") + activity?.let { + Toast.makeText( + it, + it.getString(R.string.config_apply_failed), + Toast.LENGTH_SHORT + ).show() + } + return null + } + } + + /** + * Find a game by its title ID in the user's game library + */ + fun findGameByTitleId(titleId: String, context: Context): Game? { + Log.info("[CustomSettingsHandler] Searching for game with title ID: $titleId") + // Convert hex title ID to decimal for comparison with programId + val programIdDecimal = try { + titleId.toLong(16).toString() + } catch (e: NumberFormatException) { + Log.error("[CustomSettingsHandler] Invalid title ID format: $titleId") + return null + } + + // Expected hex format with "0" prefix + val expectedHex = "0${titleId.uppercase()}" + // First check cached games for fast lookup + GameHelper.cachedGameList.find { game -> + game.programId == programIdDecimal || + game.programIdHex.equals(expectedHex, ignoreCase = true) + }?.let { foundGame -> + Log.info("[CustomSettingsHandler] Found game in cache: ${foundGame.title}") + return foundGame + } + // If not in cache, perform full game library scan + Log.info("[CustomSettingsHandler] Game not in cache, scanning full library...") + val allGames = GameHelper.getGames() + val foundGame = allGames.find { game -> + game.programId == programIdDecimal || + game.programIdHex.equals(expectedHex, ignoreCase = true) + } + if (foundGame != null) { + Log.info("[CustomSettingsHandler] Found game: ${foundGame.title} at ${foundGame.path}") + } else { + Log.warning("[CustomSettingsHandler] No game found for title ID: $titleId") + } + return foundGame + } + + /** + * Get the config file path for a game + */ + private fun getConfigFile(game: Game): File { + return SettingsFile.getCustomSettingsFile(game) + } + + /** + * Get the title ID config file path + */ + private fun getTitleIdConfigFile(titleId: String): File { + val configDir = File(DirectoryInitialization.userDirectory, "config/custom") + return File(configDir, "$titleId.ini") + } + + /** + * Write the config file with the custom settings + */ + private fun writeConfigFile(game: Game, customSettings: String): Boolean { + return try { + val configFile = getConfigFile(game) + val configDir = configFile.parentFile + if (configDir != null && !configDir.exists()) { + configDir.mkdirs() + } + + configFile.writeText(customSettings) + + Log.info("[CustomSettingsHandler] Wrote config file: ${configFile.absolutePath}") + true + } catch (e: Exception) { + Log.error("[CustomSettingsHandler] Failed to write config file: ${e.message}") + false + } + } + + /** + * Ask user if they want to overwrite existing configuration + */ + private suspend fun askUserToOverwriteConfig(activity: FragmentActivity, gameTitle: String): Boolean { + return suspendCoroutine { continuation -> + activity.runOnUiThread { + MaterialAlertDialogBuilder(activity) + .setTitle(activity.getString(R.string.config_already_exists_title)) + .setMessage( + activity.getString(R.string.config_already_exists_message, gameTitle) + ) + .setPositiveButton(activity.getString(R.string.overwrite)) { _, _ -> + continuation.resume(true) + } + .setNegativeButton(activity.getString(R.string.cancel)) { _, _ -> + continuation.resume(false) + } + .setCancelable(false) + .show() + } + } + } + + /** + * Extract driver path from custom settings INI content + */ + private fun extractDriverPath(customSettings: String): String? { + val lines = customSettings.lines() + var inGpuDriverSection = false + + for (line in lines) { + val trimmed = line.trim() + if (trimmed.startsWith("[") && trimmed.endsWith("]")) { + inGpuDriverSection = trimmed == "[GpuDriver]" + continue + } + + if (inGpuDriverSection && trimmed.startsWith("driver_path=")) { + return trimmed.substringAfter("driver_path=") + } + } + + return null + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt index feed8b3cf8..52ee7b01ea 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -197,7 +200,9 @@ object FileUtil { */ fun getFilename(uri: Uri): String { if (uri.scheme == "file") { - return uri.lastPathSegment?.takeIf { it.isNotEmpty() } ?: throw IOException("Invalid file URI: $uri") + return uri.lastPathSegment?.takeIf { it.isNotEmpty() } ?: throw IOException( + "Invalid file URI: $uri" + ) } val resolver = YuzuApplication.appContext.contentResolver diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PowerStateUpdater.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PowerStateUpdater.kt index 58d2d1e7ed..ec492569ce 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PowerStateUpdater.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PowerStateUpdater.kt @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later - package org.yuzu.yuzu_emu.utils import android.os.Handler @@ -17,7 +16,6 @@ object PowerStateUpdater { private var isStarted = false fun start() { - if (isStarted) { return } @@ -43,4 +41,4 @@ object PowerStateUpdater { } isStarted = false } -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PowerStateUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PowerStateUtils.kt index 86e3d9c785..48382fad5b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PowerStateUtils.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PowerStateUtils.kt @@ -13,7 +13,6 @@ object PowerStateUtils { @JvmStatic fun getBatteryInfo(context: Context?): IntArray { - if (context == null) { return intArrayOf(0, 0, 0) // Percentage, IsCharging, HasBattery } @@ -42,4 +41,4 @@ object PowerStateUtils { return results } -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt index a035628588..3e138c0244 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt @@ -23,10 +23,12 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings object ThemeHelper { const val SYSTEM_BAR_ALPHA = 0.9f + // Listener that detects if the theme keys are being changed from the setting menu and recreates the activity private var listener: SharedPreferences.OnSharedPreferenceChangeListener? = null - private val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) - + private val preferences = PreferenceManager.getDefaultSharedPreferences( + YuzuApplication.appContext + ) fun setTheme(activity: AppCompatActivity) { setThemeMode(activity) @@ -52,6 +54,7 @@ object ThemeHelper { private fun getSelectedStaticThemeColor(): Int { val themeIndex = preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0) val themes = arrayOf( + R.style.Theme_Eden_Main, R.style.Theme_Yuzu_Main_Violet, R.style.Theme_Yuzu_Main_Blue, R.style.Theme_Yuzu_Main_Cyan, @@ -120,7 +123,11 @@ object ThemeHelper { fun ThemeChangeListener(activity: AppCompatActivity) { listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> - val relevantKeys = listOf(Settings.PREF_STATIC_THEME_COLOR, Settings.PREF_THEME_MODE, Settings.PREF_BLACK_BACKGROUNDS) + val relevantKeys = listOf( + Settings.PREF_STATIC_THEME_COLOR, + Settings.PREF_THEME_MODE, + Settings.PREF_BLACK_BACKGROUNDS + ) if (key in relevantKeys) { activity.recreate() } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/CarouselRecyclerView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/CarouselRecyclerView.kt index ae40fcb498..8a66ebf11f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/CarouselRecyclerView.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/CarouselRecyclerView.kt @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + package org.yuzu.yuzu_emu.ui import android.content.Context @@ -53,7 +56,7 @@ class CarouselRecyclerView @JvmOverloads constructor( var flingMultiplier: Float = 1f - public var pendingScrollAfterReload: Boolean = false + var pendingScrollAfterReload: Boolean = false var useCustomDrawingOrder: Boolean = false set(value) { @@ -76,7 +79,11 @@ class CarouselRecyclerView @JvmOverloads constructor( private fun getLayoutManagerCenter(layoutManager: RecyclerView.LayoutManager): Int { return if (layoutManager is LinearLayoutManager) { - calculateCenter(layoutManager.width, layoutManager.paddingStart, layoutManager.paddingEnd) + calculateCenter( + layoutManager.width, + layoutManager.paddingStart, + layoutManager.paddingEnd + ) } else { width / 2 } @@ -121,13 +128,13 @@ class CarouselRecyclerView @JvmOverloads constructor( fun shapingFunction(x: Float, option: Int = 0): Float { return when (option) { - 0 -> 1f //Off - 1 -> 1f - x //linear descending - 2 -> (1f - x) * (1f - x) //Ease out - 3 -> if (x < 0.05f) 1f else (1f-x) * 0.8f - 4 -> kotlin.math.cos(x * Math.PI).toFloat() //Cosine - 5 -> kotlin.math.cos( (1.5f * x).coerceIn(0f, 1f) * Math.PI).toFloat() //Cosine 1.5x trimmed - else -> 1f //Default to Off + 0 -> 1f // Off + 1 -> 1f - x // linear descending + 2 -> (1f - x) * (1f - x) // Ease out + 3 -> if (x < 0.05f) 1f else (1f - x) * 0.8f + 4 -> kotlin.math.cos(x * Math.PI).toFloat() // Cosine + 5 -> kotlin.math.cos((1.5f * x).coerceIn(0f, 1f) * Math.PI).toFloat() // Cosine 1.5x trimmed + else -> 1f // Default to Off } } @@ -143,20 +150,36 @@ class CarouselRecyclerView @JvmOverloads constructor( val center = getRecyclerViewCenter() val distance = abs(getChildDistanceToCenter(child)) val internalBorderScale = resources.getFraction(R.fraction.carousel_bordercards_scale, 1, 1) - val borderScale = preferences.getFloat(CAROUSEL_BORDERCARDS_SCALE, internalBorderScale).coerceIn(0f, 1f) + val borderScale = preferences.getFloat(CAROUSEL_BORDERCARDS_SCALE, internalBorderScale).coerceIn( + 0f, + 1f + ) val shapeInput = (distance / center).coerceIn(0f, 1f) val internalShapeSetting = resources.getInteger(R.integer.carousel_cards_scaling_shape) - val scalingShapeSetting = preferences.getInt(CAROUSEL_CARDS_SCALING_SHAPE, internalShapeSetting) + val scalingShapeSetting = preferences.getInt( + CAROUSEL_CARDS_SCALING_SHAPE, + internalShapeSetting + ) val shapedScaling = shapingFunction(shapeInput, scalingShapeSetting) val scale = (borderScale + (1f - borderScale) * shapedScaling).coerceIn(0f, 1f) val maxDistance = width / 2f val alphaInput = (distance / maxDistance).coerceIn(0f, 1f) - val internalBordersAlpha = resources.getFraction(R.fraction.carousel_bordercards_alpha, 1, 1) - val borderAlpha = preferences.getFloat(CAROUSEL_BORDERCARDS_ALPHA, internalBordersAlpha).coerceIn(0f, 1f) + val internalBordersAlpha = resources.getFraction( + R.fraction.carousel_bordercards_alpha, + 1, + 1 + ) + val borderAlpha = preferences.getFloat(CAROUSEL_BORDERCARDS_ALPHA, internalBordersAlpha).coerceIn( + 0f, + 1f + ) val internalAlphaShapeSetting = resources.getInteger(R.integer.carousel_cards_alpha_shape) - val alphaShapeSetting = preferences.getInt(CAROUSEL_CARDS_ALPHA_SHAPE, internalAlphaShapeSetting) + val alphaShapeSetting = preferences.getInt( + CAROUSEL_CARDS_ALPHA_SHAPE, + internalAlphaShapeSetting + ) val shapedAlpha = shapingFunction(alphaInput, alphaShapeSetting) val alpha = (borderAlpha + (1f - borderAlpha) * shapedAlpha).coerceIn(0f, 1f) @@ -185,16 +208,33 @@ class CarouselRecyclerView @JvmOverloads constructor( val insets = rootWindowInsets val bottomInset = insets?.getInsets(android.view.WindowInsets.Type.systemBars())?.bottom ?: 0 val internalFactor = resources.getFraction(R.fraction.carousel_card_size_factor, 1, 1) - val userFactor = preferences.getFloat(CAROUSEL_CARD_SIZE_FACTOR, internalFactor).coerceIn(0f, 1f) + val userFactor = preferences.getFloat(CAROUSEL_CARD_SIZE_FACTOR, internalFactor).coerceIn( + 0f, + 1f + ) val cardSize = (userFactor * (height - bottomInset)).toInt() gameAdapter?.setCardSize(cardSize) - val internalOverlapFactor = resources.getFraction(R.fraction.carousel_overlap_factor, 1, 1) - overlapFactor = preferences.getFloat(CAROUSEL_OVERLAP_FACTOR, internalOverlapFactor).coerceIn(0f, 1f) + val internalOverlapFactor = resources.getFraction( + R.fraction.carousel_overlap_factor, + 1, + 1 + ) + overlapFactor = preferences.getFloat(CAROUSEL_OVERLAP_FACTOR, internalOverlapFactor).coerceIn( + 0f, + 1f + ) overlapPx = (cardSize * overlapFactor).toInt() - val internalFlingMultiplier = resources.getFraction(R.fraction.carousel_fling_multiplier, 1, 1) - flingMultiplier = preferences.getFloat(CAROUSEL_FLING_MULTIPLIER, internalFlingMultiplier).coerceIn(1f, 5f) + val internalFlingMultiplier = resources.getFraction( + R.fraction.carousel_fling_multiplier, + 1, + 1 + ) + flingMultiplier = preferences.getFloat( + CAROUSEL_FLING_MULTIPLIER, + internalFlingMultiplier + ).coerceIn(1f, 5f) gameAdapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { override fun onChanged() { @@ -290,20 +330,28 @@ class CarouselRecyclerView @JvmOverloads constructor( View.FOCUS_LEFT -> { if (position > 0) { val now = System.currentTimeMillis() - val repeatDetected = (now - lastFocusSearchTime) < resources.getInteger(R.integer.carousel_focus_search_repeat_threshold_ms) + val repeatDetected = (now - lastFocusSearchTime) < resources.getInteger( + R.integer.carousel_focus_search_repeat_threshold_ms + ) lastFocusSearchTime = now - if (!repeatDetected) { //ensures the first run + if (!repeatDetected) { // ensures the first run val offset = focused.width - overlapPx smoothScrollBy(-offset, 0) } - findViewHolderForAdapterPosition(position - 1)?.itemView ?: super.focusSearch(focused, direction) + findViewHolderForAdapterPosition(position - 1)?.itemView ?: super.focusSearch( + focused, + direction + ) } else { focused } } View.FOCUS_RIGHT -> { if (position < itemCount - 1) { - findViewHolderForAdapterPosition(position + 1)?.itemView ?: super.focusSearch(focused, direction) + findViewHolderForAdapterPosition(position + 1)?.itemView ?: super.focusSearch( + focused, + direction + ) } else { focused } @@ -341,7 +389,10 @@ class CarouselRecyclerView @JvmOverloads constructor( inner class OverlappingDecoration(private val overlap: Int) : ItemDecoration() { override fun getItemOffsets( - outRect: Rect, view: View, parent: RecyclerView, state: State + outRect: Rect, + view: View, + parent: RecyclerView, + state: State ) { val position = parent.getChildAdapterPosition(view) if (position > 0) { @@ -378,12 +429,17 @@ class CarouselRecyclerView @JvmOverloads constructor( return layoutManager.findViewByPosition(getClosestChildPosition()) } - //NEEDED: fixes ghost movement when snapping, but breaks inertial scrolling + // NEEDED: fixes ghost movement when snapping, but breaks inertial scrolling override fun calculateDistanceToFinalSnap( layoutManager: RecyclerView.LayoutManager, targetView: View ): IntArray? { - if (layoutManager !is LinearLayoutManager) return super.calculateDistanceToFinalSnap(layoutManager, targetView) + if (layoutManager !is LinearLayoutManager) { + return super.calculateDistanceToFinalSnap( + layoutManager, + targetView + ) + } val out = IntArray(2) out[0] = getChildDistanceToCenter(targetView).toInt() out[1] = 0 @@ -399,11 +455,14 @@ class CarouselRecyclerView @JvmOverloads constructor( if (layoutManager !is LinearLayoutManager) return RecyclerView.NO_POSITION val closestPosition = this@CarouselRecyclerView.getClosestChildPosition() val internalMaxFling = resources.getInteger(R.integer.carousel_max_fling_count) - val maxFling = preferences.getInt(CAROUSEL_MAX_FLING_COUNT, internalMaxFling).coerceIn(1, 10) + val maxFling = preferences.getInt(CAROUSEL_MAX_FLING_COUNT, internalMaxFling).coerceIn( + 1, + 10 + ) val rawFlingCount = if (velocityX == 0) 0 else velocityX / 2000 val flingCount = rawFlingCount.coerceIn(-maxFling, maxFling) - var targetPos = (closestPosition + flingCount).coerceIn(0, layoutManager.itemCount - 1) + val targetPos = (closestPosition + flingCount).coerceIn(0, layoutManager.itemCount - 1) return targetPos } } -}
\ No newline at end of file +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/GradientBorderCardView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/GradientBorderCardView.kt new file mode 100644 index 0000000000..7badadd119 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/GradientBorderCardView.kt @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.views + +import android.content.Context +import android.graphics.* +import android.util.AttributeSet +import com.google.android.material.card.MaterialCardView +import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.features.settings.model.Settings +import androidx.preference.PreferenceManager + +class GradientBorderCardView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : MaterialCardView(context, attrs, defStyleAttr) { + + private val borderPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.STROKE + strokeWidth = 6f + } + + private val borderPath = Path() + private val borderRect = RectF() + private var showGradientBorder = false + private var isEdenTheme = false + + init { + setWillNotDraw(false) + updateThemeState() + } + + private fun updateThemeState() { + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + val themeIndex = try { + prefs.getInt(Settings.PREF_STATIC_THEME_COLOR, 0) + } catch (e: Exception) { + 0 // Default to Eden theme if error + } + isEdenTheme = themeIndex == 0 + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + + // Update border style based on theme + if (isEdenTheme) { + // Gradient for Eden theme + borderPaint.shader = LinearGradient( + 0f, 0f, + w.toFloat(), h.toFloat(), + context.getColor(R.color.eden_border_gradient_start), + context.getColor(R.color.eden_border_gradient_end), + Shader.TileMode.CLAMP + ) + } else { + // Solid color for other themes + borderPaint.shader = null + val typedValue = android.util.TypedValue() + context.theme.resolveAttribute(com.google.android.material.R.attr.colorPrimary, typedValue, true) + borderPaint.color = typedValue.data + } + + // Update border rect with padding for stroke + val halfStroke = borderPaint.strokeWidth / 2 + borderRect.set( + halfStroke, + halfStroke, + w - halfStroke, + h - halfStroke + ) + + // Update path with rounded corners + borderPath.reset() + borderPath.addRoundRect( + borderRect, + radius, + radius, + Path.Direction.CW + ) + } + + override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) { + super.onFocusChanged(gainFocus, direction, previouslyFocusedRect) + showGradientBorder = gainFocus + invalidate() + } + + override fun setSelected(selected: Boolean) { + super.setSelected(selected) + showGradientBorder = selected + invalidate() + } + + override fun setPressed(pressed: Boolean) { + super.setPressed(pressed) + if (pressed) { + showGradientBorder = true + invalidate() + } + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (showGradientBorder && !isPressed) { + canvas.drawPath(borderPath, borderPaint) + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + updateThemeState() + requestLayout() + } +} diff --git a/src/android/app/src/main/res/drawable/eden_background_gradient.xml b/src/android/app/src/main/res/drawable/eden_background_gradient.xml new file mode 100644 index 0000000000..476e88bb32 --- /dev/null +++ b/src/android/app/src/main/res/drawable/eden_background_gradient.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape android:shape="rectangle"> + <solid android:color="@color/eden_background" /> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <gradient + android:angle="135" + android:centerColor="@color/eden_transparent" + android:centerX="0.5" + android:centerY="0.5" + android:endColor="@color/eden_primary_transparent" + android:gradientRadius="100%" + android:startColor="@color/eden_secondary_transparent" + android:type="radial" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/eden_button_primary_background.xml b/src/android/app/src/main/res/drawable/eden_button_primary_background.xml new file mode 100644 index 0000000000..ec22911d66 --- /dev/null +++ b/src/android/app/src/main/res/drawable/eden_button_primary_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true"> + <shape android:shape="rectangle"> + <gradient + android:angle="135" + android:startColor="@color/eden_primary_variant" + android:endColor="@color/eden_accent_purple" + android:type="linear" /> + <corners android:radius="12dp" /> + </shape> + </item> + <item> + <shape android:shape="rectangle"> + <gradient + android:angle="135" + android:startColor="@color/eden_primary" + android:endColor="@color/eden_primary_variant" + android:type="linear" /> + <corners android:radius="12dp" /> + </shape> + </item> +</selector>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/eden_card_background.xml b/src/android/app/src/main/res/drawable/eden_card_background.xml new file mode 100644 index 0000000000..a944c19fed --- /dev/null +++ b/src/android/app/src/main/res/drawable/eden_card_background.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + + <solid android:color="@color/eden_card_background" /> + + <corners android:radius="16dp" /> + + <stroke + android:width="1dp" + android:color="@color/eden_border" /> + +</shape> diff --git a/src/android/app/src/main/res/drawable/eden_card_elevated_background.xml b/src/android/app/src/main/res/drawable/eden_card_elevated_background.xml new file mode 100644 index 0000000000..04ccf3172c --- /dev/null +++ b/src/android/app/src/main/res/drawable/eden_card_elevated_background.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/eden_card_background_elevated" /> + <corners android:radius="16dp" /> + <stroke + android:width="1dp" + android:color="@color/eden_border_light" /> +</shape>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/eden_card_elevated_selector.xml b/src/android/app/src/main/res/drawable/eden_card_elevated_selector.xml new file mode 100644 index 0000000000..9c7144c100 --- /dev/null +++ b/src/android/app/src/main/res/drawable/eden_card_elevated_selector.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Pressed state with gradient border --> + <item android:state_pressed="true" android:drawable="@drawable/eden_gradient_border" /> + <!-- Selected state with gradient border --> + <item android:state_selected="true" android:drawable="@drawable/eden_gradient_border" /> + <!-- Focused state with gradient border --> + <item android:state_focused="true" android:drawable="@drawable/eden_gradient_border" /> + <!-- Default state with elevated background --> + <item android:drawable="@drawable/eden_card_elevated_background" /> +</selector>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/eden_dialog_background.xml b/src/android/app/src/main/res/drawable/eden_dialog_background.xml new file mode 100644 index 0000000000..d06b85d406 --- /dev/null +++ b/src/android/app/src/main/res/drawable/eden_dialog_background.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape android:shape="rectangle"> + <gradient + android:angle="45" + android:startColor="@color/eden_border_gradient_start" + android:endColor="@color/eden_border_gradient_end" + android:type="linear" /> + <corners android:radius="24dp" /> + </shape> + </item> + <item + android:bottom="1dp" + android:left="1dp" + android:right="1dp" + android:top="1dp"> + <shape android:shape="rectangle"> + <solid android:color="@color/eden_card_background" /> + <corners android:radius="23dp" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/eden_gradient_border.xml b/src/android/app/src/main/res/drawable/eden_gradient_border.xml new file mode 100644 index 0000000000..d17b57d7ae --- /dev/null +++ b/src/android/app/src/main/res/drawable/eden_gradient_border.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape android:shape="rectangle"> + <gradient + android:angle="45" + android:startColor="@color/eden_border_gradient_start" + android:endColor="@color/eden_border_gradient_end" + android:type="linear" /> + <corners android:radius="16dp" /> + </shape> + </item> + <item + android:bottom="2dp" + android:left="2dp" + android:right="2dp" + android:top="2dp"> + <shape android:shape="rectangle"> + <solid android:color="@color/eden_card_background" /> + <corners android:radius="14dp" /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/eden_list_item_selector.xml b/src/android/app/src/main/res/drawable/eden_list_item_selector.xml new file mode 100644 index 0000000000..2689c6d41e --- /dev/null +++ b/src/android/app/src/main/res/drawable/eden_list_item_selector.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Pressed state with gradient highlight --> + <item android:state_pressed="true"> + <layer-list> + <item> + <shape android:shape="rectangle"> + <gradient + android:angle="45" + android:startColor="@color/eden_border_gradient_start" + android:endColor="@color/eden_border_gradient_end" + android:type="linear" /> + <corners android:radius="12dp" /> + </shape> + </item> + <item + android:bottom="1dp" + android:left="1dp" + android:right="1dp" + android:top="1dp"> + <shape android:shape="rectangle"> + <solid android:color="@color/eden_card_background" /> + <corners android:radius="11dp" /> + </shape> + </item> + </layer-list> + </item> + <!-- Selected/focused state --> + <item android:state_selected="true"> + <layer-list> + <item> + <shape android:shape="rectangle"> + <gradient + android:angle="45" + android:startColor="@color/eden_border_gradient_start" + android:endColor="@color/eden_border_gradient_end" + android:type="linear" /> + <corners android:radius="12dp" /> + </shape> + </item> + <item + android:bottom="1dp" + android:left="1dp" + android:right="1dp" + android:top="1dp"> + <shape android:shape="rectangle"> + <solid android:color="@color/eden_card_background" /> + <corners android:radius="11dp" /> + </shape> + </item> + </layer-list> + </item> + <!-- Default state --> + <item> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent" /> + </shape> + </item> +</selector>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/popup_menu_background.xml b/src/android/app/src/main/res/drawable/popup_menu_background.xml new file mode 100644 index 0000000000..f792c97a23 --- /dev/null +++ b/src/android/app/src/main/res/drawable/popup_menu_background.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?attr/colorSurface" /> + <corners android:radius="8dp" /> + <stroke + android:width="1dp" + android:color="?attr/colorOutline" /> +</shape>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/theme_card_background.xml b/src/android/app/src/main/res/drawable/theme_card_background.xml new file mode 100644 index 0000000000..1d369c6519 --- /dev/null +++ b/src/android/app/src/main/res/drawable/theme_card_background.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + + <solid android:color="?attr/colorSurface" /> + + <corners android:radius="16dp" /> + + <stroke + android:width="1dp" + android:color="?attr/colorOutline" /> + +</shape>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/theme_dialog_background.xml b/src/android/app/src/main/res/drawable/theme_dialog_background.xml new file mode 100644 index 0000000000..9d456afb60 --- /dev/null +++ b/src/android/app/src/main/res/drawable/theme_dialog_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?attr/colorSurface" /> + <corners android:radius="24dp" /> +</shape>
\ No newline at end of file diff --git a/src/android/app/src/main/res/drawable/theme_list_item_selector.xml b/src/android/app/src/main/res/drawable/theme_list_item_selector.xml new file mode 100644 index 0000000000..ab6fb2f213 --- /dev/null +++ b/src/android/app/src/main/res/drawable/theme_list_item_selector.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Pressed state --> + <item android:state_pressed="true"> + <shape android:shape="rectangle"> + <solid android:color="?attr/colorSurfaceVariant" /> + <corners android:radius="12dp" /> + </shape> + </item> + + <!-- Selected/focused state --> + <item android:state_selected="true"> + <shape android:shape="rectangle"> + <solid android:color="?attr/colorSurfaceVariant" /> + <corners android:radius="12dp" /> + </shape> + </item> + + <!-- Default state --> + <item> + <shape android:shape="rectangle"> + <solid android:color="@android:color/transparent" /> + </shape> + </item> +</selector> diff --git a/src/android/app/src/main/res/layout-land/card_game_carousel.xml b/src/android/app/src/main/res/layout-land/card_game_carousel.xml index fcc9397a13..4d8e5fd148 100644 --- a/src/android/app/src/main/res/layout-land/card_game_carousel.xml +++ b/src/android/app/src/main/res/layout-land/card_game_carousel.xml @@ -1,27 +1,30 @@ -<com.google.android.material.card.MaterialCardView +<org.yuzu.yuzu_emu.views.GradientBorderCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/card_game_carousel" android:layout_width="wrap_content" android:layout_height="match_parent" - app:cardCornerRadius="8dp" - app:cardElevation="4dp" + app:cardCornerRadius="16dp" + app:cardElevation="0dp" + app:cardPreventCornerOverlap="true" + android:clipChildren="true" android:layout_margin="0dp" - app:strokeColor="@android:color/transparent" - app:strokeWidth="0dp" - android:alpha="0"> + app:cardBackgroundColor="@color/eden_card_background" + app:strokeWidth="1dp" + app:strokeColor="@color/eden_border"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="4dp"> - <ImageView + <com.google.android.material.imageview.ShapeableImageView android:id="@+id/image_game_screen" android:layout_width="0dp" android:layout_height="0dp" android:scaleType="centerCrop" android:contentDescription="@string/game_image_desc" + app:shapeAppearanceOverlay="@style/ShapeAppearance.Eden.CarouselImage" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -43,4 +46,4 @@ android:text="Game Title" /> </androidx.constraintlayout.widget.ConstraintLayout> -</com.google.android.material.card.MaterialCardView> +</org.yuzu.yuzu_emu.views.GradientBorderCardView> diff --git a/src/android/app/src/main/res/layout-land/fragment_games.xml b/src/android/app/src/main/res/layout-land/fragment_games.xml index 14e9d5358c..9bd60c6f89 100644 --- a/src/android/app/src/main/res/layout-land/fragment_games.xml +++ b/src/android/app/src/main/res/layout-land/fragment_games.xml @@ -4,7 +4,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:clipChildren="false" > @@ -44,7 +43,10 @@ style="?attr/materialCardViewFilledStyle" android:layout_width="match_parent" android:layout_height="48dp" - app:cardCornerRadius="21dp" + app:cardCornerRadius="24dp" + app:cardBackgroundColor="?attr/colorSurfaceVariant" + app:strokeColor="?attr/colorOutline" + app:strokeWidth="1dp" > <LinearLayout @@ -100,6 +102,9 @@ android:layout_width="42dp" android:layout_height="42dp" app:cardCornerRadius="21dp" + app:cardBackgroundColor="@color/eden_surface_variant" + app:strokeColor="@color/eden_border" + app:strokeWidth="1dp" > <ImageView @@ -123,6 +128,9 @@ android:layout_width="42dp" android:layout_height="42dp" app:cardCornerRadius="21dp" + app:cardBackgroundColor="@color/eden_surface_variant" + app:strokeColor="@color/eden_border" + app:strokeWidth="1dp" > <ImageView @@ -146,6 +154,9 @@ android:layout_width="42dp" android:layout_height="42dp" app:cardCornerRadius="21dp" + app:cardBackgroundColor="@color/eden_surface_variant" + app:strokeColor="@color/eden_border" + app:strokeWidth="1dp" > <ImageView @@ -210,9 +221,9 @@ app:icon="@drawable/ic_cartridge_outline" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - android:textColor="?attr/colorOnPrimaryContainer" - app:backgroundTint="?attr/colorPrimaryContainer" - app:iconTint="?attr/colorOnPrimaryContainer" + android:textColor="?attr/colorOnPrimary" + app:backgroundTint="?attr/colorPrimary" + app:iconTint="?attr/colorOnPrimary" /> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/src/android/app/src/main/res/layout-w600dp/activity_main.xml b/src/android/app/src/main/res/layout-w600dp/activity_main.xml index d4188e7c9d..99d24f3e65 100644 --- a/src/android/app/src/main/res/layout-w600dp/activity_main.xml +++ b/src/android/app/src/main/res/layout-w600dp/activity_main.xml @@ -6,7 +6,7 @@ android:id="@+id/coordinator_main" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface"> + android:background="@drawable/eden_background_gradient"> <androidx.fragment.app.FragmentContainerView android:id="@+id/fragment_container" diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml index a5eba6474a..efa27f982e 100644 --- a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml +++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml @@ -5,14 +5,16 @@ android:id="@+id/coordinator_about" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface"> + > <com.google.android.material.appbar.AppBarLayout android:id="@+id/appbar_about" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" - android:touchscreenBlocksFocus="false"> + android:touchscreenBlocksFocus="false" + android:background="@android:color/transparent" + app:elevation="0dp"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_about" @@ -37,193 +39,206 @@ android:id="@+id/content_about" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="horizontal"> + android:orientation="horizontal" + android:padding="24dp"> <ImageView android:id="@+id/image_logo" android:layout_width="200dp" android:layout_height="200dp" - android:layout_gravity="center_horizontal" - android:padding="20dp" + android:layout_gravity="center_vertical" + android:layout_marginEnd="32dp" android:src="@drawable/ic_yuzu_title" /> <LinearLayout - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_weight="1" android:orientation="vertical"> - <LinearLayout + <com.google.android.material.card.MaterialCardView android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:paddingHorizontal="16dp" - android:paddingVertical="16dp"> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.TitleMedium" + app:cardCornerRadius="16dp" + app:cardBackgroundColor="?attr/colorSurface" + app:strokeColor="?attr/colorOutline" + app:strokeWidth="1dp" + app:cardElevation="0dp"> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:text="@string/about" - android:textAlignment="viewStart" /> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.BodyMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="6dp" - android:text="@string/about_app_description" - android:textAlignment="viewStart" /> - - </LinearLayout> - - <com.google.android.material.divider.MaterialDivider - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> - - <LinearLayout + android:orientation="vertical" + android:paddingHorizontal="24dp" + android:paddingVertical="20dp"> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.TitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/about" + android:textAlignment="viewStart" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.BodyMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:text="@string/about_app_description" + android:textAlignment="viewStart" /> + + </LinearLayout> + </com.google.android.material.card.MaterialCardView> + + <com.google.android.material.card.MaterialCardView android:id="@+id/button_contributors" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?attr/selectableItemBackground" - android:orientation="vertical" - android:paddingHorizontal="16dp" - android:paddingVertical="16dp"> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.TitleMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:text="@string/contributors" - android:textAlignment="viewStart" /> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.BodyMedium" + android:layout_marginTop="12dp" + android:clickable="true" + android:focusable="true" + app:cardCornerRadius="16dp" + app:cardBackgroundColor="?attr/colorSurface" + app:strokeColor="?attr/colorOutline" + app:strokeWidth="1dp" + app:cardElevation="0dp"> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="6dp" - android:text="@string/contributors_description" - android:textAlignment="viewStart" /> - - </LinearLayout> - - <com.google.android.material.divider.MaterialDivider - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> - - <LinearLayout + android:orientation="vertical" + android:paddingHorizontal="24dp" + android:paddingVertical="20dp"> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.TitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/contributors" + android:textAlignment="viewStart" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.BodyMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:text="@string/contributors_description" + android:textAlignment="viewStart" /> + + </LinearLayout> + </com.google.android.material.card.MaterialCardView> + + <com.google.android.material.card.MaterialCardView android:id="@+id/button_licenses" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?attr/selectableItemBackground" - android:orientation="vertical" - android:paddingHorizontal="16dp" - android:paddingVertical="16dp"> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.TitleMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:text="@string/licenses" - android:textAlignment="viewStart" /> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.BodyMedium" + android:layout_marginTop="12dp" + android:clickable="true" + android:focusable="true" + app:cardCornerRadius="16dp" + app:cardBackgroundColor="?attr/colorSurface" + app:strokeColor="?attr/colorOutline" + app:strokeWidth="1dp" + app:cardElevation="0dp"> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="6dp" - android:text="@string/licenses_description" - android:textAlignment="viewStart" /> - - </LinearLayout> - - <com.google.android.material.divider.MaterialDivider - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> - - <LinearLayout + android:orientation="vertical" + android:paddingHorizontal="24dp" + android:paddingVertical="20dp"> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.TitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/licenses" + android:textAlignment="viewStart" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.BodyMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:text="@string/licenses_description" + android:textAlignment="viewStart" /> + + </LinearLayout> + </com.google.android.material.card.MaterialCardView> + + <com.google.android.material.card.MaterialCardView android:id="@+id/button_version_name" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?attr/selectableItemBackground" - android:orientation="vertical" - android:paddingHorizontal="16dp" - android:paddingVertical="16dp"> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.TitleMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:text="@string/build" - android:textAlignment="viewStart" /> - - <com.google.android.material.textview.MaterialTextView - android:id="@+id/text_version_name" - style="@style/TextAppearance.Material3.BodyMedium" + android:layout_marginTop="12dp" + android:clickable="true" + android:focusable="true" + app:cardCornerRadius="16dp" + app:cardBackgroundColor="?attr/colorSurface" + app:strokeColor="?attr/colorOutline" + app:strokeWidth="1dp" + app:cardElevation="0dp"> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="6dp" - android:textAlignment="viewStart" - tools:text="abc123" /> - - </LinearLayout> - - <com.google.android.material.divider.MaterialDivider - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> + android:orientation="vertical" + android:paddingHorizontal="24dp" + android:paddingVertical="20dp"> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.TitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/build" + android:textAlignment="viewStart" /> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/text_version_name" + style="@style/TextAppearance.Material3.BodyMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textAlignment="viewStart" + tools:text="abc123" /> + + </LinearLayout> + </com.google.android.material.card.MaterialCardView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="40dp" - android:layout_marginTop="12dp" - android:layout_marginBottom="16dp" - android:gravity="center_horizontal" + android:layout_marginTop="24dp" + android:gravity="start" android:orientation="horizontal"> - <Button + <com.google.android.material.button.MaterialButton android:id="@+id/button_discord" - style="?attr/materialIconButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" + style="@style/EdenButton.Secondary" + android:layout_width="56dp" + android:layout_height="56dp" + android:layout_marginEnd="12dp" app:icon="@drawable/ic_discord" - app:iconGravity="textEnd" + app:iconGravity="textStart" app:iconSize="24dp" - app:iconTint="?attr/colorOnSurface" /> + app:iconPadding="0dp" /> - <Button + <com.google.android.material.button.MaterialButton android:id="@+id/button_website" - style="?attr/materialIconButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" + style="@style/EdenButton.Secondary" + android:layout_width="56dp" + android:layout_height="56dp" + android:layout_marginEnd="12dp" app:icon="@drawable/ic_website" - app:iconGravity="textEnd" + app:iconGravity="textStart" app:iconSize="24dp" - app:iconTint="?attr/colorOnSurface" /> + app:iconPadding="0dp" /> - <Button + <com.google.android.material.button.MaterialButton android:id="@+id/button_github" - style="?attr/materialIconButtonStyle" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" + style="@style/EdenButton.Secondary" + android:layout_width="56dp" + android:layout_height="56dp" app:icon="@drawable/ic_github" - app:iconGravity="textEnd" + app:iconGravity="textStart" app:iconSize="24dp" - app:iconTint="?attr/colorOnSurface" /> + app:iconPadding="0dp" /> </LinearLayout> @@ -233,4 +248,4 @@ </androidx.core.widget.NestedScrollView> -</androidx.coordinatorlayout.widget.CoordinatorLayout> +</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_setup.xml b/src/android/app/src/main/res/layout-w600dp/fragment_setup.xml index 406df9eabd..72a8afc1d4 100644 --- a/src/android/app/src/main/res/layout-w600dp/fragment_setup.xml +++ b/src/android/app/src/main/res/layout-w600dp/fragment_setup.xml @@ -23,7 +23,7 @@ <com.google.android.material.button.MaterialButton android:id="@+id/button_next" - style="@style/Widget.Material3.Button.TextButton" + style="@style/EdenButton.Primary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/next" @@ -33,7 +33,7 @@ <com.google.android.material.button.MaterialButton android:id="@+id/button_back" - style="@style/Widget.Material3.Button.TextButton" + style="@style/EdenButton.Secondary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/back" diff --git a/src/android/app/src/main/res/layout-w600dp/page_setup.xml b/src/android/app/src/main/res/layout-w600dp/page_setup.xml index 9e0ab8ecb1..595abe01c7 100644 --- a/src/android/app/src/main/res/layout-w600dp/page_setup.xml +++ b/src/android/app/src/main/res/layout-w600dp/page_setup.xml @@ -78,6 +78,7 @@ <com.google.android.material.button.MaterialButton android:id="@+id/button_action" + style="@style/EdenButton.Primary" android:layout_width="wrap_content" android:layout_height="56dp" android:layout_marginTop="16dp" diff --git a/src/android/app/src/main/res/layout/activity_main.xml b/src/android/app/src/main/res/layout/activity_main.xml index 8adb35ee46..8ddb54c619 100644 --- a/src/android/app/src/main/res/layout/activity_main.xml +++ b/src/android/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,7 @@ android:id="@+id/coordinator_main" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface"> + android:background="?android:attr/colorBackground"> <androidx.fragment.app.FragmentContainerView android:id="@+id/fragment_container" diff --git a/src/android/app/src/main/res/layout/card_driver_option.xml b/src/android/app/src/main/res/layout/card_driver_option.xml index 09e26990b3..2a70a93b47 100644 --- a/src/android/app/src/main/res/layout/card_driver_option.xml +++ b/src/android/app/src/main/res/layout/card_driver_option.xml @@ -2,7 +2,7 @@ <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" - style="?attr/materialCardViewOutlinedStyle" + style="@style/EdenCard" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="16dp" diff --git a/src/android/app/src/main/res/layout/card_game_carousel.xml b/src/android/app/src/main/res/layout/card_game_carousel.xml index 43e2875306..424d6cadde 100644 --- a/src/android/app/src/main/res/layout/card_game_carousel.xml +++ b/src/android/app/src/main/res/layout/card_game_carousel.xml @@ -1,26 +1,30 @@ -<com.google.android.material.card.MaterialCardView +<org.yuzu.yuzu_emu.views.GradientBorderCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/card_game_carousel" + app:cardElevation="0dp" + app:cardBackgroundColor="@color/eden_card_background" + app:strokeWidth="1dp" + app:strokeColor="@color/eden_border" android:layout_width="wrap_content" android:layout_height="match_parent" - app:cardCornerRadius="8dp" - app:cardElevation="4dp" - android:layout_margin="4dp" - app:strokeColor="@android:color/transparent" - app:strokeWidth="0dp"> + app:cardCornerRadius="16dp" + app:cardPreventCornerOverlap="true" + android:clipChildren="true" + android:layout_margin="4dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="8dp"> - <ImageView + <com.google.android.material.imageview.ShapeableImageView android:id="@+id/image_game_screen" android:layout_width="0dp" android:layout_height="0dp" android:scaleType="centerCrop" android:contentDescription="@string/game_image_desc" + app:shapeAppearanceOverlay="@style/ShapeAppearance.Eden.CarouselImage" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -29,12 +33,14 @@ <com.google.android.material.textview.MaterialTextView android:id="@+id/text_game_title" - style="@style/TextAppearance.Material3.TitleMedium" + style="@style/SynthwaveText.Body" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:requiresFadingEdge="horizontal" android:textAlignment="center" + android:textSize="14sp" + android:textStyle="bold" app:layout_constraintTop_toBottomOf="@+id/image_game_screen" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -42,4 +48,4 @@ android:text="Game Title" /> </androidx.constraintlayout.widget.ConstraintLayout> -</com.google.android.material.card.MaterialCardView> +</org.yuzu.yuzu_emu.views.GradientBorderCardView> diff --git a/src/android/app/src/main/res/layout/card_game_grid.xml b/src/android/app/src/main/res/layout/card_game_grid.xml index 31fed597f4..3e0bf6005c 100644 --- a/src/android/app/src/main/res/layout/card_game_grid.xml +++ b/src/android/app/src/main/res/layout/card_game_grid.xml @@ -3,22 +3,24 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:focusable="false" + android:focusableInTouchMode="false"> - <com.google.android.material.card.MaterialCardView + <org.yuzu.yuzu_emu.views.GradientBorderCardView android:id="@+id/card_game_grid" - style="?attr/materialCardViewElevatedStyle" + app:cardElevation="0dp" + app:cardBackgroundColor="@color/eden_card_background" + app:strokeWidth="1dp" + app:strokeColor="@color/eden_border" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:background="?attr/selectableItemBackground" android:clickable="true" android:clipToPadding="true" android:focusable="true" android:transitionName="card_game" - app:cardCornerRadius="4dp" - app:cardBackgroundColor="@android:color/transparent" - app:cardElevation="0dp"> + app:cardCornerRadius="16dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="wrap_content" @@ -33,17 +35,19 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium" + android:scaleType="centerCrop" tools:src="@drawable/default_icon" /> <com.google.android.material.textview.MaterialTextView android:id="@+id/text_game_title" - style="@style/TextAppearance.Material3.TitleMedium" + style="@style/SynthwaveText.Body" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:requiresFadingEdge="horizontal" android:textAlignment="center" android:textSize="14sp" + android:textStyle="bold" app:layout_constraintEnd_toEndOf="@+id/image_game_screen" app:layout_constraintStart_toStartOf="@+id/image_game_screen" app:layout_constraintTop_toBottomOf="@+id/image_game_screen" @@ -51,6 +55,6 @@ </androidx.constraintlayout.widget.ConstraintLayout> - </com.google.android.material.card.MaterialCardView> + </org.yuzu.yuzu_emu.views.GradientBorderCardView> </FrameLayout> diff --git a/src/android/app/src/main/res/layout/card_game_list.xml b/src/android/app/src/main/res/layout/card_game_list.xml index bbb1000628..c694c8fc85 100644 --- a/src/android/app/src/main/res/layout/card_game_list.xml +++ b/src/android/app/src/main/res/layout/card_game_list.xml @@ -1,18 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> -<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" +<org.yuzu.yuzu_emu.views.GradientBorderCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/card_game_list" - style="?attr/materialCardViewStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dp" - android:background="?attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:transitionName="card_game" - app:cardCornerRadius="14dp" - app:cardElevation="0dp"> + app:cardCornerRadius="16dp" + app:cardElevation="0dp" + app:cardBackgroundColor="@color/eden_card_background" + app:strokeWidth="0dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" @@ -31,7 +31,7 @@ <com.google.android.material.textview.MaterialTextView android:id="@+id/text_game_title" - style="@style/TextAppearance.Material3.TitleMedium" + style="@style/SynthwaveText.Body" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" @@ -39,6 +39,7 @@ android:textAlignment="viewStart" android:singleLine="true" android:textSize="14sp" + android:textStyle="bold" app:layout_constraintBottom_toTopOf="@+id/text_game_developer" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/image_game_screen" @@ -48,7 +49,7 @@ <com.google.android.material.textview.MaterialTextView android:id="@+id/text_game_developer" - style="@style/TextAppearance.Material3.BodySmall" + style="@style/SynthwaveText.Body" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" @@ -56,6 +57,7 @@ android:textAlignment="viewStart" android:singleLine="true" android:textSize="12sp" + android:alpha="0.7" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/image_game_screen" @@ -64,4 +66,4 @@ </androidx.constraintlayout.widget.ConstraintLayout> -</com.google.android.material.card.MaterialCardView> +</org.yuzu.yuzu_emu.views.GradientBorderCardView> diff --git a/src/android/app/src/main/res/layout/card_home_option.xml b/src/android/app/src/main/res/layout/card_home_option.xml index 8a19b6b202..00a957b7a5 100644 --- a/src/android/app/src/main/res/layout/card_home_option.xml +++ b/src/android/app/src/main/res/layout/card_home_option.xml @@ -2,16 +2,15 @@ <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" - style="?attr/materialCardViewStyle" + style="@style/EdenCard" android:id="@+id/option_card" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="24dp" - android:layout_marginHorizontal="12dp" - android:background="?attr/colorSurface" + android:layout_marginBottom="16dp" + android:layout_marginHorizontal="8dp" android:clickable="true" android:focusable="true" - app:cardElevation="0dp"> + app:cardCornerRadius="16dp"> <LinearLayout android:id="@+id/option_layout" @@ -25,7 +24,7 @@ android:layout_height="24dp" android:layout_marginStart="24dp" android:layout_gravity="center_vertical" - app:tint="?attr/colorOnSurface" /> + app:tint="?attr/colorPrimary" /> <LinearLayout android:layout_width="match_parent" @@ -35,7 +34,7 @@ android:orientation="vertical"> <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.BodyMedium" + style="@style/SynthwaveText.Body" android:id="@+id/option_title" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -45,17 +44,18 @@ tools:text="@string/install_prod_keys" /> <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.BodySmall" + style="@style/SynthwaveText.Body" android:id="@+id/option_description" android:layout_width="match_parent" android:layout_height="wrap_content" android:textAlignment="viewStart" android:textSize="14sp" android:layout_marginTop="5dp" + android:alpha="0.8" tools:text="@string/install_prod_keys_description" /> <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.LabelMedium" + style="@style/SynthwaveText.Secondary" android:id="@+id/option_detail" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/src/android/app/src/main/res/layout/card_installable.xml b/src/android/app/src/main/res/layout/card_installable.xml index ce2402d7a9..3952601f5d 100644 --- a/src/android/app/src/main/res/layout/card_installable.xml +++ b/src/android/app/src/main/res/layout/card_installable.xml @@ -2,7 +2,7 @@ <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" - style="?attr/materialCardViewOutlinedStyle" + style="@style/EdenCard" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="16dp" diff --git a/src/android/app/src/main/res/layout/dialog_bottom_sheet.xml b/src/android/app/src/main/res/layout/dialog_bottom_sheet.xml index 6dd10d97ba..0fc5d0c368 100644 --- a/src/android/app/src/main/res/layout/dialog_bottom_sheet.xml +++ b/src/android/app/src/main/res/layout/dialog_bottom_sheet.xml @@ -6,14 +6,15 @@ android:orientation="vertical" android:gravity="center" app:strokeWidth="0dp" - app:cardCornerRadius="24dp"> + app:cardCornerRadius="24dp" + android:background="@drawable/theme_dialog_background"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center" - android:background="?colorSurface"> + android:background="@android:color/transparent"> <View android:layout_width="128dp" diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml index 7f32e139a8..da3ccbf801 100644 --- a/src/android/app/src/main/res/layout/fragment_about.xml +++ b/src/android/app/src/main/res/layout/fragment_about.xml @@ -5,14 +5,16 @@ android:id="@+id/coordinator_about" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface"> + > <com.google.android.material.appbar.AppBarLayout android:id="@+id/appbar_about" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" - android:touchscreenBlocksFocus="false"> + android:touchscreenBlocksFocus="false" + android:background="@android:color/transparent" + app:elevation="0dp"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar_about" @@ -37,7 +39,8 @@ android:id="@+id/content_about" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> + android:orientation="vertical" + android:paddingBottom="24dp"> <ImageView android:id="@+id/image_logo" @@ -48,183 +51,191 @@ android:layout_gravity="center_horizontal" android:src="@drawable/ic_yuzu_title" /> - <com.google.android.material.divider.MaterialDivider + <com.google.android.material.card.MaterialCardView + style="@style/EdenCard" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingVertical="16dp" - android:paddingHorizontal="16dp" - android:orientation="vertical"> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.TitleMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:textAlignment="viewStart" - android:text="@string/about" /> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.BodyMedium" + android:layout_marginHorizontal="16dp" + android:layout_marginTop="16dp" + app:cardCornerRadius="16dp"> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="6dp" - android:textAlignment="viewStart" - android:text="@string/about_app_description" /> - - </LinearLayout> - - <com.google.android.material.divider.MaterialDivider - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> - - <LinearLayout + android:paddingVertical="20dp" + android:paddingHorizontal="20dp" + android:orientation="vertical"> + + <com.google.android.material.textview.MaterialTextView + style="@style/SynthwaveText.Header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAlignment="viewStart" + android:text="@string/about" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/SynthwaveText.Body" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textAlignment="viewStart" + android:text="@string/about_app_description" /> + + </LinearLayout> + </com.google.android.material.card.MaterialCardView> + + <com.google.android.material.card.MaterialCardView android:id="@+id/button_contributors" + style="@style/EdenCard" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingVertical="16dp" - android:paddingHorizontal="16dp" - android:background="?attr/selectableItemBackground" - android:orientation="vertical"> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.TitleMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:textAlignment="viewStart" - android:text="@string/contributors" /> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.BodyMedium" + android:layout_marginHorizontal="16dp" + android:layout_marginTop="12dp" + android:clickable="true" + android:focusable="true" + app:cardCornerRadius="16dp"> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="6dp" - android:textAlignment="viewStart" - android:text="@string/contributors_description" /> - - </LinearLayout> - - <com.google.android.material.divider.MaterialDivider - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> - - <LinearLayout + android:paddingVertical="20dp" + android:paddingHorizontal="20dp" + android:orientation="vertical"> + + <com.google.android.material.textview.MaterialTextView + style="@style/SynthwaveText.Header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAlignment="viewStart" + android:text="@string/contributors" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/SynthwaveText.Body" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textAlignment="viewStart" + android:text="@string/contributors_description" /> + + </LinearLayout> + </com.google.android.material.card.MaterialCardView> + + <com.google.android.material.card.MaterialCardView android:id="@+id/button_licenses" + style="@style/EdenCard" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingVertical="16dp" - android:paddingHorizontal="16dp" - android:background="?attr/selectableItemBackground" - android:orientation="vertical"> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.TitleMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:textAlignment="viewStart" - android:text="@string/licenses" /> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.BodyMedium" + android:layout_marginHorizontal="16dp" + android:layout_marginTop="12dp" + android:clickable="true" + android:focusable="true" + app:cardCornerRadius="16dp"> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="6dp" - android:textAlignment="viewStart" - android:text="@string/licenses_description" /> - - </LinearLayout> - - <com.google.android.material.divider.MaterialDivider - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> - - <LinearLayout + android:paddingVertical="20dp" + android:paddingHorizontal="20dp" + android:orientation="vertical"> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.TitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAlignment="viewStart" + android:text="@string/licenses" /> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.BodyMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textAlignment="viewStart" + android:text="@string/licenses_description" /> + + </LinearLayout> + </com.google.android.material.card.MaterialCardView> + + <com.google.android.material.card.MaterialCardView android:id="@+id/button_version_name" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingVertical="16dp" - android:paddingHorizontal="16dp" - android:background="?attr/selectableItemBackground" - android:orientation="vertical"> - - <com.google.android.material.textview.MaterialTextView - style="@style/TextAppearance.Material3.TitleMedium" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:textAlignment="viewStart" - android:text="@string/build" /> - - <com.google.android.material.textview.MaterialTextView - android:id="@+id/text_version_name" - style="@style/TextAppearance.Material3.BodyMedium" + android:layout_marginHorizontal="16dp" + android:layout_marginTop="12dp" + android:clickable="true" + android:focusable="true" + app:cardCornerRadius="16dp" + app:cardBackgroundColor="?attr/colorSurface" + app:strokeColor="?attr/colorOutline" + app:strokeWidth="1dp" + app:cardElevation="0dp"> + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginHorizontal="24dp" - android:layout_marginTop="6dp" - android:textAlignment="viewStart" - tools:text="abc123" /> - - </LinearLayout> - - <com.google.android.material.divider.MaterialDivider - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginHorizontal="20dp" /> + android:paddingVertical="20dp" + android:paddingHorizontal="20dp" + android:orientation="vertical"> + + <com.google.android.material.textview.MaterialTextView + style="@style/TextAppearance.Material3.TitleMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAlignment="viewStart" + android:text="@string/build" /> + + <com.google.android.material.textview.MaterialTextView + android:id="@+id/text_version_name" + style="@style/TextAppearance.Material3.BodyMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="6dp" + android:textAlignment="viewStart" + tools:text="abc123" /> + + </LinearLayout> + </com.google.android.material.card.MaterialCardView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_horizontal" - android:layout_marginTop="12dp" + android:layout_marginTop="24dp" android:layout_marginBottom="16dp" android:layout_marginHorizontal="40dp"> - <Button - style="?attr/materialIconButtonStyle" + <com.google.android.material.button.MaterialButton + style="@style/EdenButton.Secondary" android:id="@+id/button_discord" android:layout_width="0dp" - android:layout_height="wrap_content" + android:layout_height="56dp" android:layout_weight="1" + android:layout_marginEnd="8dp" app:icon="@drawable/ic_discord" - app:iconTint="?attr/colorOnSurface" app:iconSize="24dp" - app:iconGravity="textEnd" /> + app:iconGravity="textStart" + app:iconPadding="0dp" /> - <Button - style="?attr/materialIconButtonStyle" + <com.google.android.material.button.MaterialButton + style="@style/EdenButton.Secondary" android:id="@+id/button_website" android:layout_width="0dp" - android:layout_height="wrap_content" + android:layout_height="56dp" android:layout_weight="1" + android:layout_marginHorizontal="4dp" app:icon="@drawable/ic_website" - app:iconTint="?attr/colorOnSurface" app:iconSize="24dp" - app:iconGravity="textEnd" /> + app:iconGravity="textStart" + app:iconPadding="0dp" /> - <Button + <com.google.android.material.button.MaterialButton android:id="@+id/button_github" - style="?attr/materialIconButtonStyle" + style="@style/EdenButton.Secondary" android:layout_width="0dp" - android:layout_height="wrap_content" + android:layout_height="56dp" android:layout_weight="1" + android:layout_marginStart="8dp" app:icon="@drawable/ic_github" - app:iconTint="?attr/colorOnSurface" app:iconSize="24dp" - app:iconGravity="textEnd" /> + app:iconGravity="textStart" + app:iconPadding="0dp" /> </LinearLayout> @@ -232,4 +243,4 @@ </androidx.core.widget.NestedScrollView> -</androidx.coordinatorlayout.widget.CoordinatorLayout> +</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file diff --git a/src/android/app/src/main/res/layout/fragment_games.xml b/src/android/app/src/main/res/layout/fragment_games.xml index a3747b21da..c77a34ab67 100644 --- a/src/android/app/src/main/res/layout/fragment_games.xml +++ b/src/android/app/src/main/res/layout/fragment_games.xml @@ -4,7 +4,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" > <LinearLayout @@ -21,9 +20,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/app_name" - android:textAppearance="@style/TextAppearance.Material3.HeadlineLarge" + style="@style/SynthwaveText.Title" android:textSize="27sp" - android:textStyle="bold" /> <Space @@ -34,10 +32,11 @@ <com.google.android.material.card.MaterialCardView android:id="@+id/view_button" - style="?attr/materialCardViewFilledStyle" + style="@style/EdenCard" android:layout_width="42dp" android:layout_height="42dp" app:cardCornerRadius="21dp" + android:padding="8dp" > <ImageView @@ -45,7 +44,7 @@ android:layout_height="18dp" android:layout_gravity="center" android:src="@drawable/ic_eye" - app:tint="?attr/colorOnSurfaceVariant" + app:tint="?attr/colorSecondary" /> </com.google.android.material.card.MaterialCardView> @@ -57,10 +56,11 @@ <com.google.android.material.card.MaterialCardView android:id="@+id/filter_button" - style="?attr/materialCardViewFilledStyle" + style="@style/EdenCard" android:layout_width="42dp" android:layout_height="42dp" app:cardCornerRadius="21dp" + android:padding="8dp" > <ImageView @@ -80,10 +80,11 @@ <com.google.android.material.card.MaterialCardView android:id="@+id/settings_button" - style="?attr/materialCardViewFilledStyle" + style="@style/EdenCard" android:layout_width="42dp" android:layout_height="42dp" app:cardCornerRadius="21dp" + android:padding="8dp" > <ImageView @@ -91,7 +92,7 @@ android:layout_height="18dp" android:layout_gravity="center" android:src="@drawable/ic_settings" - app:tint="?attr/colorOnSurfaceVariant" + app:tint="?attr/colorTertiary" /> </com.google.android.material.card.MaterialCardView> @@ -111,10 +112,11 @@ <com.google.android.material.card.MaterialCardView android:id="@+id/search_background" - style="?attr/materialCardViewFilledStyle" + style="@style/EdenCard" android:layout_width="match_parent" android:layout_height="48dp" - app:cardCornerRadius="21dp" + app:cardCornerRadius="24dp" + android:padding="4dp" > <LinearLayout @@ -132,7 +134,7 @@ android:layout_gravity="center_vertical" android:layout_marginEnd="18dp" android:src="@drawable/ic_search" - app:tint="?attr/colorOnSurfaceVariant" + app:tint="?attr/colorSecondary" /> <EditText @@ -144,6 +146,9 @@ android:inputType="text" android:maxLines="1" android:imeOptions="flagNoFullscreen" + android:textColor="?attr/colorOnBackground" + android:textColorHint="?attr/colorOnSurfaceVariant" + android:fontFamily="monospace" /> </LinearLayout> @@ -186,6 +191,7 @@ android:gravity="center" android:padding="@dimen/spacing_large" android:text="@string/empty_gamelist" + android:textColor="?attr/colorOnBackground" android:visibility="gone" /> @@ -216,9 +222,9 @@ app:icon="@drawable/ic_cartridge_outline" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - android:textColor="?attr/colorOnPrimaryContainer" - app:backgroundTint="?attr/colorPrimaryContainer" - app:iconTint="?attr/colorOnPrimaryContainer" + android:textColor="?attr/colorOnPrimary" + app:backgroundTint="?attr/colorPrimary" + app:iconTint="?attr/colorOnPrimary" /> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/src/android/app/src/main/res/layout/fragment_home_settings.xml b/src/android/app/src/main/res/layout/fragment_home_settings.xml index c179f9341a..7f90f71967 100644 --- a/src/android/app/src/main/res/layout/fragment_home_settings.xml +++ b/src/android/app/src/main/res/layout/fragment_home_settings.xml @@ -4,7 +4,6 @@ android:id="@+id/scroll_view_settings" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:scrollbars="vertical" android:fadeScrollbars="false" android:clipToPadding="false" @@ -15,21 +14,21 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:background="?attr/colorSurface" - android:paddingHorizontal="8dp"> + android:paddingHorizontal="16dp"> <ImageView android:id="@+id/logo_image" - android:layout_width="96dp" - android:layout_height="96dp" - android:layout_marginVertical="32dp" + android:layout_width="120dp" + android:layout_height="120dp" + android:layout_marginVertical="48dp" android:layout_gravity="center_horizontal" android:src="@drawable/ic_yuzu_full" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/home_settings_list" android:layout_width="match_parent" - android:layout_height="match_parent" /> + android:layout_height="match_parent" + android:clipToPadding="false" /> </androidx.appcompat.widget.LinearLayoutCompat> diff --git a/src/android/app/src/main/res/layout/fragment_settings.xml b/src/android/app/src/main/res/layout/fragment_settings.xml index 66cfebe96d..ad4a5caa56 100644 --- a/src/android/app/src/main/res/layout/fragment_settings.xml +++ b/src/android/app/src/main/res/layout/fragment_settings.xml @@ -20,7 +20,7 @@ android:layout_width="match_parent" android:layout_height="?attr/collapsingToolbarLayoutMediumSize" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap" - app:contentScrim="?attr/colorOnSurfaceInverse" + app:contentScrim="?attr/colorSurface" app:scrimVisibleHeightTrigger="100dp"> <com.google.android.material.appbar.MaterialToolbar diff --git a/src/android/app/src/main/res/layout/fragment_setup.xml b/src/android/app/src/main/res/layout/fragment_setup.xml index 9499f64636..e953d52ea6 100644 --- a/src/android/app/src/main/res/layout/fragment_setup.xml +++ b/src/android/app/src/main/res/layout/fragment_setup.xml @@ -23,7 +23,7 @@ <com.google.android.material.button.MaterialButton android:id="@+id/button_next" - style="@style/Widget.Material3.Button.TextButton" + style="@style/EdenButton.Primary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/next" @@ -33,7 +33,7 @@ <com.google.android.material.button.MaterialButton android:id="@+id/button_back" - style="@style/Widget.Material3.Button.TextButton" + style="@style/EdenButton.Secondary" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/back" diff --git a/src/android/app/src/main/res/layout/list_item_setting.xml b/src/android/app/src/main/res/layout/list_item_setting.xml index e134314976..dba637a8f6 100644 --- a/src/android/app/src/main/res/layout/list_item_setting.xml +++ b/src/android/app/src/main/res/layout/list_item_setting.xml @@ -5,7 +5,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?android:attr/selectableItemBackground" + android:background="@drawable/theme_list_item_selector" android:clickable="true" android:focusable="true" android:gravity="center_vertical" diff --git a/src/android/app/src/main/res/layout/list_item_setting_input.xml b/src/android/app/src/main/res/layout/list_item_setting_input.xml index d67cbe2453..f3273bb555 100644 --- a/src/android/app/src/main/res/layout/list_item_setting_input.xml +++ b/src/android/app/src/main/res/layout/list_item_setting_input.xml @@ -5,7 +5,7 @@ android:id="@+id/setting_body" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?android:attr/selectableItemBackground" + android:background="@drawable/theme_list_item_selector" android:clickable="true" android:focusable="true" android:gravity="center_vertical" diff --git a/src/android/app/src/main/res/layout/list_item_setting_switch.xml b/src/android/app/src/main/res/layout/list_item_setting_switch.xml index e233370583..c01d00c50c 100644 --- a/src/android/app/src/main/res/layout/list_item_setting_switch.xml +++ b/src/android/app/src/main/res/layout/list_item_setting_switch.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?android:attr/selectableItemBackground" + android:background="@drawable/theme_list_item_selector" android:clickable="true" android:focusable="true" android:minHeight="72dp" diff --git a/src/android/app/src/main/res/layout/page_setup.xml b/src/android/app/src/main/res/layout/page_setup.xml index 535abcf029..a334fcce2f 100644 --- a/src/android/app/src/main/res/layout/page_setup.xml +++ b/src/android/app/src/main/res/layout/page_setup.xml @@ -26,12 +26,10 @@ <com.google.android.material.textview.MaterialTextView android:id="@+id/text_title" - style="@style/TextAppearance.Material3.DisplaySmall" + style="@style/SynthwaveText.Header" android:layout_width="0dp" android:layout_height="0dp" android:textAlignment="center" - android:textColor="?attr/colorOnSurface" - android:textStyle="bold" app:layout_constraintBottom_toTopOf="@+id/text_description" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -41,7 +39,7 @@ <com.google.android.material.textview.MaterialTextView android:id="@+id/text_description" - style="@style/TextAppearance.Material3.TitleLarge" + style="@style/SynthwaveText.Body" android:layout_width="0dp" android:layout_height="0dp" android:textAlignment="center" @@ -57,7 +55,7 @@ <com.google.android.material.textview.MaterialTextView android:id="@+id/text_confirmation" - style="@style/TextAppearance.Material3.TitleLarge" + style="@style/SynthwaveText.Accent" android:layout_width="wrap_content" android:layout_height="0dp" android:paddingHorizontal="16dp" @@ -66,7 +64,6 @@ android:textSize="30sp" android:visibility="invisible" android:text="@string/step_complete" - android:textStyle="bold" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -76,6 +73,7 @@ <com.google.android.material.button.MaterialButton android:id="@+id/button_action" + style="@style/EdenButton.Primary" android:layout_width="wrap_content" android:layout_height="56dp" android:layout_marginTop="16dp" diff --git a/src/android/app/src/main/res/values-ar/strings.xml b/src/android/app/src/main/res/values-ar/strings.xml index e7b2ae3bb0..d1a0fdccf2 100644 --- a/src/android/app/src/main/res/values-ar/strings.xml +++ b/src/android/app/src/main/res/values-ar/strings.xml @@ -155,8 +155,8 @@ <string name="shader_backend">خلفية Shader</string> <string name="shader_backend_description">اختيار طريقة ترجمة Shaders</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">محاكاة NVDEC</string> diff --git a/src/android/app/src/main/res/values-ckb/strings.xml b/src/android/app/src/main/res/values-ckb/strings.xml index 8598810726..6fd266e4c8 100644 --- a/src/android/app/src/main/res/values-ckb/strings.xml +++ b/src/android/app/src/main/res/values-ckb/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">شادەر باکند</string> <string name="shader_backend_description">هەڵبژاردنی ڕێگای پێکهێنانی شادەر</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">ئیمولەیشنی NVDEC</string> diff --git a/src/android/app/src/main/res/values-cs/strings.xml b/src/android/app/src/main/res/values-cs/strings.xml index 06ed7975b2..8313778751 100644 --- a/src/android/app/src/main/res/values-cs/strings.xml +++ b/src/android/app/src/main/res/values-cs/strings.xml @@ -152,8 +152,8 @@ <string name="shader_backend">Backend shaderů</string> <string name="shader_backend_description">Způsob kompilace shaderů</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Emulace NVDEC</string> diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 796839d6ff..26825fee51 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Shader-Backend</string> <string name="shader_backend_description">Methode zur Shader-Kompilierung</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">NVDEC-Emulation</string> diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 596130fbad..ff89d9dcc4 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Backend de shaders</string> <string name="shader_backend_description">Elegir cómo se compilan shaders</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Emulación NVDEC</string> diff --git a/src/android/app/src/main/res/values-fa/strings.xml b/src/android/app/src/main/res/values-fa/strings.xml index 07361fd577..618a846015 100644 --- a/src/android/app/src/main/res/values-fa/strings.xml +++ b/src/android/app/src/main/res/values-fa/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">بکاند شیدر</string> <string name="shader_backend_description">انتخاب روش کامپایل و ترجمه شیدرها</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">شبیهسازی NVDEC</string> diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index d1d0a7c4ca..9d3738d686 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Backend shader</string> <string name="shader_backend_description">Méthode de compilation</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Émulation NVDEC</string> diff --git a/src/android/app/src/main/res/values-he/strings.xml b/src/android/app/src/main/res/values-he/strings.xml index 29aa00c404..80032d6f02 100644 --- a/src/android/app/src/main/res/values-he/strings.xml +++ b/src/android/app/src/main/res/values-he/strings.xml @@ -154,8 +154,8 @@ <string name="shader_backend">מנוע שיידרים</string> <string name="shader_backend_description">בחר כיצד לקמפל שיידרים</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">אמולציית NVDEC</string> diff --git a/src/android/app/src/main/res/values-hu/strings.xml b/src/android/app/src/main/res/values-hu/strings.xml index bb78b1ff98..f846dbed10 100644 --- a/src/android/app/src/main/res/values-hu/strings.xml +++ b/src/android/app/src/main/res/values-hu/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Shader backend</string> <string name="shader_backend_description">Shaderek fordításának módja</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">NVDEC emuláció</string> diff --git a/src/android/app/src/main/res/values-id/strings.xml b/src/android/app/src/main/res/values-id/strings.xml index d060a0c7c0..d7f18f2c38 100644 --- a/src/android/app/src/main/res/values-id/strings.xml +++ b/src/android/app/src/main/res/values-id/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Backend Shader</string> <string name="shader_backend_description">Pilih cara shader dikompilasi dan diterjemahkan untuk GPU Anda.</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Emulasi NVDEC</string> diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index aea0a9b29f..2f23cc28f9 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Backend shader</string> <string name="shader_backend_description">Scegli come compilare gli shader</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Emulazione NVDEC</string> diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index 521a816917..cf92771f14 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">シェーダーバックエンド</string> <string name="shader_backend_description">シェーダーのコンパイル方法</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">NVDECエミュレーション</string> diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index bd0d929514..a39e16cc29 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">셰이더 백엔드</string> <string name="shader_backend_description">셰이더 컴파일 방식 선택</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">NVDEC 에뮬레이션</string> <string name="nvdec_emulation_description">비디오 디코딩 처리 방식 선택</string> diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index 1f962ea46c..f3e87bb6a0 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Shader-backend</string> <string name="shader_backend_description">Velg hvordan shadere kompileres</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">NVDEC-emulering</string> diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index f41721b761..dbf2ecd07e 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Backend shaderów</string> <string name="shader_backend_description">Wybierz metodę kompilacji shaderów.</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Emulacja NVDEC</string> diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index 05af74e6e0..8c2f135134 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Backend de shader</string> <string name="shader_backend_description">Define como shaders são compilados</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Emulação NVDEC</string> diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index 065b9e1765..0da3a61e20 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Backend de Shader</string> <string name="shader_backend_description">Método de compilação de shaders.</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Emulação NVDEC</string> diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index 6f15e9ee44..ec9b24418b 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Шейдерный бэкенд</string> <string name="shader_backend_description">Метод компиляции шейдеров</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Эмуляция NVDEC</string> diff --git a/src/android/app/src/main/res/values-sr/strings.xml b/src/android/app/src/main/res/values-sr/strings.xml index 274c78436d..1ebdcadd2e 100644 --- a/src/android/app/src/main/res/values-sr/strings.xml +++ b/src/android/app/src/main/res/values-sr/strings.xml @@ -118,8 +118,8 @@ <string name="shader_backend">Схадер Бацкенд</string> <string name="shader_backend_description">Изаберите како се сјеначици саставе и преведете за ваш ГПУ.</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">НВДЕЦ Емулација</string> diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index 579befd866..56a40422cd 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Система обробки шейдерів</string> <string name="shader_backend_description">Спосіб компіляції шейдерів</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Емуляція NVDEC</string> diff --git a/src/android/app/src/main/res/values-vi/strings.xml b/src/android/app/src/main/res/values-vi/strings.xml index 95a55ab325..bace0834d1 100644 --- a/src/android/app/src/main/res/values-vi/strings.xml +++ b/src/android/app/src/main/res/values-vi/strings.xml @@ -153,8 +153,8 @@ <string name="shader_backend">Backend Shader</string> <string name="shader_backend_description">Chọn cách biên dịch shader</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">Giả lập NVDEC</string> diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index fd8cb4219f..136e5f9bb1 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml @@ -152,8 +152,8 @@ <string name="shader_backend">着色器后端</string> <string name="shader_backend_description">选择着色器编译方式</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">NVDEC模拟</string> diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index 32c9053088..f04ca89fb6 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml @@ -156,8 +156,8 @@ <string name="shader_backend">著色器後端</string> <string name="shader_backend_description">選擇著色器的編譯與轉譯方式</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">NVDEC模擬</string> diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 855fd6e769..602003cf8a 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -389,6 +389,7 @@ </integer-array> <string-array name="staticThemeNames"> + <item>@string/eden_theme</item> <item>@string/violet</item> <item>@string/blue</item> <item>@string/cyan</item> @@ -409,6 +410,7 @@ <item>6</item> <item>7</item> <item>8</item> + <item>9</item> </integer-array> <string-array name="anisoEntries"> diff --git a/src/android/app/src/main/res/values/eden_colors.xml b/src/android/app/src/main/res/values/eden_colors.xml new file mode 100644 index 0000000000..fe29e13ef9 --- /dev/null +++ b/src/android/app/src/main/res/values/eden_colors.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <!-- Synthwave/Vaporwave Primary Colors --> + <color name="eden_primary">#FF0080</color> <!-- Neon magenta --> + <color name="eden_primary_variant">#E6006B</color> <!-- Darker magenta --> + <color name="eden_secondary">#00FFFF</color> <!-- Electric cyan --> + <color name="eden_secondary_variant">#00E6E6</color> <!-- Darker cyan --> + + <!-- Background Colors - Deep space black --> + <color name="eden_background">#000000</color> <!-- Pure black background --> + <color name="eden_surface">#0D0D0D</color> <!-- Card surface --> + <color name="eden_surface_variant">#1A1A1A</color> <!-- Elevated surface --> + + <!-- Text Colors - High contrast for readability --> + <color name="eden_on_background">#FFFFFF</color> <!-- Pure white text --> + <color name="eden_on_surface">#FFFFFF</color> <!-- Pure white text --> + <color name="eden_on_primary">#FFFFFF</color> <!-- White on neon --> + <color name="eden_on_secondary">#000000</color> <!-- Black on cyan --> + + <!-- Synthwave Accent Colors --> + <color name="eden_accent_pink">#FF0080</color> <!-- Neon magenta --> + <color name="eden_accent_purple">#9D00FF</color> <!-- Electric purple --> + <color name="eden_accent_blue">#0080FF</color> <!-- Electric blue --> + <color name="eden_accent_orange">#FF8000</color> <!-- Neon orange --> + + <!-- Synthwave Gradient Colors --> + <color name="eden_gradient_start">#FF0080</color> <!-- Neon magenta --> + <color name="eden_gradient_middle">#9D00FF</color> <!-- Electric purple --> + <color name="eden_gradient_end">#00FFFF</color> <!-- Electric cyan --> + + <!-- Neon Glow Effects --> + <color name="eden_glow_pink">#80FF0080</color> <!-- Magenta glow --> + <color name="eden_glow_cyan">#8000FFFF</color> <!-- Cyan glow --> + <color name="eden_glow_purple">#809D00FF</color> <!-- Purple glow --> + <color name="eden_glow_orange">#80FF8000</color> <!-- Orange glow --> + + <!-- Neon Border Colors --> + <color name="eden_border">#333333</color> <!-- Subtle border --> + <color name="eden_border_light">#555555</color> <!-- Lighter border --> + <color name="eden_border_gradient_start">#FF0080</color> <!-- Neon magenta --> + <color name="eden_border_gradient_end">#00FFFF</color> <!-- Electric cyan --> + + <!-- Retro Grid Pattern --> + <color name="eden_grid_line">#1A1A1A</color> <!-- Grid lines --> + <color name="eden_grid_line_accent">#FF0080</color> <!-- Neon grid lines --> + <color name="eden_grid_line_cyan">#00FFFF</color> <!-- Cyan grid lines --> + + <!-- Synthwave Status Colors --> + <color name="eden_error">#FF0040</color> <!-- Neon red --> + <color name="eden_success">#00FF80</color> <!-- Neon green --> + <color name="eden_warning">#FFFF00</color> <!-- Neon yellow --> + <color name="eden_info">#0080FF</color> <!-- Electric blue --> + + <!-- Overlay Colors --> + <color name="eden_overlay_dark">#CC000000</color> + <color name="eden_overlay_medium">#80000000</color> + <color name="eden_overlay_light">#33000000</color> + + <!-- Neon Button Colors --> + <color name="eden_button_primary_bg">#FF0080</color> <!-- Neon magenta --> + <color name="eden_button_secondary_bg">#00000000</color> <!-- Transparent --> + <color name="eden_button_secondary_border">#00FFFF</color> <!-- Electric cyan --> + + <!-- Synthwave Card Colors --> + <color name="eden_card_background">#0D0D0D</color> <!-- Almost black --> + <color name="eden_card_background_elevated">#1A1A1A</color> <!-- Elevated black --> + + <!-- Retro Navigation Colors --> + <color name="eden_nav_background">#000000</color> <!-- Pure black --> + <color name="eden_nav_selected">#FF0080</color> <!-- Neon magenta --> + <color name="eden_nav_unselected">#666666</color> <!-- Gray --> + + <!-- Transparent versions for gradients --> + <color name="eden_transparent">#00000000</color> + <color name="eden_primary_transparent">#00FF0080</color> + <color name="eden_secondary_transparent">#0000FFFF</color> + + <!-- Additional Synthwave Colors --> + <color name="eden_scan_line">#33FF0080</color> <!-- Scan line effect --> + <color name="eden_hologram">#1A00FFFF</color> <!-- Holographic effect --> + <color name="eden_neon_outline">#FFFF0080</color> <!-- Neon outline --> + +</resources>
\ No newline at end of file diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index b10e90757e..5d8276ab71 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -112,8 +112,8 @@ <string name="shader_backend">Shader Backend</string> <string name="shader_backend_description">Choose how shaders are compiled and translated for your GPU.</string> <string name="shader_backend_glsl">GLSL</string> - <string name="shader_backend_glasm">GLASM</string>string> - <string name="shader_backend_spirv">Spir-V</string>string> + <string name="shader_backend_glasm">GLASM</string> + <string name="shader_backend_spirv">Spir-V</string> <!-- NVDEC Emulation --> <string name="nvdec_emulation">NVDEC Emulation</string> @@ -230,7 +230,7 @@ <!-- Setup strings --> <string name="welcome">Welcome!</string> - <string name="welcome_description">Learn how to setup <b>eden</b> and jump into emulation.</string> + <string name="welcome_description">Learn how to setup <b>Eden</b> and jump into emulation.</string> <string name="get_started">Get started</string> <string name="keys">Keys</string> <string name="keys_description">Select your <b>prod.keys</b> file with the button below.</string> @@ -271,7 +271,7 @@ <string name="search_and_filter_games">Search and filter games</string> <string name="select_games_folder">Select games folder</string> <string name="manage_game_folders">Manage game folders</string> - <string name="select_games_folder_description">Allows eden to populate the games list</string> + <string name="select_games_folder_description">Allows Eden to populate the games list</string> <string name="add_games_warning">Skip selecting games folder?</string> <string name="add_games_warning_description">Games won\'t be displayed in the Games list if a folder isn\'t selected.</string> <string name="add_games_warning_help">https://yuzu-mirror.github.io/help/quickstart/#dumping-games</string> @@ -290,7 +290,7 @@ <string name="notifications_description">Grant the notification permission with the button below.</string> <string name="give_permission">Grant permission</string> <string name="notification_warning">Skip granting the notification permission?</string> - <string name="notification_warning_description">eden won\'t be able to notify you of important information.</string> + <string name="notification_warning_description">Eden won\'t be able to notify you of important information.</string> <string name="permission_denied">Permission denied</string> <string name="permission_denied_description">You denied this permission too many times and now you have to manually grant it in system settings.</string> <string name="about">About</string> @@ -314,11 +314,11 @@ <string name="search_recently_added">Recently added</string> <string name="search_retail">Retail</string> <string name="search_homebrew">Homebrew</string> - <string name="open_user_folder">Open eden folder</string> - <string name="open_user_folder_description">Manage eden\'s internal files</string> + <string name="open_user_folder">Open Eden folder</string> + <string name="open_user_folder_description">Manage Eden\'s internal files</string> <string name="theme_and_color_description">Modify the look of the app</string> <string name="no_file_manager">No file manager found</string> - <string name="notification_no_directory_link">Could not open eden directory</string> + <string name="notification_no_directory_link">Could not open Eden directory</string> <string name="notification_no_directory_link_description">Please locate the user folder with the file manager\'s side panel manually.</string> <string name="manage_save_data">Manage save data</string> <string name="manage_save_data_description">Save data found. Please select an option below.</string> @@ -340,7 +340,7 @@ <string name="firmware_installed_failure_description">Make sure the firmware nca files are at the root of the zip and try again.</string> <string name="firmware_uninstalled_failure">Firmware uninstallation failed</string> <string name="share_log">Share debug logs</string> - <string name="share_log_description">Share eden\'s log file to debug issues</string> + <string name="share_log_description">Share Eden\'s log file to debug issues</string> <string name="share_log_missing">No log file found</string> <string name="install_game_content">Install game content</string> <string name="install_game_content_description">Install game updates or DLC</string> @@ -356,7 +356,7 @@ <string name="install_game_content_help_link">https://yuzu-mirror.github.io/help/quickstart/#dumping-installed-updates</string> <string name="custom_driver_not_supported">Custom drivers not supported</string> <string name="custom_driver_not_supported_description">Custom driver loading isn\'t currently supported for this device.\nCheck this option again in the future to see if support was added!</string> - <string name="manage_yuzu_data">Manage eden data</string> + <string name="manage_yuzu_data">Manage Eden data</string> <string name="manage_yuzu_data_description">Import/export firmware, keys, user data, and more!</string> <string name="share_save_file">Share save file</string> <string name="export_save_failed">Failed to export save</string> @@ -424,16 +424,16 @@ <string name="copied_to_clipboard">Copied to clipboard</string> <string name="about_app_description">An open-source Switch emulator</string> <string name="contributors">Contributors</string> - <string name="contributors_description">Contributors who made eden for Android possible</string> + <string name="contributors_description">Contributors who made Eden for Android possible</string> <string name="contributors_link">https://git.eden-emu.dev/eden-emu/eden/activity/contributors</string> - <string name="licenses_description">Projects that make eden for Android possible</string> + <string name="licenses_description">Projects that make Eden for Android possible</string> <string name="build">Build</string> <string name="user_data">User data</string> <string name="user_data_description">Import/export all app data.\n\nWhen importing user data, all existing user data will be deleted!\n\nImporting data from Citron may cause issues. It\'s recommended to manually import all needed data.</string> <string name="exporting_user_data">Exporting user data…</string> <string name="importing_user_data">Importing user data…</string> <string name="import_user_data">Import user data</string> - <string name="invalid_yuzu_backup">Invalid eden backup</string> + <string name="invalid_yuzu_backup">Invalid Eden backup</string> <string name="user_data_export_success">User data exported successfully</string> <string name="user_data_import_success">User data imported successfully</string> <string name="user_data_export_cancelled">Export cancelled</string> @@ -770,6 +770,45 @@ <string name="loader_requires_firmware">Game Requires Firmware</string> <string name="loader_requires_firmware_description"><![CDATA[The game you are trying to launch requires firmware to boot or to get past the opening menu. Please <a href="https://yuzu-mirror.github.io/help/quickstart"> dump and install firmware</a>, or press "OK" to launch anyways.]]></string> + <!-- Intent Launch strings --> + <string name="searching_for_game">Searching for game...</string> + <string name="game_not_found_for_title_id">Game not found for Title ID: %1$s</string> + <string name="custom_settings_failed_title">Custom Settings Failed</string> + <string name="custom_settings_failed_message">Failed to apply custom settings for %1$s: %2$s</string> + <string name="launch_with_default_settings">Launch with Default Settings</string> + <string name="launch_cancelled">Launch cancelled</string> + <string name="custom_settings_failure_reasons">Unable to apply the requested settings. This may be due to missing GPU drivers or configuration issues.</string> + <string name="custom_settings_applied">Custom settings applied</string> + <string name="launching_game">Launching %1$s...</string> + <string name="failed_to_initialize_game">Failed to initialize game</string> + <string name="custom_intent_launch_message_with_settings">Would you like to launch %1$s with custom settings?</string> + <string name="custom_intent_launch_message">Would you like to launch %1$s?</string> + <string name="custom_intent_launch_title">Launch Game</string> + <string name="launch">Launch</string> + + <!-- Custom Config strings --> + <string name="config_write_failed">Failed to write configuration file</string> + <string name="config_apply_failed">Failed to apply configuration</string> + <string name="config_already_exists_title">Configuration Already Exists</string> + <string name="config_already_exists_message">Custom settings already exist for %1$s.\n\nWould you like to overwrite the existing configuration?\n\nThis action cannot be undone.</string> + <string name="config_exists_prompt">Checking for existing configuration...</string> + <string name="overwrite_cancelled">Overwrite cancelled</string> + <string name="checking_driver">Checking for custom driver: %1$s</string> + <string name="driver_unavailable">Custom driver not available for this device</string> + <string name="overwrite">Overwrite</string> + + <!-- Driver strings --> + <string name="missing_gpu_driver_title">GPU Driver Missing</string> + <string name="missing_gpu_driver_message">The selected custom driver \"%s\" is not installed. Would you like to download and install it now?</string> + <string name="downloading_driver">Downloading driver...</string> + <string name="driver_installed">Driver installed successfully</string> + <string name="driver_installation_failed_title">Driver Installation Failed</string> + <string name="driver_installation_failed_message">Failed to install the GPU driver: %s</string> + <string name="driver_not_available_title">Driver Not Available</string> + <string name="driver_not_available_message">The selected driver is not available for download.</string> + <string name="driver_not_found">Required driver not installed: %s</string> + <string name="invalid_driver_file">Invalid driver file: %s</string> + <!-- Emulation Menu --> <string name="emulation_exit">Exit emulation</string> <string name="emulation_done">Done</string> @@ -997,7 +1036,8 @@ <!-- Static Themes --> <string name="static_theme_color">Theme Color</string> - <string name="violet">Violet (Default)</string> + <string name="eden_theme">Eden (Default)</string> + <string name="violet">Violet</string> <string name="blue">Blue</string> <string name="cyan">Cyan</string> <string name="red">Red</string> diff --git a/src/android/app/src/main/res/values/styles.xml b/src/android/app/src/main/res/values/styles.xml index be49a1b348..9f487052c4 100644 --- a/src/android/app/src/main/res/values/styles.xml +++ b/src/android/app/src/main/res/values/styles.xml @@ -162,4 +162,131 @@ <item name="rippleColor">@color/yuzu_inversePrimary_pink</item> </style> + <!-- Eden theme styles --> + <style name="EdenSlider" parent="Widget.Material3.Slider"> + <item name="tickVisible">false</item> + <item name="labelBehavior">gone</item> + <item name="trackColorActive">?attr/colorPrimary</item> + <item name="trackColorInactive">?attr/colorOutline</item> + <item name="thumbColor">?attr/colorSecondary</item> + <item name="haloColor">?attr/colorSecondary</item> + </style> + + <style name="EdenMaterialDialog" parent="ThemeOverlay.Material3.MaterialAlertDialog"> + <item name="colorPrimary">@color/eden_primary</item> + <item name="colorSurface">@color/eden_card_background</item> + <item name="colorSurfaceContainerHigh">@color/eden_card_background</item> + <item name="colorOnSurface">@color/eden_on_surface</item> + <item name="colorOnSurfaceVariant">@color/eden_on_surface</item> + <item name="colorSecondary">@color/eden_secondary</item> + <item name="android:textColorPrimary">@color/eden_on_surface</item> + <item name="android:textColorSecondary">@color/eden_on_surface</item> + <item name="android:colorBackground">@color/eden_card_background</item> + <item name="buttonBarPositiveButtonStyle">@style/EdenButton.Dialog</item> + <item name="buttonBarNegativeButtonStyle">@style/EdenButton.Dialog</item> + <item name="buttonBarNeutralButtonStyle">@style/EdenButton.Dialog</item> + </style> + + <style name="EdenButton.Dialog" parent="Widget.Material3.Button.TextButton.Dialog"> + <item name="android:textColor">@color/eden_primary</item> + <item name="rippleColor">@color/eden_glow_pink</item> + </style> + <style name="EdenPopupMenu" parent="Widget.Material3.PopupMenu"> + <item name="android:popupBackground">@drawable/popup_menu_background</item> + </style> + <style name="YuzuPopupMenu" parent="Widget.Material3.PopupMenu"> + <item name="android:popupBackground">@drawable/popup_menu_background</item> + </style> + + <style name="EdenButton.Primary" parent="Widget.Material3.Button"> + <item name="android:textColor">@color/eden_on_primary</item> + <item name="android:textAllCaps">false</item> + <item name="android:textStyle">bold</item> + <item name="android:letterSpacing">0.05</item> + <item name="backgroundTint">@color/eden_primary</item> + </style> + + <style name="EdenButton.Secondary" parent="Widget.Material3.Button.OutlinedButton"> + <item name="strokeColor">@color/eden_secondary</item> + <item name="strokeWidth">2dp</item> + <item name="android:textColor">@color/eden_secondary</item> + <item name="android:textAllCaps">false</item> + <item name="cornerRadius">12dp</item> + <item name="android:textStyle">bold</item> + <item name="android:letterSpacing">0.05</item> + </style> + + <style name="EdenCard" parent=""> + <item name="android:background">@drawable/theme_card_background</item> + <item name="android:elevation">0dp</item> + <item name="android:focusable">true</item> + <item name="android:clickable">true</item> + </style> + <style name="EdenGameCard" parent="Widget.Material3.CardView.Elevated"> + <item name="cardElevation">0dp</item> + <item name="cardBackgroundColor">?attr/colorSurface</item> + <item name="strokeWidth">0dp</item> + <item name="android:focusable">true</item> + <item name="android:clickable">true</item> + <item name="android:stateListAnimator">@null</item> + </style> + + <style name="EdenCardElevated" parent=""> + <item name="android:background">@drawable/eden_card_elevated_selector</item> + <item name="android:elevation">0dp</item> + <item name="android:padding">16dp</item> + </style> + <!-- Synthwave Text Styles --> + <style name="SynthwaveText.Title" parent="TextAppearance.Material3.DisplayLarge"> + <item name="android:textColor">@color/eden_on_background</item> + <item name="android:textStyle">bold</item> + <item name="android:letterSpacing">0.1</item> + <item name="android:fontFamily">monospace</item> + <item name="android:shadowColor">@color/eden_glow_pink</item> + <item name="android:shadowDx">0</item> + <item name="android:shadowDy">0</item> + <item name="android:shadowRadius">8</item> + </style> + <style name="SynthwaveText.Header" parent="TextAppearance.Material3.DisplaySmall"> + <item name="android:textColor">@color/eden_primary</item> + <item name="android:textStyle">bold</item> + <item name="android:letterSpacing">0.05</item> + <item name="android:fontFamily">monospace</item> + <item name="android:shadowColor">@color/eden_glow_pink</item> + <item name="android:shadowDx">0</item> + <item name="android:shadowDy">0</item> + <item name="android:shadowRadius">6</item> + </style> + <style name="SynthwaveText.Body" parent="TextAppearance.Material3.BodyLarge"> + <item name="android:textColor">@color/eden_on_background</item> + <item name="android:fontFamily">monospace</item> + <item name="android:letterSpacing">0.02</item> + </style> + <style name="SynthwaveText.Secondary" parent="TextAppearance.Material3.BodyMedium"> + <item name="android:textColor">@color/eden_secondary</item> + <item name="android:fontFamily">monospace</item> + <item name="android:shadowColor">@color/eden_glow_cyan</item> + <item name="android:shadowDx">0</item> + <item name="android:shadowDy">0</item> + <item name="android:shadowRadius">4</item> + </style> + <style name="SynthwaveText.Accent" parent="TextAppearance.Material3.LabelLarge"> + <item name="android:textColor">@color/eden_accent_orange</item> + <item name="android:textStyle">bold</item> + <item name="android:fontFamily">monospace</item> + <item name="android:letterSpacing">0.1</item> + <item name="android:shadowColor">@color/eden_glow_orange</item> + <item name="android:shadowDx">0</item> + <item name="android:shadowDy">0</item> + <item name="android:shadowRadius">4</item> + </style> + <!-- Shape appearance for carousel images --> + <style name="ShapeAppearance.Eden.CarouselImage" parent=""> + <item name="cornerFamily">rounded</item> + <item name="cornerSizeTopLeft">8dp</item> + <item name="cornerSizeTopRight">8dp</item> + <item name="cornerSizeBottomLeft">0dp</item> + <item name="cornerSizeBottomRight">0dp</item> + </style> + </resources> diff --git a/src/android/app/src/main/res/values/themes.xml b/src/android/app/src/main/res/values/themes.xml index 20b789ec45..7f14c2205d 100644 --- a/src/android/app/src/main/res/values/themes.xml +++ b/src/android/app/src/main/res/values/themes.xml @@ -2,9 +2,9 @@ <resources> <style name="Theme.Yuzu.Splash.Main" parent="Theme.SplashScreen"> - <item name="windowSplashScreenBackground">@color/yuzu_surface_violet</item> + <item name="windowSplashScreenBackground">@color/eden_background</item> <item name="windowSplashScreenAnimatedIcon">@drawable/ic_yuzu</item> - <item name="postSplashScreenTheme">@style/Theme.Yuzu.Main.Violet</item> + <item name="postSplashScreenTheme">@style/Theme.Yuzu.Main</item> </style> <style name="Theme.Yuzu.Main" parent="Theme.Material3.DayNight.NoActionBar"> @@ -23,6 +23,58 @@ <item name="android:enforceStatusBarContrast">false</item> <item name="android:enforceNavigationBarContrast">false</item> + <!-- Popup menu theme --> + <item name="popupMenuStyle">@style/YuzuPopupMenu</item> + </style> + + <style name="Theme.Eden.Main" parent="Theme.Material3.DayNight.NoActionBar"> + <!-- Primary colors --> + <item name="colorPrimary">@color/eden_primary</item> + <item name="colorOnPrimary">@color/eden_on_primary</item> + <item name="colorPrimaryContainer">@color/eden_primary_variant</item> + <item name="colorOnPrimaryContainer">@color/eden_on_primary</item> + <!-- Secondary colors --> + <item name="colorSecondary">@color/eden_secondary</item> + <item name="colorOnSecondary">@color/eden_on_secondary</item> + <item name="colorSecondaryContainer">@color/eden_secondary_variant</item> + <item name="colorOnSecondaryContainer">@color/eden_on_secondary</item> + <!-- Tertiary colors --> + <item name="colorTertiary">@color/eden_accent_purple</item> + <item name="colorOnTertiary">@color/eden_on_primary</item> + <item name="colorTertiaryContainer">@color/eden_accent_blue</item> + <item name="colorOnTertiaryContainer">@color/eden_on_primary</item> + <!-- Background and surface --> + <item name="android:colorBackground">@color/eden_background</item> + <item name="colorOnBackground">@color/eden_on_background</item> + <item name="colorSurface">@color/eden_surface</item> + <item name="colorOnSurface">@color/eden_on_surface</item> + <item name="colorSurfaceVariant">@color/eden_surface_variant</item> + <item name="colorOnSurfaceVariant">@color/eden_on_surface</item> + <!-- Outline and borders --> + <item name="colorOutline">@color/eden_border</item> + <item name="colorOutlineVariant">@color/eden_border_light</item> + <!-- Error colors --> + <item name="colorError">@color/eden_error</item> + <item name="colorErrorContainer">@color/eden_error</item> + <item name="colorOnError">@color/eden_on_primary</item> + <item name="colorOnErrorContainer">@color/eden_on_primary</item> + <!-- System UI --> + <item name="android:statusBarColor">@android:color/transparent</item> + <item name="android:navigationBarColor">@android:color/transparent</item> + <item name="android:windowLightStatusBar">false</item> + <item name="android:windowLightNavigationBar">false</item> + <!-- Other theme attributes --> + <item name="android:shadowColor">@color/eden_overlay_dark</item> + <item name="sliderStyle">@style/EdenSlider</item> + <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> + <item name="android:enforceStatusBarContrast">false</item> + <item name="android:enforceNavigationBarContrast">false</item> + <!-- Material dialog theme --> + <item name="materialAlertDialogTheme">@style/EdenMaterialDialog</item> + <!-- Popup menu theme --> + <item name="popupMenuStyle">@style/EdenPopupMenu</item> + <item name="android:textColorPrimary">@color/eden_on_background</item> + <item name="android:itemTextAppearance">@style/TextAppearance.Material3.BodyLarge</item> </style> <style name="Theme.Yuzu.Main.Blue" parent="Theme.Yuzu.Main"> |
