forked from eden-emu/eden
[android]: (feat) emuready launch intent + redesign (#162)
feat: emuready intent support and slight redesign Co-authored-by: crueter <crueter@eden-emu.dev> Reviewed-on: eden-emu/eden#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>
This commit is contained in:
parent
3b72c29303
commit
f72783e017
106 changed files with 2264 additions and 697 deletions
|
@ -156,7 +156,6 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
version = "3.22.1"
|
version = "3.22.1"
|
||||||
|
|
|
@ -12,7 +12,7 @@ SPDX-FileCopyrightText: Eden Emulator Project
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
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.touchscreen" android:required="false" />
|
||||||
<uses-feature android:name="android.hardware.gamepad" android:required="false" />
|
<uses-feature android:name="android.hardware.gamepad" android:required="false" />
|
||||||
<uses-feature android:name="android.software.leanback" 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:banner="@drawable/tv_banner"
|
||||||
android:fullBackupContent="@xml/data_extraction_rules"
|
android:fullBackupContent="@xml/data_extraction_rules"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules_api_31"
|
android:dataExtractionRules="@xml/data_extraction_rules_api_31"
|
||||||
|
tools:targetApi="33"
|
||||||
android:enableOnBackInvokedCallback="true">
|
android:enableOnBackInvokedCallback="true">
|
||||||
|
|
||||||
<meta-data android:name="com.samsung.android.gamehub" android:value="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" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:mimeType="application/octet-stream" android:scheme="content"/>
|
<data android:mimeType="application/octet-stream" android:scheme="content"/>
|
||||||
</intent-filter>
|
</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" />
|
<meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu
|
package org.yuzu.yuzu_emu
|
||||||
|
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
|
@ -17,7 +16,6 @@ import android.widget.TextView
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import net.swiftzer.semver.SemVer
|
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
|
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.Patch
|
||||||
import org.yuzu.yuzu_emu.model.GameVerificationResult
|
import org.yuzu.yuzu_emu.model.GameVerificationResult
|
||||||
import org.yuzu.yuzu_emu.network.NetPlayManager
|
import org.yuzu.yuzu_emu.network.NetPlayManager
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class which contains methods that interact
|
* Class which contains methods that interact
|
||||||
|
@ -276,8 +273,7 @@ object NativeLibrary {
|
||||||
val emulationActivity = sEmulationActivity.get()
|
val emulationActivity = sEmulationActivity.get()
|
||||||
if (emulationActivity != null) {
|
if (emulationActivity != null) {
|
||||||
emulationActivity.addNetPlayMessages(type, message)
|
emulationActivity.addNetPlayMessages(type, message)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
NetPlayManager.addNetPlayMessage(type, message)
|
NetPlayManager.addNetPlayMessage(type, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.activities
|
package org.yuzu.yuzu_emu.activities
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
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.NfcReader
|
||||||
import org.yuzu.yuzu_emu.utils.ParamPackage
|
import org.yuzu.yuzu_emu.utils.ParamPackage
|
||||||
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
||||||
import org.yuzu.yuzu_emu.utils.PowerStateUtils
|
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@ -204,6 +202,12 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
setIntent(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)
|
nfcReader.onNewIntent(intent)
|
||||||
InputHandler.updateControllerData()
|
InputHandler.updateControllerData()
|
||||||
}
|
}
|
||||||
|
@ -421,7 +425,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||||
NetPlayManager.addNetPlayMessage(type, msg)
|
NetPlayManager.addNetPlayMessage(type, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private var pictureInPictureReceiver = object : BroadcastReceiver() {
|
private var pictureInPictureReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent) {
|
override fun onReceive(context: Context?, intent: Intent) {
|
||||||
if (intent.action == actionPlay) {
|
if (intent.action == actionPlay) {
|
||||||
|
|
|
@ -4,15 +4,10 @@
|
||||||
package org.yuzu.yuzu_emu.adapters
|
package org.yuzu.yuzu_emu.adapters
|
||||||
|
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.net.Uri
|
|
||||||
import android.text.Html
|
import android.text.Html
|
||||||
import android.text.method.LinkMovementMethod
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.pm.ShortcutInfoCompat
|
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.GameIconUtils
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
|
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
@ -103,9 +97,21 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
|
||||||
val binding = when (viewType) {
|
val binding = when (viewType) {
|
||||||
VIEW_TYPE_LIST -> CardGameListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
VIEW_TYPE_LIST -> CardGameListBinding.inflate(
|
||||||
VIEW_TYPE_GRID -> CardGameGridBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
LayoutInflater.from(parent.context),
|
||||||
VIEW_TYPE_CAROUSEL -> CardGameCarouselBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
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")
|
else -> throw IllegalArgumentException("Invalid view type")
|
||||||
}
|
}
|
||||||
return GameViewHolder(binding, viewType)
|
return GameViewHolder(binding, viewType)
|
||||||
|
@ -212,7 +218,10 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
||||||
.setIcon(GameIconUtils.getShortcutIcon(activity, game))
|
.setIcon(GameIconUtils.getShortcutIcon(activity, game))
|
||||||
.setIntent(game.launchIntent)
|
.setIntent(game.launchIntent)
|
||||||
.build()
|
.build()
|
||||||
ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
|
ShortcutManagerCompat.pushDynamicShortcut(
|
||||||
|
YuzuApplication.appContext,
|
||||||
|
shortcut
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// 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.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import org.yuzu.yuzu_emu.R
|
|
||||||
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
|
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
import org.yuzu.yuzu_emu.model.HomeSetting
|
import org.yuzu.yuzu_emu.model.HomeSetting
|
||||||
|
|
|
@ -28,8 +28,7 @@ class ChatMessage(
|
||||||
val username: String, // Username is the community/forum username
|
val username: String, // Username is the community/forum username
|
||||||
val message: String,
|
val message: String,
|
||||||
val timestamp: String = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date())
|
val timestamp: String = SimpleDateFormat("HH:mm", Locale.getDefault()).format(Date())
|
||||||
) {
|
)
|
||||||
}
|
|
||||||
|
|
||||||
class ChatDialog(context: Context) : BottomSheetDialog(context) {
|
class ChatDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
private lateinit var binding: DialogChatBinding
|
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.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 {
|
handler.post {
|
||||||
chatAdapter.notifyDataSetChanged()
|
chatAdapter.notifyDataSetChanged()
|
||||||
|
@ -133,10 +133,12 @@ class ChatAdapter(private val messages: List<ChatMessage>) :
|
||||||
fun bind(message: ChatMessage) {
|
fun bind(message: ChatMessage) {
|
||||||
binding.usernameText.text = message.nickname
|
binding.usernameText.text = message.nickname
|
||||||
binding.messageText.text = message.message
|
binding.messageText.text = message.message
|
||||||
binding.userIcon.setImageResource(when (message.nickname) {
|
binding.userIcon.setImageResource(
|
||||||
|
when (message.nickname) {
|
||||||
"System" -> R.drawable.ic_system
|
"System" -> R.drawable.ic_system
|
||||||
else -> R.drawable.ic_user
|
else -> R.drawable.ic_user
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,6 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) {
|
||||||
it.score
|
it.score
|
||||||
}.map { it.item }
|
}.map { it.item }
|
||||||
adapter.updateRooms(sortedList)
|
adapter.updateRooms(sortedList)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.EditText
|
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
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.network.NetPlayManager
|
||||||
import org.yuzu.yuzu_emu.utils.CompatUtils
|
import org.yuzu.yuzu_emu.utils.CompatUtils
|
||||||
import org.yuzu.yuzu_emu.utils.GameHelper
|
import org.yuzu.yuzu_emu.utils.GameHelper
|
||||||
import java.net.InetAddress
|
|
||||||
|
|
||||||
class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
private lateinit var adapter: NetPlayAdapter
|
private lateinit var adapter: NetPlayAdapter
|
||||||
|
@ -55,7 +53,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
|
||||||
when {
|
when {
|
||||||
NetPlayManager.netPlayIsJoined() -> DialogMultiplayerLobbyBinding.inflate(layoutInflater)
|
NetPlayManager.netPlayIsJoined() -> DialogMultiplayerLobbyBinding.inflate(
|
||||||
|
layoutInflater
|
||||||
|
)
|
||||||
.apply {
|
.apply {
|
||||||
setContentView(root)
|
setContentView(root)
|
||||||
adapter = NetPlayAdapter()
|
adapter = NetPlayAdapter()
|
||||||
|
@ -77,7 +77,6 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
btnModeration.setOnClickListener {
|
btnModeration.setOnClickListener {
|
||||||
showModerationDialog()
|
showModerationDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -140,7 +139,8 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
inner class NetPlayAdapter : RecyclerView.Adapter<NetPlayAdapter.NetPlayViewHolder>() {
|
inner class NetPlayAdapter : RecyclerView.Adapter<NetPlayAdapter.NetPlayViewHolder>() {
|
||||||
val netPlayItems = mutableListOf<NetPlayItems>()
|
val netPlayItems = mutableListOf<NetPlayItems>()
|
||||||
|
|
||||||
abstract inner class NetPlayViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
|
abstract inner class NetPlayViewHolder(itemView: View) :
|
||||||
|
RecyclerView.ViewHolder(itemView),
|
||||||
View.OnClickListener {
|
View.OnClickListener {
|
||||||
init {
|
init {
|
||||||
itemView.setOnClickListener(this)
|
itemView.setOnClickListener(this)
|
||||||
|
@ -167,7 +167,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
visibility = if (iconRes != 0) {
|
visibility = if (iconRes != 0) {
|
||||||
setImageResource(iconRes)
|
setImageResource(iconRes)
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
} else View.GONE
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,7 +188,6 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
|
||||||
override fun onClick(clicked: View) {}
|
override fun onClick(clicked: View) {}
|
||||||
|
|
||||||
|
|
||||||
private fun showPopupMenu(view: View) {
|
private fun showPopupMenu(view: View) {
|
||||||
PopupMenu(view.context, view).apply {
|
PopupMenu(view.context, view).apply {
|
||||||
menuInflater.inflate(R.menu.menu_netplay_member, menu)
|
menuInflater.inflate(R.menu.menu_netplay_member, menu)
|
||||||
|
@ -201,7 +202,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
} else if (item.itemId == R.id.action_ban) {
|
} else if (item.itemId == R.id.action_ban) {
|
||||||
NetPlayManager.netPlayBanUser(netPlayItems.name)
|
NetPlayManager.netPlayBanUser(netPlayItems.name)
|
||||||
true
|
true
|
||||||
} else false
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
|
@ -360,12 +363,15 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
|
||||||
val visibilityList: List<String> = listOf(
|
val visibilityList: List<String> = listOf(
|
||||||
context.getString(R.string.multiplayer_public_visibility),
|
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(
|
binding.textTitle.text = activity.getString(
|
||||||
if (isCreateRoom) R.string.multiplayer_create_room
|
if (isCreateRoom) {
|
||||||
else R.string.multiplayer_join_room
|
R.string.multiplayer_create_room
|
||||||
|
} else {
|
||||||
|
R.string.multiplayer_join_room
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// setup listeners etc
|
// 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 {
|
binding.dropdownLobbyVisibility.apply {
|
||||||
setAdapter(
|
setAdapter(
|
||||||
|
@ -501,8 +509,11 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
binding.btnConfirm.isEnabled = false
|
binding.btnConfirm.isEnabled = false
|
||||||
binding.btnConfirm.text =
|
binding.btnConfirm.text =
|
||||||
activity.getString(
|
activity.getString(
|
||||||
if (isCreateRoom) R.string.multiplayer_creating
|
if (isCreateRoom) {
|
||||||
else R.string.multiplayer_joining
|
R.string.multiplayer_creating
|
||||||
|
} else {
|
||||||
|
R.string.multiplayer_joining
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// We don't need to worry about validation because it's already been done.
|
// 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(
|
Toast.makeText(
|
||||||
YuzuApplication.appContext,
|
YuzuApplication.appContext,
|
||||||
if (isCreateRoom) R.string.multiplayer_create_room_success
|
if (isCreateRoom) {
|
||||||
else R.string.multiplayer_join_room_success,
|
R.string.multiplayer_create_room_success
|
||||||
|
} else {
|
||||||
|
R.string.multiplayer_join_room_success
|
||||||
|
},
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
|
|
||||||
|
@ -619,7 +633,9 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
val binding = ItemBanListBinding.inflate(
|
val binding = ItemBanListBinding.inflate(
|
||||||
LayoutInflater.from(parent.context), parent, false
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
return ViewHolder(binding)
|
return ViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
@ -654,6 +670,5 @@ class NetPlayDialog(context: Context) : BottomSheetDialog(context) {
|
||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.yuzu.yuzu_emu.databinding.ItemDriverGroupBinding
|
||||||
import org.yuzu.yuzu_emu.fragments.DriverFetcherFragment.DriverGroup
|
import org.yuzu.yuzu_emu.fragments.DriverFetcherFragment.DriverGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.transition.AutoTransition
|
|
||||||
import androidx.transition.ChangeBounds
|
import androidx.transition.ChangeBounds
|
||||||
import androidx.transition.Fade
|
import androidx.transition.Fade
|
||||||
import androidx.transition.TransitionManager
|
import androidx.transition.TransitionManager
|
||||||
|
@ -89,7 +88,9 @@ class DriverGroupAdapter(
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverGroupViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverGroupViewHolder {
|
||||||
val binding = ItemDriverGroupBinding.inflate(
|
val binding = ItemDriverGroupBinding.inflate(
|
||||||
LayoutInflater.from(parent.context), parent, false
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
return DriverGroupViewHolder(binding)
|
return DriverGroupViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
package org.yuzu.yuzu_emu.features.fetcher
|
||||||
|
|
||||||
import android.animation.LayoutTransition
|
import android.animation.LayoutTransition
|
||||||
|
@ -71,7 +74,7 @@ class ReleaseAdapter(
|
||||||
|
|
||||||
// truncates to 150 chars so it does not take up too much space.
|
// truncates to 150 chars so it does not take up too much space.
|
||||||
var bodyPreview = release.body.take(150)
|
var bodyPreview = release.body.take(150)
|
||||||
bodyPreview = bodyPreview.replace("#", "").removeSurrounding(" ");
|
bodyPreview = bodyPreview.replace("#", "").removeSurrounding(" ")
|
||||||
|
|
||||||
val body =
|
val body =
|
||||||
bodyPreview.replace("\\r\\n", "\n").replace("\\n", "\n").replace("\n", "<br>")
|
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.imageDownloadsArrow.rotation = if (isVisible) 0f else 180f
|
||||||
binding.buttonToggleDownloads.text =
|
binding.buttonToggleDownloads.text =
|
||||||
if (isVisible) activity.getString(R.string.show_downloads)
|
if (isVisible) {
|
||||||
else activity.getString(R.string.hide_downloads)
|
activity.getString(R.string.show_downloads)
|
||||||
|
} else {
|
||||||
|
activity.getString(R.string.hide_downloads)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.buttonToggleDownloads.setOnClickListener {
|
binding.buttonToggleDownloads.setOnClickListener {
|
||||||
|
@ -139,9 +145,15 @@ class ReleaseAdapter(
|
||||||
release.artifacts.forEach { artifact ->
|
release.artifacts.forEach { artifact ->
|
||||||
val button = MaterialButton(binding.root.context).apply {
|
val button = MaterialButton(binding.root.context).apply {
|
||||||
text = artifact.name
|
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
|
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)
|
setIconResource(R.drawable.ic_import)
|
||||||
iconTint = ColorStateList.valueOf(
|
iconTint = ColorStateList.valueOf(
|
||||||
MaterialColors.getColor(
|
MaterialColors.getColor(
|
||||||
|
@ -199,7 +211,9 @@ class ReleaseAdapter(
|
||||||
input.copyTo(output)
|
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 driverData = GpuDriverHelper.getMetadataFromZip(file)
|
||||||
val driverPath =
|
val driverPath =
|
||||||
"${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(file.toUri())}"
|
"${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(
|
||||||
|
file.toUri()
|
||||||
|
)}"
|
||||||
|
|
||||||
if (GpuDriverHelper.copyDriverToInternalStorage(file.toUri())) {
|
if (GpuDriverHelper.copyDriverToInternalStorage(file.toUri())) {
|
||||||
driverViewModel.onDriverAdded(Pair(driverPath, driverData))
|
driverViewModel.onDriverAdded(Pair(driverPath, driverData))
|
||||||
|
@ -254,7 +270,9 @@ class ReleaseAdapter(
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReleaseViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReleaseViewHolder {
|
||||||
val binding = ItemReleaseBinding.inflate(
|
val binding = ItemReleaseBinding.inflate(
|
||||||
LayoutInflater.from(parent.context), parent, false
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
return ReleaseViewHolder(binding)
|
return ReleaseViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
package org.yuzu.yuzu_emu.features.fetcher
|
||||||
|
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
|
|
|
@ -64,13 +64,12 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||||
SHOW_SHADERS_BUILDING("show_shaders_building"),
|
SHOW_SHADERS_BUILDING("show_shaders_building"),
|
||||||
|
|
||||||
DEBUG_FLUSH_BY_LINE("flush_lines"),
|
DEBUG_FLUSH_BY_LINE("flush_lines"),
|
||||||
USE_LRU_CACHE("use_lru_cache"),;
|
USE_LRU_CACHE("use_lru_cache");
|
||||||
|
|
||||||
external fun isRaiiEnabled(): Boolean
|
external fun isRaiiEnabled(): Boolean
|
||||||
// external fun isFrameSkippingEnabled(): Boolean
|
// external fun isFrameSkippingEnabled(): Boolean
|
||||||
external fun isFrameInterpolationEnabled(): Boolean
|
external fun isFrameInterpolationEnabled(): Boolean
|
||||||
|
|
||||||
|
|
||||||
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
||||||
NativeConfig.getBoolean(key, needsGlobal)
|
NativeConfig.getBoolean(key, needsGlobal)
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
||||||
OFFLINE_WEB_APPLET("offline_web_applet_mode"),
|
OFFLINE_WEB_APPLET("offline_web_applet_mode"),
|
||||||
LOGIN_SHARE_APPLET("login_share_applet_mode"),
|
LOGIN_SHARE_APPLET("login_share_applet_mode"),
|
||||||
WIFI_WEB_AUTH_APPLET("wifi_web_auth_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)
|
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
||||||
|
|
|
@ -13,7 +13,7 @@ enum class StringSetting(override val key: String) : AbstractStringSetting {
|
||||||
DEVICE_NAME("device_name"),
|
DEVICE_NAME("device_name"),
|
||||||
|
|
||||||
WEB_TOKEN("eden_token"),
|
WEB_TOKEN("eden_token"),
|
||||||
WEB_USERNAME("eden_username"),
|
WEB_USERNAME("eden_username")
|
||||||
;
|
;
|
||||||
|
|
||||||
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
|
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
|
||||||
|
|
|
@ -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.ShortSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
import org.yuzu.yuzu_emu.network.NetDataValidators
|
import org.yuzu.yuzu_emu.network.NetDataValidators
|
||||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -516,7 +515,6 @@ abstract class SettingsItem(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
put(
|
put(
|
||||||
SingleChoiceSetting(
|
SingleChoiceSetting(
|
||||||
IntSetting.RENDERER_VSYNC,
|
IntSetting.RENDERER_VSYNC,
|
||||||
|
|
|
@ -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-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -18,7 +21,7 @@ class SingleChoiceSetting(
|
||||||
@ArrayRes val choicesId: Int,
|
@ArrayRes val choicesId: Int,
|
||||||
@ArrayRes val valuesId: Int,
|
@ArrayRes val valuesId: Int,
|
||||||
val warnChoices: List<Int> = ArrayList(),
|
val warnChoices: List<Int> = ArrayList(),
|
||||||
@StringRes val warningMessage: Int = 0,
|
@StringRes val warningMessage: Int = 0
|
||||||
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
|
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
|
||||||
override val type = TYPE_SINGLE_CHOICE
|
override val type = TYPE_SINGLE_CHOICE
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||||
|
|
||||||
import android.text.Editable
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
||||||
override fun afterTextChanged(s: Editable?) {
|
override fun afterTextChanged(s: Editable?) {
|
||||||
val isValid = validator(s.toString())
|
val isValid = validator(s.toString())
|
||||||
stringInputBinding.editTextLayout.isErrorEnabled = !isValid
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -8,7 +11,6 @@ import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
|
@ -16,13 +18,11 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
|
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
|
||||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
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.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
package org.yuzu.yuzu_emu.features.settings.ui
|
package org.yuzu.yuzu_emu.features.settings.ui
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
|
||||||
import android.app.AlertDialog
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
@ -1057,7 +1055,9 @@ class SettingsFragmentPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting {
|
val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting {
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(
|
||||||
|
YuzuApplication.appContext
|
||||||
|
)
|
||||||
override fun getInt(needsGlobal: Boolean): Int =
|
override fun getInt(needsGlobal: Boolean): Int =
|
||||||
preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0)
|
preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0)
|
||||||
override fun setInt(value: Int) {
|
override fun setInt(value: Int) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
|
|
|
@ -33,7 +33,10 @@ class AddGameFolderDialogFragment : DialogFragment() {
|
||||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
|
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
|
||||||
val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked)
|
val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked)
|
||||||
homeViewModel.setGamesDirSelected(true)
|
homeViewModel.setGamesDirSelected(true)
|
||||||
val calledFromGameFragment = requireArguments().getBoolean("calledFromGameFragment", false)
|
val calledFromGameFragment = requireArguments().getBoolean(
|
||||||
|
"calledFromGameFragment",
|
||||||
|
false
|
||||||
|
)
|
||||||
gamesViewModel.addFolder(newGameDir, calledFromGameFragment)
|
gamesViewModel.addFolder(newGameDir, calledFromGameFragment)
|
||||||
}
|
}
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
|
|
@ -62,14 +62,14 @@ class DriverFetcherFragment : Fragment() {
|
||||||
val path: String = "",
|
val path: String = "",
|
||||||
val sort: Int = 0,
|
val sort: Int = 0,
|
||||||
val useTagName: Boolean = false,
|
val useTagName: Boolean = false,
|
||||||
val sortMode: SortMode = SortMode.Default,
|
val sortMode: SortMode = SortMode.Default
|
||||||
)
|
)
|
||||||
|
|
||||||
private val repoList: List<DriverRepo> = listOf(
|
private val repoList: List<DriverRepo> = listOf(
|
||||||
DriverRepo("Mr. Purple Turnip", "MrPurple666/purple-turnip", 0),
|
DriverRepo("Mr. Purple Turnip", "MrPurple666/purple-turnip", 0),
|
||||||
DriverRepo("GameHub Adreno 8xx", "crueter/GameHub-8Elite-Drivers", 1),
|
DriverRepo("GameHub Adreno 8xx", "crueter/GameHub-8Elite-Drivers", 1),
|
||||||
DriverRepo("KIMCHI Turnip", "K11MCH1/AdrenoToolsDrivers", 2, true, SortMode.PublishTime),
|
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(
|
private val driverMap = listOf(
|
||||||
|
@ -81,7 +81,7 @@ class DriverFetcherFragment : Fragment() {
|
||||||
IntRange(700, 710) to "KIMCHI 25.2.0_r5",
|
IntRange(700, 710) to "KIMCHI 25.2.0_r5",
|
||||||
IntRange(711, 799) to "Mr. Purple T21",
|
IntRange(711, 799) to "Mr. Purple T21",
|
||||||
IntRange(800, 899) to "GameHub Adreno 8xx",
|
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
|
private lateinit var driverGroupAdapter: DriverGroupAdapter
|
||||||
|
@ -124,7 +124,9 @@ class DriverFetcherFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
_binding = FragmentDriverFetcherBinding.inflate(inflater)
|
_binding = FragmentDriverFetcherBinding.inflate(inflater)
|
||||||
binding.badgeRecommendedDriver.text = recommendedDriver
|
binding.badgeRecommendedDriver.text = recommendedDriver
|
||||||
|
@ -178,8 +180,12 @@ class DriverFetcherFragment : Fragment() {
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
MaterialAlertDialogBuilder(requireActivity()).setTitle(getString(R.string.error_during_fetch))
|
MaterialAlertDialogBuilder(requireActivity()).setTitle(
|
||||||
.setMessage("${getString(R.string.failed_to_fetch)} ${name}:\n${e.message}")
|
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() }
|
.setPositiveButton(getString(R.string.ok)) { dialog, _ -> dialog.cancel() }
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
|
@ -188,7 +194,9 @@ class DriverFetcherFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val group = DriverGroup(
|
val group = DriverGroup(
|
||||||
name, releases, sort
|
name,
|
||||||
|
releases,
|
||||||
|
sort
|
||||||
)
|
)
|
||||||
|
|
||||||
synchronized(driverGroups) {
|
synchronized(driverGroups) {
|
||||||
|
@ -223,7 +231,9 @@ class DriverFetcherFragment : Fragment() {
|
||||||
binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets)
|
binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets)
|
||||||
|
|
||||||
binding.listDrivers.updatePadding(
|
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
|
windowInsets
|
||||||
|
@ -239,11 +249,13 @@ class DriverFetcherFragment : Fragment() {
|
||||||
var artifacts: List<Artifact> = ArrayList(),
|
var artifacts: List<Artifact> = ArrayList(),
|
||||||
var prerelease: Boolean = false,
|
var prerelease: Boolean = false,
|
||||||
var latest: Boolean = false,
|
var latest: Boolean = false,
|
||||||
var publishTime: LocalDateTime = LocalDateTime.now(),
|
var publishTime: LocalDateTime = LocalDateTime.now()
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun fromJsonArray(
|
fun fromJsonArray(
|
||||||
jsonString: String, useTagName: Boolean, sortMode: SortMode
|
jsonString: String,
|
||||||
|
useTagName: Boolean,
|
||||||
|
sortMode: SortMode
|
||||||
): ArrayList<Release> {
|
): ArrayList<Release> {
|
||||||
val mapper = jacksonObjectMapper()
|
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) {
|
} catch (e: Exception) {
|
||||||
// TODO: handle malformed input.
|
// TODO: handle malformed input.
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
@ -324,6 +345,6 @@ class DriverFetcherFragment : Fragment() {
|
||||||
data class DriverGroup(
|
data class DriverGroup(
|
||||||
val name: String,
|
val name: String,
|
||||||
val releases: ArrayList<Release>,
|
val releases: ArrayList<Release>,
|
||||||
val sort: Int,
|
val sort: Int
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -25,7 +25,6 @@ import kotlinx.coroutines.withContext
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.adapters.DriverAdapter
|
import org.yuzu.yuzu_emu.adapters.DriverAdapter
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding
|
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.Settings
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
|
import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
|
||||||
|
@ -108,7 +107,9 @@ class DriverManagerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.buttonFetch.setOnClickListener {
|
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 {
|
binding.listDrivers.apply {
|
||||||
|
|
|
@ -45,6 +45,7 @@ import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.window.layout.FoldingFeature
|
import androidx.window.layout.FoldingFeature
|
||||||
|
@ -52,7 +53,6 @@ import androidx.window.layout.WindowInfoTracker
|
||||||
import androidx.window.layout.WindowLayoutInfo
|
import androidx.window.layout.WindowLayoutInfo
|
||||||
import com.google.android.material.color.MaterialColors
|
import com.google.android.material.color.MaterialColors
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.slider.Slider
|
|
||||||
import com.google.android.material.textview.MaterialTextView
|
import com.google.android.material.textview.MaterialTextView
|
||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
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
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
import org.yuzu.yuzu_emu.utils.collect
|
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
|
import java.io.File
|
||||||
|
|
||||||
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
@ -90,24 +96,29 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
private var perfStatsUpdater: (() -> Unit)? = null
|
private var perfStatsUpdater: (() -> Unit)? = null
|
||||||
private var socUpdater: (() -> Unit)? = null
|
private var socUpdater: (() -> Unit)? = null
|
||||||
|
|
||||||
private lateinit var cpuBackend: String
|
|
||||||
private lateinit var gpuDriver: String
|
|
||||||
|
|
||||||
private var _binding: FragmentEmulationBinding? = null
|
private var _binding: FragmentEmulationBinding? = null
|
||||||
|
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private val args by navArgs<EmulationFragmentArgs>()
|
private val args by navArgs<EmulationFragmentArgs>()
|
||||||
|
|
||||||
private lateinit var game: Game
|
private var game: Game? = null
|
||||||
|
|
||||||
private val emulationViewModel: EmulationViewModel by activityViewModels()
|
private val emulationViewModel: EmulationViewModel by activityViewModels()
|
||||||
private val driverViewModel: DriverViewModel by activityViewModels()
|
private val driverViewModel: DriverViewModel by activityViewModels()
|
||||||
|
|
||||||
private var isInFoldableLayout = false
|
private var isInFoldableLayout = false
|
||||||
|
private var emulationStarted = false
|
||||||
|
|
||||||
private lateinit var gpuModel: String
|
private lateinit var gpuModel: String
|
||||||
private lateinit var fwVersion: 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) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
if (context is EmulationActivity) {
|
if (context is EmulationActivity) {
|
||||||
|
@ -125,9 +136,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
updateOrientation()
|
updateOrientation()
|
||||||
|
|
||||||
val intentUri: Uri? = requireActivity().intent.data
|
val intent = requireActivity().intent
|
||||||
var intentGame: Game? = null
|
val intentUri: Uri? = intent.data
|
||||||
if (intentUri != null) {
|
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))) {
|
intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri))) {
|
||||||
GameHelper.getGame(requireActivity().intent.data!!, false)
|
GameHelper.getGame(requireActivity().intent.data!!, false)
|
||||||
} else {
|
} else {
|
||||||
|
@ -135,13 +152,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
finishGameSetup()
|
||||||
game = if (args.game != null) {
|
|
||||||
args.game!!
|
|
||||||
} else {
|
|
||||||
intentGame!!
|
|
||||||
}
|
}
|
||||||
} catch (e: NullPointerException) {
|
|
||||||
|
/**
|
||||||
|
* Complete the game setup process (extracted for async custom settings handling)
|
||||||
|
*/
|
||||||
|
private fun finishGameSetup() {
|
||||||
|
try {
|
||||||
|
val gameToUse = args.game ?: intentGame
|
||||||
|
|
||||||
|
if (gameToUse == null) {
|
||||||
|
Log.error("[EmulationFragment] No game found in arguments or intent")
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.string.no_game_present,
|
R.string.no_game_present,
|
||||||
|
@ -151,22 +173,288 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always load custom settings when launching a game from an intent
|
game = gameToUse
|
||||||
if (args.custom || intentGame != null) {
|
|
||||||
SettingsFile.loadCustomConfig(game)
|
} catch (e: Exception) {
|
||||||
NativeConfig.unloadPerGameConfig()
|
Log.error("[EmulationFragment] Error during game setup: ${e.message}")
|
||||||
} else {
|
Toast.makeText(
|
||||||
NativeConfig.reloadGlobalConfig()
|
requireContext(),
|
||||||
|
"Setup error: ${e.message?.take(30) ?: "Unknown"}",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
requireActivity().finish()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install the selected driver asynchronously as the game starts
|
try {
|
||||||
driverViewModel.onLaunchGame()
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
// Normal game launch from arguments
|
||||||
retainInstance = true
|
else -> {
|
||||||
emulationState = EmulationState(game.path) {
|
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
|
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 {
|
||||||
|
Log.error("[EmulationFragment] EmuReady intent missing title_id")
|
||||||
|
Toast.makeText(
|
||||||
|
requireContext(),
|
||||||
|
"Invalid request: missing title ID",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
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()
|
gpuModel = GpuDriverHelper.getGpuModel().toString()
|
||||||
fwVersion = NativeLibrary.firmwareVersion()
|
fwVersion = NativeLibrary.firmwareVersion()
|
||||||
|
|
||||||
|
@ -223,10 +525,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
|
||||||
binding.inGameMenu.getHeaderView(0).apply {
|
|
||||||
val titleView = findViewById<TextView>(R.id.text_game_title)
|
updateGameTitle()
|
||||||
titleView.text = game.title
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
|
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
|
||||||
val lockMode = IntSetting.LOCK_DRAWER.getInt()
|
val lockMode = IntSetting.LOCK_DRAWER.getInt()
|
||||||
|
@ -293,13 +593,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
R.id.menu_multiplayer -> {
|
R.id.menu_multiplayer -> {
|
||||||
emulationActivity?.displayMultiplayerDialog()
|
emulationActivity?.displayMultiplayerDialog()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
R.id.menu_controls -> {
|
R.id.menu_controls -> {
|
||||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||||
null,
|
null,
|
||||||
|
@ -368,8 +666,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
GameIconUtils.loadGameIcon(game, binding.loadingImage)
|
GameIconUtils.loadGameIcon(game!!, binding.loadingImage)
|
||||||
binding.loadingTitle.text = game.title
|
binding.loadingTitle.text = game!!.title
|
||||||
binding.loadingTitle.isSelected = true
|
binding.loadingTitle.isSelected = true
|
||||||
binding.loadingText.isSelected = true
|
binding.loadingText.isSelected = true
|
||||||
|
|
||||||
|
@ -408,7 +706,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
|
||||||
emulationState.updateSurface()
|
emulationState.updateSurface()
|
||||||
|
|
||||||
// Setup overlays
|
|
||||||
updateShowStatsOverlay()
|
updateShowStatsOverlay()
|
||||||
updateSocOverlay()
|
updateSocOverlay()
|
||||||
|
|
||||||
|
@ -418,7 +715,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
val cpuBackendLabel = findViewById<TextView>(R.id.cpu_backend)
|
val cpuBackendLabel = findViewById<TextView>(R.id.cpu_backend)
|
||||||
val vendorLabel = findViewById<TextView>(R.id.gpu_vendor)
|
val vendorLabel = findViewById<TextView>(R.id.gpu_vendor)
|
||||||
|
|
||||||
titleView.text = game.title
|
titleView.text = game?.title ?: ""
|
||||||
cpuBackendLabel.text = NativeLibrary.getCpuBackend()
|
cpuBackendLabel.text = NativeLibrary.getCpuBackend()
|
||||||
vendorLabel.text = NativeLibrary.getGpuDriver()
|
vendorLabel.text = NativeLibrary.getGpuDriver()
|
||||||
}
|
}
|
||||||
|
@ -456,16 +753,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
ViewUtils.showView(binding.loadingIndicator)
|
ViewUtils.showView(binding.loadingIndicator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emulationViewModel.emulationStopped.collect(viewLifecycleOwner) {
|
|
||||||
if (it && emulationViewModel.programChanged.value != -1) {
|
|
||||||
if (perfStatsUpdater != null) {
|
|
||||||
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (socUpdater != null) {
|
emulationViewModel.emulationStopped.collect(viewLifecycleOwner) { stopped ->
|
||||||
socUpdateHandler.removeCallbacks(socUpdater!!)
|
if (stopped && emulationViewModel.programChanged.value != -1) {
|
||||||
|
perfStatsRunnable?.let { runnable ->
|
||||||
|
perfStatsUpdateHandler.removeCallbacks(
|
||||||
|
runnable
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
socRunnable?.let { runnable -> socUpdateHandler.removeCallbacks(runnable) }
|
||||||
emulationState.changeProgram(emulationViewModel.programChanged.value)
|
emulationState.changeProgram(emulationViewModel.programChanged.value)
|
||||||
emulationViewModel.setProgramChanged(-1)
|
emulationViewModel.setProgramChanged(-1)
|
||||||
emulationViewModel.setEmulationStopped(false)
|
emulationViewModel.setEmulationStopped(false)
|
||||||
|
@ -473,10 +769,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) {
|
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) {
|
||||||
if (it) startEmulation()
|
if (it && !NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
|
||||||
|
startEmulation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
driverViewModel.onLaunchGame()
|
||||||
|
}
|
||||||
|
|
||||||
private fun startEmulation(programIndex: Int = 0) {
|
private fun startEmulation(programIndex: Int = 0) {
|
||||||
if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
|
if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
|
||||||
if (!DirectoryInitialization.areDirectoriesReady) {
|
if (!DirectoryInitialization.areDirectoriesReady) {
|
||||||
|
@ -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() {
|
override fun onPause() {
|
||||||
if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) {
|
if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) {
|
||||||
emulationState.pause()
|
emulationState.pause()
|
||||||
|
@ -634,7 +943,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
val batteryTemp = getBatteryTemperature()
|
val batteryTemp = getBatteryTemperature()
|
||||||
when (IntSetting.BAT_TEMPERATURE_UNIT.getInt(needsGlobal)) {
|
when (IntSetting.BAT_TEMPERATURE_UNIT.getInt(needsGlobal)) {
|
||||||
0 -> sb.append(String.format("%.1f°C", batteryTemp))
|
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 =
|
val battery: BatteryManager =
|
||||||
requireContext().getSystemService(Context.BATTERY_SERVICE) as BatteryManager
|
requireContext().getSystemService(Context.BATTERY_SERVICE) as BatteryManager
|
||||||
val batteryIntent = requireContext().registerReceiver(null,
|
val batteryIntent = requireContext().registerReceiver(
|
||||||
IntentFilter(Intent.ACTION_BATTERY_CHANGED))
|
null,
|
||||||
|
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
||||||
|
)
|
||||||
|
|
||||||
val capacity = battery.getIntProperty(BATTERY_PROPERTY_CAPACITY)
|
val capacity = battery.getIntProperty(BATTERY_PROPERTY_CAPACITY)
|
||||||
val nowUAmps = battery.getIntProperty(BATTERY_PROPERTY_CURRENT_NOW)
|
val nowUAmps = battery.getIntProperty(BATTERY_PROPERTY_CURRENT_NOW)
|
||||||
|
@ -671,20 +987,21 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BooleanSetting.PERF_OVERLAY_BACKGROUND.getBoolean(needsGlobal)) {
|
if (BooleanSetting.PERF_OVERLAY_BACKGROUND.getBoolean(needsGlobal)) {
|
||||||
binding.showStatsOverlayText.setBackgroundResource(R.color.yuzu_transparent_black)
|
binding.showStatsOverlayText.setBackgroundResource(
|
||||||
|
R.color.yuzu_transparent_black
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.showStatsOverlayText.setBackgroundResource(0)
|
binding.showStatsOverlayText.setBackgroundResource(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.showStatsOverlayText.text = sb.toString()
|
binding.showStatsOverlayText.text = sb.toString()
|
||||||
}
|
}
|
||||||
perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 800)
|
perfStatsUpdateHandler.postDelayed(perfStatsRunnable!!, 800)
|
||||||
}
|
}
|
||||||
perfStatsUpdateHandler.post(perfStatsUpdater!!)
|
perfStatsRunnable = Runnable { perfStatsUpdater?.invoke() }
|
||||||
|
perfStatsUpdateHandler.post(perfStatsRunnable!!)
|
||||||
} else {
|
} else {
|
||||||
if (perfStatsUpdater != null) {
|
perfStatsRunnable?.let { perfStatsUpdateHandler.removeCallbacks(it) }
|
||||||
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,46 +1084,61 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
) {
|
) {
|
||||||
sb.setLength(0)
|
sb.setLength(0)
|
||||||
|
|
||||||
if (BooleanSetting.SHOW_DEVICE_MODEL.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
|
if (BooleanSetting.SHOW_DEVICE_MODEL.getBoolean(
|
||||||
|
NativeConfig.isPerGameConfigLoaded()
|
||||||
|
)
|
||||||
|
) {
|
||||||
sb.append(Build.MODEL)
|
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(" | ")
|
if (sb.isNotEmpty()) sb.append(" | ")
|
||||||
sb.append(gpuModel)
|
sb.append(gpuModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 31) {
|
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(" | ")
|
if (sb.isNotEmpty()) sb.append(" | ")
|
||||||
sb.append(Build.SOC_MODEL)
|
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(" | ")
|
if (sb.isNotEmpty()) sb.append(" | ")
|
||||||
sb.append(fwVersion)
|
sb.append(fwVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.showSocOverlayText.text = sb.toString()
|
binding.showSocOverlayText.text = sb.toString()
|
||||||
|
|
||||||
if (BooleanSetting.SOC_OVERLAY_BACKGROUND.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
|
if (BooleanSetting.SOC_OVERLAY_BACKGROUND.getBoolean(
|
||||||
binding.showSocOverlayText.setBackgroundResource(R.color.yuzu_transparent_black)
|
NativeConfig.isPerGameConfigLoaded()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
binding.showSocOverlayText.setBackgroundResource(
|
||||||
|
R.color.yuzu_transparent_black
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.showSocOverlayText.setBackgroundResource(0)
|
binding.showSocOverlayText.setBackgroundResource(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
socUpdateHandler.postDelayed(socUpdater!!, 1000)
|
socUpdateHandler.postDelayed(socRunnable!!, 1000)
|
||||||
}
|
}
|
||||||
socUpdateHandler.post(socUpdater!!)
|
socRunnable = Runnable { socUpdater?.invoke() }
|
||||||
|
socUpdateHandler.post(socRunnable!!)
|
||||||
} else {
|
} else {
|
||||||
if (socUpdater != null) {
|
socRunnable?.let { socUpdateHandler.removeCallbacks(it) }
|
||||||
socUpdateHandler.removeCallbacks(socUpdater!!)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("SourceLockedOrientationActivity")
|
@SuppressLint("SourceLockedOrientationActivity")
|
||||||
private fun updateOrientation() {
|
private fun updateOrientation() {
|
||||||
|
@ -919,11 +1251,34 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
|
||||||
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||||
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height)
|
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height)
|
||||||
|
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)
|
emulationState.newSurface(holder.surface)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emulationState.newSurface(holder.surface)
|
||||||
|
} else {
|
||||||
|
emulationState.newSurface(holder.surface)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||||
emulationState.clearSurface()
|
emulationState.clearSurface()
|
||||||
|
emulationStarted = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showOverlayOptions() {
|
private fun showOverlayOptions() {
|
||||||
|
@ -1096,22 +1451,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
inputScaleSlider.apply {
|
inputScaleSlider.apply {
|
||||||
valueTo = 150F
|
valueTo = 150F
|
||||||
value = IntSetting.OVERLAY_SCALE.getInt().toFloat()
|
value = IntSetting.OVERLAY_SCALE.getInt().toFloat()
|
||||||
addOnChangeListener(
|
addOnChangeListener { _, value, _ ->
|
||||||
Slider.OnChangeListener { _, value, _ ->
|
|
||||||
inputScaleValue.text = "${value.toInt()}%"
|
inputScaleValue.text = "${value.toInt()}%"
|
||||||
setControlScale(value.toInt())
|
setControlScale(value.toInt())
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
inputOpacitySlider.apply {
|
inputOpacitySlider.apply {
|
||||||
valueTo = 100F
|
valueTo = 100F
|
||||||
value = IntSetting.OVERLAY_OPACITY.getInt().toFloat()
|
value = IntSetting.OVERLAY_OPACITY.getInt().toFloat()
|
||||||
addOnChangeListener(
|
addOnChangeListener { _, value, _ ->
|
||||||
Slider.OnChangeListener { _, value, _ ->
|
|
||||||
inputOpacityValue.text = "${value.toInt()}%"
|
inputOpacityValue.text = "${value.toInt()}%"
|
||||||
setControlOpacity(value.toInt())
|
setControlOpacity(value.toInt())
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
inputScaleValue.text = "${inputScaleSlider.value.toInt()}%"
|
inputScaleValue.text = "${inputScaleSlider.value.toInt()}%"
|
||||||
inputOpacityValue.text = "${inputOpacitySlider.value.toInt()}%"
|
inputOpacityValue.text = "${inputOpacitySlider.value.toInt()}%"
|
||||||
|
@ -1147,7 +1498,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
val cutInsets: Insets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
val cutInsets: Insets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||||
var left = 0
|
var left = 0
|
||||||
var right = 0
|
var right = 0
|
||||||
if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR) {
|
if (v.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
|
||||||
left = cutInsets.left
|
left = cutInsets.left
|
||||||
} else {
|
} else {
|
||||||
right = cutInsets.right
|
right = cutInsets.right
|
||||||
|
@ -1168,7 +1519,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
lateinit var emulationThread: Thread
|
lateinit var emulationThread: Thread
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Starting state is stopped.
|
|
||||||
state = State.STOPPED
|
state = State.STOPPED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1176,7 +1526,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
val isStopped: Boolean
|
val isStopped: Boolean
|
||||||
get() = state == State.STOPPED
|
get() = state == State.STOPPED
|
||||||
|
|
||||||
// Getters for the current state
|
|
||||||
@get:Synchronized
|
@get:Synchronized
|
||||||
val isPaused: Boolean
|
val isPaused: Boolean
|
||||||
get() = state == State.PAUSED
|
get() = state == State.PAUSED
|
||||||
|
@ -1196,7 +1545,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// State changing methods
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun pause() {
|
fun pause() {
|
||||||
if (state != State.PAUSED) {
|
if (state != State.PAUSED) {
|
||||||
|
|
|
@ -27,7 +27,6 @@ import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import org.yuzu.yuzu_emu.BuildConfig
|
|
||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
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.adapters.HomeSettingAdapter
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
|
import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
|
||||||
import org.yuzu.yuzu_emu.features.DocumentProvider
|
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.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||||
import org.yuzu.yuzu_emu.model.HomeSetting
|
import org.yuzu.yuzu_emu.model.HomeSetting
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
import org.yuzu.yuzu_emu.ui.main.MainActivity
|
||||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
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.Log
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
|
|
||||||
|
|
||||||
class HomeSettingsFragment : Fragment() {
|
class HomeSettingsFragment : Fragment() {
|
||||||
private var _binding: FragmentHomeSettingsBinding? = null
|
private var _binding: FragmentHomeSettingsBinding? = null
|
||||||
|
@ -125,7 +123,7 @@ class HomeSettingsFragment : Fragment() {
|
||||||
R.drawable.ic_two_users,
|
R.drawable.ic_two_users,
|
||||||
{
|
{
|
||||||
mainActivity.displayMultiplayerDialog()
|
mainActivity.displayMultiplayerDialog()
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
add(
|
add(
|
||||||
|
@ -254,6 +252,8 @@ class HomeSettingsFragment : Fragment() {
|
||||||
viewLifecycleOwner,
|
viewLifecycleOwner,
|
||||||
optionsList
|
optionsList
|
||||||
)
|
)
|
||||||
|
val spacing = resources.getDimensionPixelSize(R.dimen.spacing_small)
|
||||||
|
addItemDecoration(SpacingItemDecoration(spacing))
|
||||||
}
|
}
|
||||||
|
|
||||||
setInsets()
|
setInsets()
|
||||||
|
@ -403,7 +403,7 @@ class HomeSettingsFragment : Fragment() {
|
||||||
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||||
|
|
||||||
binding.scrollViewSettings.updatePadding(
|
binding.scrollViewSettings.updatePadding(
|
||||||
top = barInsets.top,
|
top = barInsets.top
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.homeSettingsList.updatePadding(
|
binding.homeSettingsList.updatePadding(
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
|
|
@ -78,7 +78,6 @@ class SetupFragment : Fragment() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
mainActivity = requireActivity() as MainActivity
|
mainActivity = requireActivity() as MainActivity
|
||||||
|
|
||||||
|
|
||||||
requireActivity().onBackPressedDispatcher.addCallback(
|
requireActivity().onBackPressedDispatcher.addCallback(
|
||||||
viewLifecycleOwner,
|
viewLifecycleOwner,
|
||||||
object : OnBackPressedCallback(true) {
|
object : OnBackPressedCallback(true) {
|
||||||
|
|
|
@ -22,7 +22,11 @@ class MidScreenSwipeRefreshLayout @JvmOverloads constructor(
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
startX = ev.x
|
startX = ev.x
|
||||||
val width = width
|
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 leftBound = ((1 - center_fraction) / 2) * width
|
||||||
val rightBound = leftBound + (width * center_fraction)
|
val rightBound = leftBound + (width * center_fraction)
|
||||||
allowRefresh = startX >= leftBound && startX <= rightBound
|
allowRefresh = startX >= leftBound && startX <= rightBound
|
||||||
|
|
|
@ -27,7 +27,7 @@ object NetDataValidators {
|
||||||
|
|
||||||
fun roomVisibility(s: String, context: Context): Boolean {
|
fun roomVisibility(s: String, context: Context): Boolean {
|
||||||
if (s != context.getString(R.string.multiplayer_public_visibility)) {
|
if (s != context.getString(R.string.multiplayer_public_visibility)) {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return token()
|
return token()
|
||||||
|
|
|
@ -70,7 +70,6 @@ object NetPlayManager {
|
||||||
val gameName: String
|
val gameName: String
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
private var messageListener: ((Int, String) -> Unit)? = null
|
private var messageListener: ((Int, String) -> Unit)? = null
|
||||||
private var adapterRefreshListener: ((Int, String) -> Unit)? = null
|
private var adapterRefreshListener: ((Int, String) -> Unit)? = null
|
||||||
|
|
||||||
|
@ -199,7 +198,6 @@ object NetPlayManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
if (!isChatOpen) {
|
if (!isChatOpen) {
|
||||||
// TODO(alekpop, crueter): Improve this, potentially a drawer at the top?
|
// TODO(alekpop, crueter): Improve this, potentially a drawer at the top?
|
||||||
|
@ -207,7 +205,6 @@ object NetPlayManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
messageListener?.invoke(type, msg)
|
messageListener?.invoke(type, msg)
|
||||||
adapterRefreshListener?.invoke(type, msg)
|
adapterRefreshListener?.invoke(type, msg)
|
||||||
}
|
}
|
||||||
|
@ -218,19 +215,29 @@ object NetPlayManager {
|
||||||
NetPlayStatus.LOST_CONNECTION -> context.getString(R.string.multiplayer_lost_connection)
|
NetPlayStatus.LOST_CONNECTION -> context.getString(R.string.multiplayer_lost_connection)
|
||||||
NetPlayStatus.NAME_COLLISION -> context.getString(R.string.multiplayer_name_collision)
|
NetPlayStatus.NAME_COLLISION -> context.getString(R.string.multiplayer_name_collision)
|
||||||
NetPlayStatus.MAC_COLLISION -> context.getString(R.string.multiplayer_mac_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_VERSION -> context.getString(R.string.multiplayer_wrong_version)
|
||||||
NetPlayStatus.WRONG_PASSWORD -> context.getString(R.string.multiplayer_wrong_password)
|
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.ROOM_IS_FULL -> context.getString(R.string.multiplayer_room_is_full)
|
||||||
NetPlayStatus.HOST_BANNED -> context.getString(R.string.multiplayer_host_banned)
|
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.NO_SUCH_USER -> context.getString(R.string.multiplayer_no_such_user)
|
||||||
NetPlayStatus.ALREADY_IN_ROOM -> context.getString(R.string.multiplayer_already_in_room)
|
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.HOST_KICKED -> context.getString(R.string.multiplayer_host_kicked)
|
||||||
NetPlayStatus.UNKNOWN_ERROR -> context.getString(R.string.multiplayer_unknown_error)
|
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_IDLE -> context.getString(R.string.multiplayer_room_idle)
|
||||||
NetPlayStatus.ROOM_JOINING -> context.getString(R.string.multiplayer_room_joining)
|
NetPlayStatus.ROOM_JOINING -> context.getString(R.string.multiplayer_room_joining)
|
||||||
NetPlayStatus.ROOM_JOINED -> context.getString(R.string.multiplayer_room_joined)
|
NetPlayStatus.ROOM_JOINED -> context.getString(R.string.multiplayer_room_joined)
|
||||||
|
@ -247,7 +254,9 @@ object NetPlayManager {
|
||||||
msg
|
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
|
NetPlayStatus.CHAT_MESSAGE -> msg
|
||||||
else -> ""
|
else -> ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,20 +7,13 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Gravity
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.ViewTreeObserver
|
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.ImageButton
|
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
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.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
|
@ -111,7 +104,7 @@ class GamesFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
gameAdapter = GameAdapter(
|
gameAdapter = GameAdapter(
|
||||||
requireActivity() as AppCompatActivity,
|
requireActivity() as AppCompatActivity
|
||||||
)
|
)
|
||||||
|
|
||||||
applyGridGamesBinding()
|
applyGridGamesBinding()
|
||||||
|
@ -238,7 +231,9 @@ class GamesFragment : Fragment() {
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
if (getCurrentViewType() == GameAdapter.VIEW_TYPE_CAROUSEL) {
|
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())
|
val searchTerm = binding.searchText.text.toString().lowercase(Locale.getDefault())
|
||||||
if (searchTerm.isEmpty()) {
|
if (searchTerm.isEmpty()) {
|
||||||
((binding.gridGames as? RecyclerView)?.adapter as? GameAdapter)?.submitList(filteredList)
|
((binding.gridGames as? RecyclerView)?.adapter as? GameAdapter)?.submitList(
|
||||||
|
filteredList
|
||||||
|
)
|
||||||
gamesViewModel.setFilteredGames(filteredList)
|
gamesViewModel.setFilteredGames(filteredList)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -464,7 +461,9 @@ class GamesFragment : Fragment() {
|
||||||
// Always set margin as original + insets
|
// Always set margin as original + insets
|
||||||
mlpHeader.leftMargin = (originalHeaderLeftMargin ?: 0) + leftInset
|
mlpHeader.leftMargin = (originalHeaderLeftMargin ?: 0) + leftInset
|
||||||
mlpHeader.rightMargin = (originalHeaderRightMargin ?: 0) + rightInset
|
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.header.layoutParams = mlpHeader
|
||||||
|
|
||||||
binding.noticeText.updatePadding(bottom = spacingNavigation)
|
binding.noticeText.updatePadding(bottom = spacingNavigation)
|
||||||
|
|
|
@ -6,8 +6,6 @@ package org.yuzu.yuzu_emu.ui.main
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.ParcelFileDescriptor
|
|
||||||
import android.provider.OpenableColumns
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
@ -49,7 +47,6 @@ import java.io.BufferedOutputStream
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.net.toFile
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(), ThemeProvider {
|
class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
|
@ -69,7 +66,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
private var checkedFirmware = false
|
private var checkedFirmware = false
|
||||||
|
|
||||||
private val requestBluetoothPermissionsLauncher =
|
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 }
|
val granted = permissions.entries.all { it.value }
|
||||||
if (granted) {
|
if (granted) {
|
||||||
// Permissions were granted.
|
// Permissions were granted.
|
||||||
|
@ -111,10 +110,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
|
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
|
||||||
checkAndRequestBluetoothPermissions()
|
checkAndRequestBluetoothPermissions()
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
|
@ -151,16 +148,20 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
binding.statusBarShade.setBackgroundColor(
|
binding.statusBarShade.setBackgroundColor(
|
||||||
ThemeHelper.getColorWithOpacity(
|
ThemeHelper.getColorWithOpacity(
|
||||||
MaterialColors.getColor(
|
MaterialColors.getColor(
|
||||||
binding.root, com.google.android.material.R.attr.colorSurface
|
binding.root,
|
||||||
), ThemeHelper.SYSTEM_BAR_ALPHA
|
com.google.android.material.R.attr.colorSurface
|
||||||
|
),
|
||||||
|
ThemeHelper.SYSTEM_BAR_ALPHA
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (InsetsHelper.getSystemGestureType(applicationContext) != InsetsHelper.GESTURE_NAVIGATION) {
|
if (InsetsHelper.getSystemGestureType(applicationContext) != InsetsHelper.GESTURE_NAVIGATION) {
|
||||||
binding.navigationBarShade.setBackgroundColor(
|
binding.navigationBarShade.setBackgroundColor(
|
||||||
ThemeHelper.getColorWithOpacity(
|
ThemeHelper.getColorWithOpacity(
|
||||||
MaterialColors.getColor(
|
MaterialColors.getColor(
|
||||||
binding.root, com.google.android.material.R.attr.colorSurface
|
binding.root,
|
||||||
), ThemeHelper.SYSTEM_BAR_ALPHA
|
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.statusBarShadeVisible.collect(this) { showStatusBarShade(it) }
|
||||||
homeViewModel.contentToInstall.collect(
|
homeViewModel.contentToInstall.collect(
|
||||||
this, resetState = { homeViewModel.setContentToInstall(null) }) {
|
this,
|
||||||
|
resetState = { homeViewModel.setContentToInstall(null) }
|
||||||
|
) {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
installContent(it)
|
installContent(it)
|
||||||
}
|
}
|
||||||
|
@ -181,7 +184,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
homeViewModel.checkFirmware.collect(
|
homeViewModel.checkFirmware.collect(
|
||||||
this, resetState = { homeViewModel.setCheckFirmware(false) }) {
|
this,
|
||||||
|
resetState = { homeViewModel.setCheckFirmware(false) }
|
||||||
|
) {
|
||||||
if (it) checkFirmware()
|
if (it) checkFirmware()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +209,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
PreferenceManager.getDefaultSharedPreferences(applicationContext).edit() {
|
PreferenceManager.getDefaultSharedPreferences(applicationContext).edit() {
|
||||||
putBoolean(Settings.PREF_SHOULD_SHOW_PRE_ALPHA_WARNING, false)
|
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() {
|
private fun checkFirmware() {
|
||||||
val resultCode: Int = NativeLibrary.verifyFirmware()
|
val resultCode: Int = NativeLibrary.verifyFirmware()
|
||||||
if (resultCode == 0) return;
|
if (resultCode == 0) return
|
||||||
|
|
||||||
val resultString: String =
|
val resultString: String =
|
||||||
resources.getStringArray(R.array.verifyFirmwareResults)[resultCode]
|
resources.getStringArray(R.array.verifyFirmwareResults)[resultCode]
|
||||||
|
@ -313,14 +319,17 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
|
|
||||||
fun processGamesDir(result: Uri, calledFromGameFragment: Boolean = false) {
|
fun processGamesDir(result: Uri, calledFromGameFragment: Boolean = false) {
|
||||||
contentResolver.takePersistableUriPermission(
|
contentResolver.takePersistableUriPermission(
|
||||||
result, Intent.FLAG_GRANT_READ_URI_PERMISSION
|
result,
|
||||||
|
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
)
|
)
|
||||||
|
|
||||||
val uriString = result.toString()
|
val uriString = result.toString()
|
||||||
val folder = gamesViewModel.folders.value.firstOrNull { it.uriString == uriString }
|
val folder = gamesViewModel.folders.value.firstOrNull { it.uriString == uriString }
|
||||||
if (folder != null) {
|
if (folder != null) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
applicationContext, R.string.folder_already_added, Toast.LENGTH_SHORT
|
applicationContext,
|
||||||
|
R.string.folder_already_added,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -343,16 +352,19 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
|
|
||||||
fun processKey(result: Uri, extension: String = "keys") {
|
fun processKey(result: Uri, extension: String = "keys") {
|
||||||
contentResolver.takePersistableUriPermission(
|
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) {
|
if (resultCode == 0) {
|
||||||
// TODO(crueter): It may be worth it to switch some of these Toasts to snackbars,
|
// TODO(crueter): It may be worth it to switch some of these Toasts to snackbars,
|
||||||
// since most of it is foreground-only anyways.
|
// since most of it is foreground-only anyways.
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
applicationContext, R.string.keys_install_success, Toast.LENGTH_SHORT
|
applicationContext,
|
||||||
|
R.string.keys_install_success,
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
|
|
||||||
gamesViewModel.reloadGames(true)
|
gamesViewModel.reloadGames(true)
|
||||||
|
@ -384,12 +396,15 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
val cacheFirmwareDir = File("${cacheDir.path}/registered/")
|
val cacheFirmwareDir = File("${cacheDir.path}/registered/")
|
||||||
|
|
||||||
ProgressDialogFragment.newInstance(
|
ProgressDialogFragment.newInstance(
|
||||||
this, R.string.firmware_installing
|
this,
|
||||||
|
R.string.firmware_installing
|
||||||
) { progressCallback, _ ->
|
) { progressCallback, _ ->
|
||||||
var messageToShow: Any
|
var messageToShow: Any
|
||||||
try {
|
try {
|
||||||
FileUtil.unzipToInternalStorage(
|
FileUtil.unzipToInternalStorage(
|
||||||
result.toString(), cacheFirmwareDir, progressCallback
|
result.toString(),
|
||||||
|
cacheFirmwareDir,
|
||||||
|
progressCallback
|
||||||
)
|
)
|
||||||
val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1
|
val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1
|
||||||
val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2
|
val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2
|
||||||
|
@ -423,7 +438,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
val firmwarePath =
|
val firmwarePath =
|
||||||
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
|
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
|
||||||
ProgressDialogFragment.newInstance(
|
ProgressDialogFragment.newInstance(
|
||||||
this, R.string.firmware_uninstalling
|
this,
|
||||||
|
R.string.firmware_uninstalling
|
||||||
) { progressCallback, _ ->
|
) { progressCallback, _ ->
|
||||||
var messageToShow: Any
|
var messageToShow: Any
|
||||||
try {
|
try {
|
||||||
|
@ -459,12 +475,15 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressDialogFragment.newInstance(
|
ProgressDialogFragment.newInstance(
|
||||||
this@MainActivity, R.string.verifying_content, false
|
this@MainActivity,
|
||||||
|
R.string.verifying_content,
|
||||||
|
false
|
||||||
) { _, _ ->
|
) { _, _ ->
|
||||||
var updatesMatchProgram = true
|
var updatesMatchProgram = true
|
||||||
for (document in documents) {
|
for (document in documents) {
|
||||||
val valid = NativeLibrary.doesUpdateMatchProgram(
|
val valid = NativeLibrary.doesUpdateMatchProgram(
|
||||||
addonViewModel.game!!.programId, document.toString()
|
addonViewModel.game!!.programId,
|
||||||
|
document.toString()
|
||||||
)
|
)
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
updatesMatchProgram = false
|
updatesMatchProgram = false
|
||||||
|
@ -480,14 +499,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
titleId = R.string.content_install_notice,
|
titleId = R.string.content_install_notice,
|
||||||
descriptionId = R.string.content_install_notice_description,
|
descriptionId = R.string.content_install_notice_description,
|
||||||
positiveAction = { homeViewModel.setContentToInstall(documents) },
|
positiveAction = { homeViewModel.setContentToInstall(documents) },
|
||||||
negativeAction = {})
|
negativeAction = {}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
|
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun installContent(documents: List<Uri>) {
|
private fun installContent(documents: List<Uri>) {
|
||||||
ProgressDialogFragment.newInstance(
|
ProgressDialogFragment.newInstance(
|
||||||
this@MainActivity, R.string.installing_game_content
|
this@MainActivity,
|
||||||
|
R.string.installing_game_content
|
||||||
) { progressCallback, messageCallback ->
|
) { progressCallback, messageCallback ->
|
||||||
var installSuccess = 0
|
var installSuccess = 0
|
||||||
var installOverwrite = 0
|
var installOverwrite = 0
|
||||||
|
@ -495,11 +516,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
var error = 0
|
var error = 0
|
||||||
documents.forEach {
|
documents.forEach {
|
||||||
messageCallback.invoke(FileUtil.getFilename(it))
|
messageCallback.invoke(FileUtil.getFilename(it))
|
||||||
when (InstallResult.from(
|
when (
|
||||||
|
InstallResult.from(
|
||||||
NativeLibrary.installFileToNand(
|
NativeLibrary.installFileToNand(
|
||||||
it.toString(), progressCallback
|
it.toString(),
|
||||||
|
progressCallback
|
||||||
)
|
)
|
||||||
)) {
|
)
|
||||||
|
) {
|
||||||
InstallResult.Success -> {
|
InstallResult.Success -> {
|
||||||
installSuccess += 1
|
installSuccess += 1
|
||||||
}
|
}
|
||||||
|
@ -525,7 +549,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
if (installSuccess > 0) {
|
if (installSuccess > 0) {
|
||||||
installResult.append(
|
installResult.append(
|
||||||
getString(
|
getString(
|
||||||
R.string.install_game_content_success_install, installSuccess
|
R.string.install_game_content_success_install,
|
||||||
|
installSuccess
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
installResult.append(separator)
|
installResult.append(separator)
|
||||||
|
@ -533,7 +558,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
if (installOverwrite > 0) {
|
if (installOverwrite > 0) {
|
||||||
installResult.append(
|
installResult.append(
|
||||||
getString(
|
getString(
|
||||||
R.string.install_game_content_success_overwrite, installOverwrite
|
R.string.install_game_content_success_overwrite,
|
||||||
|
installOverwrite
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
installResult.append(separator)
|
installResult.append(separator)
|
||||||
|
@ -543,7 +569,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
installResult.append(separator)
|
installResult.append(separator)
|
||||||
installResult.append(
|
installResult.append(
|
||||||
getString(
|
getString(
|
||||||
R.string.install_game_content_failed_count, errorTotal
|
R.string.install_game_content_failed_count,
|
||||||
|
errorTotal
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
installResult.append(separator)
|
installResult.append(separator)
|
||||||
|
@ -584,7 +611,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressDialogFragment.newInstance(
|
ProgressDialogFragment.newInstance(
|
||||||
this, R.string.exporting_user_data, true
|
this,
|
||||||
|
R.string.exporting_user_data,
|
||||||
|
true
|
||||||
) { progressCallback, _ ->
|
) { progressCallback, _ ->
|
||||||
val zipResult = FileUtil.zipFromInternalStorage(
|
val zipResult = FileUtil.zipFromInternalStorage(
|
||||||
File(DirectoryInitialization.userDirectory!!),
|
File(DirectoryInitialization.userDirectory!!),
|
||||||
|
@ -608,7 +637,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressDialogFragment.newInstance(
|
ProgressDialogFragment.newInstance(
|
||||||
this, R.string.importing_user_data
|
this,
|
||||||
|
R.string.importing_user_data
|
||||||
) { progressCallback, _ ->
|
) { progressCallback, _ ->
|
||||||
val checkStream =
|
val checkStream =
|
||||||
ZipInputStream(BufferedInputStream(contentResolver.openInputStream(result)))
|
ZipInputStream(BufferedInputStream(contentResolver.openInputStream(result)))
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -197,7 +200,9 @@ object FileUtil {
|
||||||
*/
|
*/
|
||||||
fun getFilename(uri: Uri): String {
|
fun getFilename(uri: Uri): String {
|
||||||
if (uri.scheme == "file") {
|
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
|
val resolver = YuzuApplication.appContext.contentResolver
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.utils
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
@ -17,7 +16,6 @@ object PowerStateUpdater {
|
||||||
private var isStarted = false
|
private var isStarted = false
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
|
|
||||||
if (isStarted) {
|
if (isStarted) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ object PowerStateUtils {
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getBatteryInfo(context: Context?): IntArray {
|
fun getBatteryInfo(context: Context?): IntArray {
|
||||||
|
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
return intArrayOf(0, 0, 0) // Percentage, IsCharging, HasBattery
|
return intArrayOf(0, 0, 0) // Percentage, IsCharging, HasBattery
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,12 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
|
|
||||||
object ThemeHelper {
|
object ThemeHelper {
|
||||||
const val SYSTEM_BAR_ALPHA = 0.9f
|
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
|
// 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 var listener: SharedPreferences.OnSharedPreferenceChangeListener? = null
|
||||||
private val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
private val preferences = PreferenceManager.getDefaultSharedPreferences(
|
||||||
|
YuzuApplication.appContext
|
||||||
|
)
|
||||||
|
|
||||||
fun setTheme(activity: AppCompatActivity) {
|
fun setTheme(activity: AppCompatActivity) {
|
||||||
setThemeMode(activity)
|
setThemeMode(activity)
|
||||||
|
@ -52,6 +54,7 @@ object ThemeHelper {
|
||||||
private fun getSelectedStaticThemeColor(): Int {
|
private fun getSelectedStaticThemeColor(): Int {
|
||||||
val themeIndex = preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0)
|
val themeIndex = preferences.getInt(Settings.PREF_STATIC_THEME_COLOR, 0)
|
||||||
val themes = arrayOf(
|
val themes = arrayOf(
|
||||||
|
R.style.Theme_Eden_Main,
|
||||||
R.style.Theme_Yuzu_Main_Violet,
|
R.style.Theme_Yuzu_Main_Violet,
|
||||||
R.style.Theme_Yuzu_Main_Blue,
|
R.style.Theme_Yuzu_Main_Blue,
|
||||||
R.style.Theme_Yuzu_Main_Cyan,
|
R.style.Theme_Yuzu_Main_Cyan,
|
||||||
|
@ -120,7 +123,11 @@ object ThemeHelper {
|
||||||
|
|
||||||
fun ThemeChangeListener(activity: AppCompatActivity) {
|
fun ThemeChangeListener(activity: AppCompatActivity) {
|
||||||
listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
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) {
|
if (key in relevantKeys) {
|
||||||
activity.recreate()
|
activity.recreate()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// 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
|
package org.yuzu.yuzu_emu.ui
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -53,7 +56,7 @@ class CarouselRecyclerView @JvmOverloads constructor(
|
||||||
|
|
||||||
var flingMultiplier: Float = 1f
|
var flingMultiplier: Float = 1f
|
||||||
|
|
||||||
public var pendingScrollAfterReload: Boolean = false
|
var pendingScrollAfterReload: Boolean = false
|
||||||
|
|
||||||
var useCustomDrawingOrder: Boolean = false
|
var useCustomDrawingOrder: Boolean = false
|
||||||
set(value) {
|
set(value) {
|
||||||
|
@ -76,7 +79,11 @@ class CarouselRecyclerView @JvmOverloads constructor(
|
||||||
|
|
||||||
private fun getLayoutManagerCenter(layoutManager: RecyclerView.LayoutManager): Int {
|
private fun getLayoutManagerCenter(layoutManager: RecyclerView.LayoutManager): Int {
|
||||||
return if (layoutManager is LinearLayoutManager) {
|
return if (layoutManager is LinearLayoutManager) {
|
||||||
calculateCenter(layoutManager.width, layoutManager.paddingStart, layoutManager.paddingEnd)
|
calculateCenter(
|
||||||
|
layoutManager.width,
|
||||||
|
layoutManager.paddingStart,
|
||||||
|
layoutManager.paddingEnd
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
width / 2
|
width / 2
|
||||||
}
|
}
|
||||||
|
@ -143,20 +150,36 @@ class CarouselRecyclerView @JvmOverloads constructor(
|
||||||
val center = getRecyclerViewCenter()
|
val center = getRecyclerViewCenter()
|
||||||
val distance = abs(getChildDistanceToCenter(child))
|
val distance = abs(getChildDistanceToCenter(child))
|
||||||
val internalBorderScale = resources.getFraction(R.fraction.carousel_bordercards_scale, 1, 1)
|
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 shapeInput = (distance / center).coerceIn(0f, 1f)
|
||||||
val internalShapeSetting = resources.getInteger(R.integer.carousel_cards_scaling_shape)
|
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 shapedScaling = shapingFunction(shapeInput, scalingShapeSetting)
|
||||||
val scale = (borderScale + (1f - borderScale) * shapedScaling).coerceIn(0f, 1f)
|
val scale = (borderScale + (1f - borderScale) * shapedScaling).coerceIn(0f, 1f)
|
||||||
|
|
||||||
val maxDistance = width / 2f
|
val maxDistance = width / 2f
|
||||||
val alphaInput = (distance / maxDistance).coerceIn(0f, 1f)
|
val alphaInput = (distance / maxDistance).coerceIn(0f, 1f)
|
||||||
val internalBordersAlpha = resources.getFraction(R.fraction.carousel_bordercards_alpha, 1, 1)
|
val internalBordersAlpha = resources.getFraction(
|
||||||
val borderAlpha = preferences.getFloat(CAROUSEL_BORDERCARDS_ALPHA, internalBordersAlpha).coerceIn(0f, 1f)
|
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 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 shapedAlpha = shapingFunction(alphaInput, alphaShapeSetting)
|
||||||
val alpha = (borderAlpha + (1f - borderAlpha) * shapedAlpha).coerceIn(0f, 1f)
|
val alpha = (borderAlpha + (1f - borderAlpha) * shapedAlpha).coerceIn(0f, 1f)
|
||||||
|
|
||||||
|
@ -185,16 +208,33 @@ class CarouselRecyclerView @JvmOverloads constructor(
|
||||||
val insets = rootWindowInsets
|
val insets = rootWindowInsets
|
||||||
val bottomInset = insets?.getInsets(android.view.WindowInsets.Type.systemBars())?.bottom ?: 0
|
val bottomInset = insets?.getInsets(android.view.WindowInsets.Type.systemBars())?.bottom ?: 0
|
||||||
val internalFactor = resources.getFraction(R.fraction.carousel_card_size_factor, 1, 1)
|
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()
|
val cardSize = (userFactor * (height - bottomInset)).toInt()
|
||||||
gameAdapter?.setCardSize(cardSize)
|
gameAdapter?.setCardSize(cardSize)
|
||||||
|
|
||||||
val internalOverlapFactor = resources.getFraction(R.fraction.carousel_overlap_factor, 1, 1)
|
val internalOverlapFactor = resources.getFraction(
|
||||||
overlapFactor = preferences.getFloat(CAROUSEL_OVERLAP_FACTOR, internalOverlapFactor).coerceIn(0f, 1f)
|
R.fraction.carousel_overlap_factor,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
overlapFactor = preferences.getFloat(CAROUSEL_OVERLAP_FACTOR, internalOverlapFactor).coerceIn(
|
||||||
|
0f,
|
||||||
|
1f
|
||||||
|
)
|
||||||
overlapPx = (cardSize * overlapFactor).toInt()
|
overlapPx = (cardSize * overlapFactor).toInt()
|
||||||
|
|
||||||
val internalFlingMultiplier = resources.getFraction(R.fraction.carousel_fling_multiplier, 1, 1)
|
val internalFlingMultiplier = resources.getFraction(
|
||||||
flingMultiplier = preferences.getFloat(CAROUSEL_FLING_MULTIPLIER, internalFlingMultiplier).coerceIn(1f, 5f)
|
R.fraction.carousel_fling_multiplier,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
flingMultiplier = preferences.getFloat(
|
||||||
|
CAROUSEL_FLING_MULTIPLIER,
|
||||||
|
internalFlingMultiplier
|
||||||
|
).coerceIn(1f, 5f)
|
||||||
|
|
||||||
gameAdapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
gameAdapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||||
override fun onChanged() {
|
override fun onChanged() {
|
||||||
|
@ -290,20 +330,28 @@ class CarouselRecyclerView @JvmOverloads constructor(
|
||||||
View.FOCUS_LEFT -> {
|
View.FOCUS_LEFT -> {
|
||||||
if (position > 0) {
|
if (position > 0) {
|
||||||
val now = System.currentTimeMillis()
|
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
|
lastFocusSearchTime = now
|
||||||
if (!repeatDetected) { // ensures the first run
|
if (!repeatDetected) { // ensures the first run
|
||||||
val offset = focused.width - overlapPx
|
val offset = focused.width - overlapPx
|
||||||
smoothScrollBy(-offset, 0)
|
smoothScrollBy(-offset, 0)
|
||||||
}
|
}
|
||||||
findViewHolderForAdapterPosition(position - 1)?.itemView ?: super.focusSearch(focused, direction)
|
findViewHolderForAdapterPosition(position - 1)?.itemView ?: super.focusSearch(
|
||||||
|
focused,
|
||||||
|
direction
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
focused
|
focused
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
View.FOCUS_RIGHT -> {
|
View.FOCUS_RIGHT -> {
|
||||||
if (position < itemCount - 1) {
|
if (position < itemCount - 1) {
|
||||||
findViewHolderForAdapterPosition(position + 1)?.itemView ?: super.focusSearch(focused, direction)
|
findViewHolderForAdapterPosition(position + 1)?.itemView ?: super.focusSearch(
|
||||||
|
focused,
|
||||||
|
direction
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
focused
|
focused
|
||||||
}
|
}
|
||||||
|
@ -341,7 +389,10 @@ class CarouselRecyclerView @JvmOverloads constructor(
|
||||||
|
|
||||||
inner class OverlappingDecoration(private val overlap: Int) : ItemDecoration() {
|
inner class OverlappingDecoration(private val overlap: Int) : ItemDecoration() {
|
||||||
override fun getItemOffsets(
|
override fun getItemOffsets(
|
||||||
outRect: Rect, view: View, parent: RecyclerView, state: State
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: State
|
||||||
) {
|
) {
|
||||||
val position = parent.getChildAdapterPosition(view)
|
val position = parent.getChildAdapterPosition(view)
|
||||||
if (position > 0) {
|
if (position > 0) {
|
||||||
|
@ -383,7 +434,12 @@ class CarouselRecyclerView @JvmOverloads constructor(
|
||||||
layoutManager: RecyclerView.LayoutManager,
|
layoutManager: RecyclerView.LayoutManager,
|
||||||
targetView: View
|
targetView: View
|
||||||
): IntArray? {
|
): IntArray? {
|
||||||
if (layoutManager !is LinearLayoutManager) return super.calculateDistanceToFinalSnap(layoutManager, targetView)
|
if (layoutManager !is LinearLayoutManager) {
|
||||||
|
return super.calculateDistanceToFinalSnap(
|
||||||
|
layoutManager,
|
||||||
|
targetView
|
||||||
|
)
|
||||||
|
}
|
||||||
val out = IntArray(2)
|
val out = IntArray(2)
|
||||||
out[0] = getChildDistanceToCenter(targetView).toInt()
|
out[0] = getChildDistanceToCenter(targetView).toInt()
|
||||||
out[1] = 0
|
out[1] = 0
|
||||||
|
@ -399,10 +455,13 @@ class CarouselRecyclerView @JvmOverloads constructor(
|
||||||
if (layoutManager !is LinearLayoutManager) return RecyclerView.NO_POSITION
|
if (layoutManager !is LinearLayoutManager) return RecyclerView.NO_POSITION
|
||||||
val closestPosition = this@CarouselRecyclerView.getClosestChildPosition()
|
val closestPosition = this@CarouselRecyclerView.getClosestChildPosition()
|
||||||
val internalMaxFling = resources.getInteger(R.integer.carousel_max_fling_count)
|
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 rawFlingCount = if (velocityX == 0) 0 else velocityX / 2000
|
||||||
val flingCount = rawFlingCount.coerceIn(-maxFling, maxFling)
|
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
|
return targetPos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/card_game_carousel"
|
android:id="@+id/card_game_carousel"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:cardCornerRadius="8dp"
|
app:cardCornerRadius="16dp"
|
||||||
app:cardElevation="4dp"
|
app:cardElevation="0dp"
|
||||||
|
app:cardPreventCornerOverlap="true"
|
||||||
|
android:clipChildren="true"
|
||||||
android:layout_margin="0dp"
|
android:layout_margin="0dp"
|
||||||
app:strokeColor="@android:color/transparent"
|
app:cardBackgroundColor="@color/eden_card_background"
|
||||||
app:strokeWidth="0dp"
|
app:strokeWidth="1dp"
|
||||||
android:alpha="0">
|
app:strokeColor="@color/eden_border">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:padding="4dp">
|
android:padding="4dp">
|
||||||
|
|
||||||
<ImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/image_game_screen"
|
android:id="@+id/image_game_screen"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:contentDescription="@string/game_image_desc"
|
android:contentDescription="@string/game_image_desc"
|
||||||
|
app:shapeAppearanceOverlay="@style/ShapeAppearance.Eden.CarouselImage"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -43,4 +46,4 @@
|
||||||
android:text="Game Title" />
|
android:text="Game Title" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</org.yuzu.yuzu_emu.views.GradientBorderCardView>
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface"
|
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
@ -44,7 +43,10 @@
|
||||||
style="?attr/materialCardViewFilledStyle"
|
style="?attr/materialCardViewFilledStyle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
app:cardCornerRadius="21dp"
|
app:cardCornerRadius="24dp"
|
||||||
|
app:cardBackgroundColor="?attr/colorSurfaceVariant"
|
||||||
|
app:strokeColor="?attr/colorOutline"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -100,6 +102,9 @@
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
app:cardCornerRadius="21dp"
|
app:cardCornerRadius="21dp"
|
||||||
|
app:cardBackgroundColor="@color/eden_surface_variant"
|
||||||
|
app:strokeColor="@color/eden_border"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -123,6 +128,9 @@
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
app:cardCornerRadius="21dp"
|
app:cardCornerRadius="21dp"
|
||||||
|
app:cardBackgroundColor="@color/eden_surface_variant"
|
||||||
|
app:strokeColor="@color/eden_border"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -146,6 +154,9 @@
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
app:cardCornerRadius="21dp"
|
app:cardCornerRadius="21dp"
|
||||||
|
app:cardBackgroundColor="@color/eden_surface_variant"
|
||||||
|
app:strokeColor="@color/eden_border"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -210,9 +221,9 @@
|
||||||
app:icon="@drawable/ic_cartridge_outline"
|
app:icon="@drawable/ic_cartridge_outline"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:textColor="?attr/colorOnPrimaryContainer"
|
android:textColor="?attr/colorOnPrimary"
|
||||||
app:backgroundTint="?attr/colorPrimaryContainer"
|
app:backgroundTint="?attr/colorPrimary"
|
||||||
app:iconTint="?attr/colorOnPrimaryContainer"
|
app:iconTint="?attr/colorOnPrimary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -6,7 +6,7 @@
|
||||||
android:id="@+id/coordinator_main"
|
android:id="@+id/coordinator_main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface">
|
android:background="@drawable/eden_background_gradient">
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/fragment_container"
|
android:id="@+id/fragment_container"
|
||||||
|
|
|
@ -5,14 +5,16 @@
|
||||||
android:id="@+id/coordinator_about"
|
android:id="@+id/coordinator_about"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface">
|
>
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbar_about"
|
android:id="@+id/appbar_about"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
android:touchscreenBlocksFocus="false">
|
android:touchscreenBlocksFocus="false"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
app:elevation="0dp">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/toolbar_about"
|
android:id="@+id/toolbar_about"
|
||||||
|
@ -37,33 +39,42 @@
|
||||||
android:id="@+id/content_about"
|
android:id="@+id/content_about"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/image_logo"
|
android:id="@+id/image_logo"
|
||||||
android:layout_width="200dp"
|
android:layout_width="200dp"
|
||||||
android:layout_height="200dp"
|
android:layout_height="200dp"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_vertical"
|
||||||
android:padding="20dp"
|
android:layout_marginEnd="32dp"
|
||||||
android:src="@drawable/ic_yuzu_title" />
|
android:src="@drawable/ic_yuzu_title" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:cardCornerRadius="16dp"
|
||||||
|
app:cardBackgroundColor="?attr/colorSurface"
|
||||||
|
app:strokeColor="?attr/colorOutline"
|
||||||
|
app:strokeWidth="1dp"
|
||||||
|
app:cardElevation="0dp">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="24dp"
|
||||||
android:paddingVertical="16dp">
|
android:paddingVertical="20dp">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:text="@string/about"
|
android:text="@string/about"
|
||||||
android:textAlignment="viewStart" />
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
|
@ -71,32 +82,36 @@
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/TextAppearance.Material3.BodyMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:text="@string/about_app_description"
|
android:text="@string/about_app_description"
|
||||||
android:textAlignment="viewStart" />
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.divider.MaterialDivider
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_contributors"
|
android:id="@+id/button_contributors"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackground"
|
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:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="24dp"
|
||||||
android:paddingVertical="16dp">
|
android:paddingVertical="20dp">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:text="@string/contributors"
|
android:text="@string/contributors"
|
||||||
android:textAlignment="viewStart" />
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
|
@ -104,32 +119,36 @@
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/TextAppearance.Material3.BodyMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:text="@string/contributors_description"
|
android:text="@string/contributors_description"
|
||||||
android:textAlignment="viewStart" />
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.divider.MaterialDivider
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_licenses"
|
android:id="@+id/button_licenses"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackground"
|
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:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="24dp"
|
||||||
android:paddingVertical="16dp">
|
android:paddingVertical="20dp">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:text="@string/licenses"
|
android:text="@string/licenses"
|
||||||
android:textAlignment="viewStart" />
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
|
@ -137,32 +156,36 @@
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/TextAppearance.Material3.BodyMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:text="@string/licenses_description"
|
android:text="@string/licenses_description"
|
||||||
android:textAlignment="viewStart" />
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.divider.MaterialDivider
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_version_name"
|
android:id="@+id/button_version_name"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?attr/selectableItemBackground"
|
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:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="24dp"
|
||||||
android:paddingVertical="16dp">
|
android:paddingVertical="20dp">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:text="@string/build"
|
android:text="@string/build"
|
||||||
android:textAlignment="viewStart" />
|
android:textAlignment="viewStart" />
|
||||||
|
|
||||||
|
@ -171,59 +194,51 @@
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/TextAppearance.Material3.BodyMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
tools:text="abc123" />
|
tools:text="abc123" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
<com.google.android.material.divider.MaterialDivider
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="40dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginTop="12dp"
|
android:gravity="start"
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_discord"
|
android:id="@+id/button_discord"
|
||||||
style="?attr/materialIconButtonStyle"
|
style="@style/EdenButton.Secondary"
|
||||||
android:layout_width="0dp"
|
android:layout_width="56dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="56dp"
|
||||||
android:layout_weight="1"
|
android:layout_marginEnd="12dp"
|
||||||
app:icon="@drawable/ic_discord"
|
app:icon="@drawable/ic_discord"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textStart"
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconTint="?attr/colorOnSurface" />
|
app:iconPadding="0dp" />
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_website"
|
android:id="@+id/button_website"
|
||||||
style="?attr/materialIconButtonStyle"
|
style="@style/EdenButton.Secondary"
|
||||||
android:layout_width="0dp"
|
android:layout_width="56dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="56dp"
|
||||||
android:layout_weight="1"
|
android:layout_marginEnd="12dp"
|
||||||
app:icon="@drawable/ic_website"
|
app:icon="@drawable/ic_website"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textStart"
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconTint="?attr/colorOnSurface" />
|
app:iconPadding="0dp" />
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_github"
|
android:id="@+id/button_github"
|
||||||
style="?attr/materialIconButtonStyle"
|
style="@style/EdenButton.Secondary"
|
||||||
android:layout_width="0dp"
|
android:layout_width="56dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="56dp"
|
||||||
android:layout_weight="1"
|
|
||||||
app:icon="@drawable/ic_github"
|
app:icon="@drawable/ic_github"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textStart"
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconTint="?attr/colorOnSurface" />
|
app:iconPadding="0dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_next"
|
android:id="@+id/button_next"
|
||||||
style="@style/Widget.Material3.Button.TextButton"
|
style="@style/EdenButton.Primary"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/next"
|
android:text="@string/next"
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_back"
|
android:id="@+id/button_back"
|
||||||
style="@style/Widget.Material3.Button.TextButton"
|
style="@style/EdenButton.Secondary"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/back"
|
android:text="@string/back"
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_action"
|
android:id="@+id/button_action"
|
||||||
|
style="@style/EdenButton.Primary"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
android:id="@+id/coordinator_main"
|
android:id="@+id/coordinator_main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface">
|
android:background="?android:attr/colorBackground">
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/fragment_container"
|
android:id="@+id/fragment_container"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
style="?attr/materialCardViewOutlinedStyle"
|
style="@style/EdenCard"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
|
|
|
@ -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:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/card_game_carousel"
|
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_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:cardCornerRadius="8dp"
|
app:cardCornerRadius="16dp"
|
||||||
app:cardElevation="4dp"
|
app:cardPreventCornerOverlap="true"
|
||||||
android:layout_margin="4dp"
|
android:clipChildren="true"
|
||||||
app:strokeColor="@android:color/transparent"
|
android:layout_margin="4dp">
|
||||||
app:strokeWidth="0dp">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:padding="8dp">
|
android:padding="8dp">
|
||||||
|
|
||||||
<ImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/image_game_screen"
|
android:id="@+id/image_game_screen"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
android:contentDescription="@string/game_image_desc"
|
android:contentDescription="@string/game_image_desc"
|
||||||
|
app:shapeAppearanceOverlay="@style/ShapeAppearance.Eden.CarouselImage"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -29,12 +33,14 @@
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_game_title"
|
android:id="@+id/text_game_title"
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/SynthwaveText.Body"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:requiresFadingEdge="horizontal"
|
android:requiresFadingEdge="horizontal"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/image_game_screen"
|
app:layout_constraintTop_toBottomOf="@+id/image_game_screen"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -42,4 +48,4 @@
|
||||||
android:text="Game Title" />
|
android:text="Game Title" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</org.yuzu.yuzu_emu.views.GradientBorderCardView>
|
||||||
|
|
|
@ -3,22 +3,24 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
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"
|
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_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:clipToPadding="true"
|
android:clipToPadding="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:transitionName="card_game"
|
android:transitionName="card_game"
|
||||||
app:cardCornerRadius="4dp"
|
app:cardCornerRadius="16dp">
|
||||||
app:cardBackgroundColor="@android:color/transparent"
|
|
||||||
app:cardElevation="0dp">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -33,17 +35,19 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium"
|
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
tools:src="@drawable/default_icon" />
|
tools:src="@drawable/default_icon" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_game_title"
|
android:id="@+id/text_game_title"
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/SynthwaveText.Body"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:requiresFadingEdge="horizontal"
|
android:requiresFadingEdge="horizontal"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
app:layout_constraintEnd_toEndOf="@+id/image_game_screen"
|
app:layout_constraintEnd_toEndOf="@+id/image_game_screen"
|
||||||
app:layout_constraintStart_toStartOf="@+id/image_game_screen"
|
app:layout_constraintStart_toStartOf="@+id/image_game_screen"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/image_game_screen"
|
app:layout_constraintTop_toBottomOf="@+id/image_game_screen"
|
||||||
|
@ -51,6 +55,6 @@
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</org.yuzu.yuzu_emu.views.GradientBorderCardView>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/card_game_list"
|
android:id="@+id/card_game_list"
|
||||||
style="?attr/materialCardViewStyle"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:transitionName="card_game"
|
android:transitionName="card_game"
|
||||||
app:cardCornerRadius="14dp"
|
app:cardCornerRadius="16dp"
|
||||||
app:cardElevation="0dp">
|
app:cardElevation="0dp"
|
||||||
|
app:cardBackgroundColor="@color/eden_card_background"
|
||||||
|
app:strokeWidth="0dp">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_game_title"
|
android:id="@+id/text_game_title"
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/SynthwaveText.Body"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/text_game_developer"
|
app:layout_constraintBottom_toTopOf="@+id/text_game_developer"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/image_game_screen"
|
app:layout_constraintStart_toEndOf="@+id/image_game_screen"
|
||||||
|
@ -48,7 +49,7 @@
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_game_developer"
|
android:id="@+id/text_game_developer"
|
||||||
style="@style/TextAppearance.Material3.BodySmall"
|
style="@style/SynthwaveText.Body"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
|
@ -56,6 +57,7 @@
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
|
android:alpha="0.7"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@+id/image_game_screen"
|
app:layout_constraintStart_toEndOf="@+id/image_game_screen"
|
||||||
|
@ -64,4 +66,4 @@
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</org.yuzu.yuzu_emu.views.GradientBorderCardView>
|
||||||
|
|
|
@ -2,16 +2,15 @@
|
||||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
style="?attr/materialCardViewStyle"
|
style="@style/EdenCard"
|
||||||
android:id="@+id/option_card"
|
android:id="@+id/option_card"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:layout_marginHorizontal="12dp"
|
android:layout_marginHorizontal="8dp"
|
||||||
android:background="?attr/colorSurface"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:cardElevation="0dp">
|
app:cardCornerRadius="16dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/option_layout"
|
android:id="@+id/option_layout"
|
||||||
|
@ -25,7 +24,7 @@
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
app:tint="?attr/colorOnSurface" />
|
app:tint="?attr/colorPrimary" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -35,7 +34,7 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/SynthwaveText.Body"
|
||||||
android:id="@+id/option_title"
|
android:id="@+id/option_title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -45,17 +44,18 @@
|
||||||
tools:text="@string/install_prod_keys" />
|
tools:text="@string/install_prod_keys" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.BodySmall"
|
style="@style/SynthwaveText.Body"
|
||||||
android:id="@+id/option_description"
|
android:id="@+id/option_description"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
|
android:alpha="0.8"
|
||||||
tools:text="@string/install_prod_keys_description" />
|
tools:text="@string/install_prod_keys_description" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.LabelMedium"
|
style="@style/SynthwaveText.Secondary"
|
||||||
android:id="@+id/option_detail"
|
android:id="@+id/option_detail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
style="?attr/materialCardViewOutlinedStyle"
|
style="@style/EdenCard"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
|
|
|
@ -6,14 +6,15 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
app:strokeWidth="0dp"
|
app:strokeWidth="0dp"
|
||||||
app:cardCornerRadius="24dp">
|
app:cardCornerRadius="24dp"
|
||||||
|
android:background="@drawable/theme_dialog_background">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:background="?colorSurface">
|
android:background="@android:color/transparent">
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="128dp"
|
android:layout_width="128dp"
|
||||||
|
|
|
@ -5,14 +5,16 @@
|
||||||
android:id="@+id/coordinator_about"
|
android:id="@+id/coordinator_about"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface">
|
>
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbar_about"
|
android:id="@+id/appbar_about"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
android:touchscreenBlocksFocus="false">
|
android:touchscreenBlocksFocus="false"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
app:elevation="0dp">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/toolbar_about"
|
android:id="@+id/toolbar_about"
|
||||||
|
@ -37,7 +39,8 @@
|
||||||
android:id="@+id/content_about"
|
android:id="@+id/content_about"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="24dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/image_logo"
|
android:id="@+id/image_logo"
|
||||||
|
@ -48,89 +51,94 @@
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:src="@drawable/ic_yuzu_title" />
|
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_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="20dp" />
|
android:layout_marginHorizontal="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:cardCornerRadius="16dp">
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingVertical="16dp"
|
android:paddingVertical="20dp"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="20dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/SynthwaveText.Header"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:text="@string/about" />
|
android:text="@string/about" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/SynthwaveText.Body"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:text="@string/about_app_description" />
|
android:text="@string/about_app_description" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.divider.MaterialDivider
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_contributors"
|
android:id="@+id/button_contributors"
|
||||||
|
style="@style/EdenCard"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingVertical="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:paddingHorizontal="16dp"
|
android:layout_marginTop="12dp"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
app:cardCornerRadius="16dp">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="20dp"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/SynthwaveText.Header"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:text="@string/contributors" />
|
android:text="@string/contributors" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/SynthwaveText.Body"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:text="@string/contributors_description" />
|
android:text="@string/contributors_description" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.divider.MaterialDivider
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_licenses"
|
android:id="@+id/button_licenses"
|
||||||
|
style="@style/EdenCard"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingVertical="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:paddingHorizontal="16dp"
|
android:layout_marginTop="12dp"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
app:cardCornerRadius="16dp">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingVertical="20dp"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:text="@string/licenses" />
|
android:text="@string/licenses" />
|
||||||
|
|
||||||
|
@ -138,32 +146,37 @@
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/TextAppearance.Material3.BodyMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:text="@string/licenses_description" />
|
android:text="@string/licenses_description" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.divider.MaterialDivider
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_version_name"
|
android:id="@+id/button_version_name"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingVertical="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:paddingHorizontal="16dp"
|
android:layout_marginTop="12dp"
|
||||||
android:background="?attr/selectableItemBackground"
|
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:paddingVertical="20dp"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
android:text="@string/build" />
|
android:text="@string/build" />
|
||||||
|
|
||||||
|
@ -172,59 +185,57 @@
|
||||||
style="@style/TextAppearance.Material3.BodyMedium"
|
style="@style/TextAppearance.Material3.BodyMedium"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginTop="6dp"
|
android:layout_marginTop="6dp"
|
||||||
android:textAlignment="viewStart"
|
android:textAlignment="viewStart"
|
||||||
tools:text="abc123" />
|
tools:text="abc123" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
<com.google.android.material.divider.MaterialDivider
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="20dp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:layout_marginHorizontal="40dp">
|
android:layout_marginHorizontal="40dp">
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
style="?attr/materialIconButtonStyle"
|
style="@style/EdenButton.Secondary"
|
||||||
android:id="@+id/button_discord"
|
android:id="@+id/button_discord"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="56dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
app:icon="@drawable/ic_discord"
|
app:icon="@drawable/ic_discord"
|
||||||
app:iconTint="?attr/colorOnSurface"
|
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconGravity="textEnd" />
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp" />
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
style="?attr/materialIconButtonStyle"
|
style="@style/EdenButton.Secondary"
|
||||||
android:id="@+id/button_website"
|
android:id="@+id/button_website"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="56dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginHorizontal="4dp"
|
||||||
app:icon="@drawable/ic_website"
|
app:icon="@drawable/ic_website"
|
||||||
app:iconTint="?attr/colorOnSurface"
|
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconGravity="textEnd" />
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp" />
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_github"
|
android:id="@+id/button_github"
|
||||||
style="?attr/materialIconButtonStyle"
|
style="@style/EdenButton.Secondary"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="56dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
app:icon="@drawable/ic_github"
|
app:icon="@drawable/ic_github"
|
||||||
app:iconTint="?attr/colorOnSurface"
|
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconGravity="textEnd" />
|
app:iconGravity="textStart"
|
||||||
|
app:iconPadding="0dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface"
|
|
||||||
>
|
>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -21,9 +20,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/app_name"
|
android:text="@string/app_name"
|
||||||
android:textAppearance="@style/TextAppearance.Material3.HeadlineLarge"
|
style="@style/SynthwaveText.Title"
|
||||||
android:textSize="27sp"
|
android:textSize="27sp"
|
||||||
android:textStyle="bold"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
|
@ -34,10 +32,11 @@
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/view_button"
|
android:id="@+id/view_button"
|
||||||
style="?attr/materialCardViewFilledStyle"
|
style="@style/EdenCard"
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
app:cardCornerRadius="21dp"
|
app:cardCornerRadius="21dp"
|
||||||
|
android:padding="8dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -45,7 +44,7 @@
|
||||||
android:layout_height="18dp"
|
android:layout_height="18dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:src="@drawable/ic_eye"
|
android:src="@drawable/ic_eye"
|
||||||
app:tint="?attr/colorOnSurfaceVariant"
|
app:tint="?attr/colorSecondary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
@ -57,10 +56,11 @@
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/filter_button"
|
android:id="@+id/filter_button"
|
||||||
style="?attr/materialCardViewFilledStyle"
|
style="@style/EdenCard"
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
app:cardCornerRadius="21dp"
|
app:cardCornerRadius="21dp"
|
||||||
|
android:padding="8dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -80,10 +80,11 @@
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/settings_button"
|
android:id="@+id/settings_button"
|
||||||
style="?attr/materialCardViewFilledStyle"
|
style="@style/EdenCard"
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
app:cardCornerRadius="21dp"
|
app:cardCornerRadius="21dp"
|
||||||
|
android:padding="8dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -91,7 +92,7 @@
|
||||||
android:layout_height="18dp"
|
android:layout_height="18dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:src="@drawable/ic_settings"
|
android:src="@drawable/ic_settings"
|
||||||
app:tint="?attr/colorOnSurfaceVariant"
|
app:tint="?attr/colorTertiary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
@ -111,10 +112,11 @@
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/search_background"
|
android:id="@+id/search_background"
|
||||||
style="?attr/materialCardViewFilledStyle"
|
style="@style/EdenCard"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
app:cardCornerRadius="21dp"
|
app:cardCornerRadius="24dp"
|
||||||
|
android:padding="4dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -132,7 +134,7 @@
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_marginEnd="18dp"
|
android:layout_marginEnd="18dp"
|
||||||
android:src="@drawable/ic_search"
|
android:src="@drawable/ic_search"
|
||||||
app:tint="?attr/colorOnSurfaceVariant"
|
app:tint="?attr/colorSecondary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
@ -144,6 +146,9 @@
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:imeOptions="flagNoFullscreen"
|
android:imeOptions="flagNoFullscreen"
|
||||||
|
android:textColor="?attr/colorOnBackground"
|
||||||
|
android:textColorHint="?attr/colorOnSurfaceVariant"
|
||||||
|
android:fontFamily="monospace"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -186,6 +191,7 @@
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:padding="@dimen/spacing_large"
|
android:padding="@dimen/spacing_large"
|
||||||
android:text="@string/empty_gamelist"
|
android:text="@string/empty_gamelist"
|
||||||
|
android:textColor="?attr/colorOnBackground"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -216,9 +222,9 @@
|
||||||
app:icon="@drawable/ic_cartridge_outline"
|
app:icon="@drawable/ic_cartridge_outline"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:textColor="?attr/colorOnPrimaryContainer"
|
android:textColor="?attr/colorOnPrimary"
|
||||||
app:backgroundTint="?attr/colorPrimaryContainer"
|
app:backgroundTint="?attr/colorPrimary"
|
||||||
app:iconTint="?attr/colorOnPrimaryContainer"
|
app:iconTint="?attr/colorOnPrimary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -4,7 +4,6 @@
|
||||||
android:id="@+id/scroll_view_settings"
|
android:id="@+id/scroll_view_settings"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/colorSurface"
|
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
android:fadeScrollbars="false"
|
android:fadeScrollbars="false"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
|
@ -15,21 +14,21 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:background="?attr/colorSurface"
|
android:paddingHorizontal="16dp">
|
||||||
android:paddingHorizontal="8dp">
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/logo_image"
|
android:id="@+id/logo_image"
|
||||||
android:layout_width="96dp"
|
android:layout_width="120dp"
|
||||||
android:layout_height="96dp"
|
android:layout_height="120dp"
|
||||||
android:layout_marginVertical="32dp"
|
android:layout_marginVertical="48dp"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:src="@drawable/ic_yuzu_full" />
|
android:src="@drawable/ic_yuzu_full" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/home_settings_list"
|
android:id="@+id/home_settings_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false" />
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
|
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
|
||||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||||
app:contentScrim="?attr/colorOnSurfaceInverse"
|
app:contentScrim="?attr/colorSurface"
|
||||||
app:scrimVisibleHeightTrigger="100dp">
|
app:scrimVisibleHeightTrigger="100dp">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_next"
|
android:id="@+id/button_next"
|
||||||
style="@style/Widget.Material3.Button.TextButton"
|
style="@style/EdenButton.Primary"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/next"
|
android:text="@string/next"
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_back"
|
android:id="@+id/button_back"
|
||||||
style="@style/Widget.Material3.Button.TextButton"
|
style="@style/EdenButton.Secondary"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/back"
|
android:text="@string/back"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="@drawable/theme_list_item_selector"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
android:id="@+id/setting_body"
|
android:id="@+id/setting_body"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="@drawable/theme_list_item_selector"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="@drawable/theme_list_item_selector"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:minHeight="72dp"
|
android:minHeight="72dp"
|
||||||
|
|
|
@ -26,12 +26,10 @@
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_title"
|
android:id="@+id/text_title"
|
||||||
style="@style/TextAppearance.Material3.DisplaySmall"
|
style="@style/SynthwaveText.Header"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:textColor="?attr/colorOnSurface"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toTopOf="@+id/text_description"
|
app:layout_constraintBottom_toTopOf="@+id/text_description"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
@ -41,7 +39,7 @@
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_description"
|
android:id="@+id/text_description"
|
||||||
style="@style/TextAppearance.Material3.TitleLarge"
|
style="@style/SynthwaveText.Body"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
|
@ -57,7 +55,7 @@
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/text_confirmation"
|
android:id="@+id/text_confirmation"
|
||||||
style="@style/TextAppearance.Material3.TitleLarge"
|
style="@style/SynthwaveText.Accent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:paddingHorizontal="16dp"
|
android:paddingHorizontal="16dp"
|
||||||
|
@ -66,7 +64,6 @@
|
||||||
android:textSize="30sp"
|
android:textSize="30sp"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
android:text="@string/step_complete"
|
android:text="@string/step_complete"
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
@ -76,6 +73,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_action"
|
android:id="@+id/button_action"
|
||||||
|
style="@style/EdenButton.Primary"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
|
|
|
@ -155,8 +155,8 @@
|
||||||
<string name="shader_backend">خلفية Shader</string>
|
<string name="shader_backend">خلفية Shader</string>
|
||||||
<string name="shader_backend_description">اختيار طريقة ترجمة Shaders</string>
|
<string name="shader_backend_description">اختيار طريقة ترجمة Shaders</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">محاكاة NVDEC</string>
|
<string name="nvdec_emulation">محاكاة NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">شادەر باکند</string>
|
<string name="shader_backend">شادەر باکند</string>
|
||||||
<string name="shader_backend_description">هەڵبژاردنی ڕێگای پێکهێنانی شادەر</string>
|
<string name="shader_backend_description">هەڵبژاردنی ڕێگای پێکهێنانی شادەر</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">ئیمولەیشنی NVDEC</string>
|
<string name="nvdec_emulation">ئیمولەیشنی NVDEC</string>
|
||||||
|
|
|
@ -152,8 +152,8 @@
|
||||||
<string name="shader_backend">Backend shaderů</string>
|
<string name="shader_backend">Backend shaderů</string>
|
||||||
<string name="shader_backend_description">Způsob kompilace shaderů</string>
|
<string name="shader_backend_description">Způsob kompilace shaderů</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Emulace NVDEC</string>
|
<string name="nvdec_emulation">Emulace NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Shader-Backend</string>
|
<string name="shader_backend">Shader-Backend</string>
|
||||||
<string name="shader_backend_description">Methode zur Shader-Kompilierung</string>
|
<string name="shader_backend_description">Methode zur Shader-Kompilierung</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">NVDEC-Emulation</string>
|
<string name="nvdec_emulation">NVDEC-Emulation</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Backend de shaders</string>
|
<string name="shader_backend">Backend de shaders</string>
|
||||||
<string name="shader_backend_description">Elegir cómo se compilan 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_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Emulación NVDEC</string>
|
<string name="nvdec_emulation">Emulación NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">بکاند شیدر</string>
|
<string name="shader_backend">بکاند شیدر</string>
|
||||||
<string name="shader_backend_description">انتخاب روش کامپایل و ترجمه شیدرها</string>
|
<string name="shader_backend_description">انتخاب روش کامپایل و ترجمه شیدرها</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">شبیهسازی NVDEC</string>
|
<string name="nvdec_emulation">شبیهسازی NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Backend shader</string>
|
<string name="shader_backend">Backend shader</string>
|
||||||
<string name="shader_backend_description">Méthode de compilation</string>
|
<string name="shader_backend_description">Méthode de compilation</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Émulation NVDEC</string>
|
<string name="nvdec_emulation">Émulation NVDEC</string>
|
||||||
|
|
|
@ -154,8 +154,8 @@
|
||||||
<string name="shader_backend">מנוע שיידרים</string>
|
<string name="shader_backend">מנוע שיידרים</string>
|
||||||
<string name="shader_backend_description">בחר כיצד לקמפל שיידרים</string>
|
<string name="shader_backend_description">בחר כיצד לקמפל שיידרים</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">אמולציית NVDEC</string>
|
<string name="nvdec_emulation">אמולציית NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Shader backend</string>
|
<string name="shader_backend">Shader backend</string>
|
||||||
<string name="shader_backend_description">Shaderek fordításának módja</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_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">NVDEC emuláció</string>
|
<string name="nvdec_emulation">NVDEC emuláció</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Backend Shader</string>
|
<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_description">Pilih cara shader dikompilasi dan diterjemahkan untuk GPU Anda.</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Emulasi NVDEC</string>
|
<string name="nvdec_emulation">Emulasi NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Backend shader</string>
|
<string name="shader_backend">Backend shader</string>
|
||||||
<string name="shader_backend_description">Scegli come compilare gli shader</string>
|
<string name="shader_backend_description">Scegli come compilare gli shader</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Emulazione NVDEC</string>
|
<string name="nvdec_emulation">Emulazione NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">シェーダーバックエンド</string>
|
<string name="shader_backend">シェーダーバックエンド</string>
|
||||||
<string name="shader_backend_description">シェーダーのコンパイル方法</string>
|
<string name="shader_backend_description">シェーダーのコンパイル方法</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">NVDECエミュレーション</string>
|
<string name="nvdec_emulation">NVDECエミュレーション</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">셰이더 백엔드</string>
|
<string name="shader_backend">셰이더 백엔드</string>
|
||||||
<string name="shader_backend_description">셰이더 컴파일 방식 선택</string>
|
<string name="shader_backend_description">셰이더 컴파일 방식 선택</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">NVDEC 에뮬레이션</string>
|
<string name="nvdec_emulation">NVDEC 에뮬레이션</string>
|
||||||
<string name="nvdec_emulation_description">비디오 디코딩 처리 방식 선택</string>
|
<string name="nvdec_emulation_description">비디오 디코딩 처리 방식 선택</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Shader-backend</string>
|
<string name="shader_backend">Shader-backend</string>
|
||||||
<string name="shader_backend_description">Velg hvordan shadere kompileres</string>
|
<string name="shader_backend_description">Velg hvordan shadere kompileres</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">NVDEC-emulering</string>
|
<string name="nvdec_emulation">NVDEC-emulering</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Backend shaderów</string>
|
<string name="shader_backend">Backend shaderów</string>
|
||||||
<string name="shader_backend_description">Wybierz metodę kompilacji 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_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Emulacja NVDEC</string>
|
<string name="nvdec_emulation">Emulacja NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Backend de shader</string>
|
<string name="shader_backend">Backend de shader</string>
|
||||||
<string name="shader_backend_description">Define como shaders são compilados</string>
|
<string name="shader_backend_description">Define como shaders são compilados</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Emulação NVDEC</string>
|
<string name="nvdec_emulation">Emulação NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Backend de Shader</string>
|
<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_description">Método de compilação de shaders.</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Emulação NVDEC</string>
|
<string name="nvdec_emulation">Emulação NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Шейдерный бэкенд</string>
|
<string name="shader_backend">Шейдерный бэкенд</string>
|
||||||
<string name="shader_backend_description">Метод компиляции шейдеров</string>
|
<string name="shader_backend_description">Метод компиляции шейдеров</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Эмуляция NVDEC</string>
|
<string name="nvdec_emulation">Эмуляция NVDEC</string>
|
||||||
|
|
|
@ -118,8 +118,8 @@
|
||||||
<string name="shader_backend">Схадер Бацкенд</string>
|
<string name="shader_backend">Схадер Бацкенд</string>
|
||||||
<string name="shader_backend_description">Изаберите како се сјеначици саставе и преведете за ваш ГПУ.</string>
|
<string name="shader_backend_description">Изаберите како се сјеначици саставе и преведете за ваш ГПУ.</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">НВДЕЦ Емулација</string>
|
<string name="nvdec_emulation">НВДЕЦ Емулација</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Система обробки шейдерів</string>
|
<string name="shader_backend">Система обробки шейдерів</string>
|
||||||
<string name="shader_backend_description">Спосіб компіляції шейдерів</string>
|
<string name="shader_backend_description">Спосіб компіляції шейдерів</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Емуляція NVDEC</string>
|
<string name="nvdec_emulation">Емуляція NVDEC</string>
|
||||||
|
|
|
@ -153,8 +153,8 @@
|
||||||
<string name="shader_backend">Backend Shader</string>
|
<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_description">Chọn cách biên dịch shader</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">Giả lập NVDEC</string>
|
<string name="nvdec_emulation">Giả lập NVDEC</string>
|
||||||
|
|
|
@ -152,8 +152,8 @@
|
||||||
<string name="shader_backend">着色器后端</string>
|
<string name="shader_backend">着色器后端</string>
|
||||||
<string name="shader_backend_description">选择着色器编译方式</string>
|
<string name="shader_backend_description">选择着色器编译方式</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">NVDEC模拟</string>
|
<string name="nvdec_emulation">NVDEC模拟</string>
|
||||||
|
|
|
@ -156,8 +156,8 @@
|
||||||
<string name="shader_backend">著色器後端</string>
|
<string name="shader_backend">著色器後端</string>
|
||||||
<string name="shader_backend_description">選擇著色器的編譯與轉譯方式</string>
|
<string name="shader_backend_description">選擇著色器的編譯與轉譯方式</string>
|
||||||
<string name="shader_backend_glsl">GLSL</string>
|
<string name="shader_backend_glsl">GLSL</string>
|
||||||
<string name="shader_backend_glasm">GLASM</string>string>
|
<string name="shader_backend_glasm">GLASM</string>
|
||||||
<string name="shader_backend_spirv">Spir-V</string>string>
|
<string name="shader_backend_spirv">Spir-V</string>
|
||||||
|
|
||||||
<!-- NVDEC Emulation -->
|
<!-- NVDEC Emulation -->
|
||||||
<string name="nvdec_emulation">NVDEC模擬</string>
|
<string name="nvdec_emulation">NVDEC模擬</string>
|
||||||
|
|
|
@ -389,6 +389,7 @@
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="staticThemeNames">
|
<string-array name="staticThemeNames">
|
||||||
|
<item>@string/eden_theme</item>
|
||||||
<item>@string/violet</item>
|
<item>@string/violet</item>
|
||||||
<item>@string/blue</item>
|
<item>@string/blue</item>
|
||||||
<item>@string/cyan</item>
|
<item>@string/cyan</item>
|
||||||
|
@ -409,6 +410,7 @@
|
||||||
<item>6</item>
|
<item>6</item>
|
||||||
<item>7</item>
|
<item>7</item>
|
||||||
<item>8</item>
|
<item>8</item>
|
||||||
|
<item>9</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<string-array name="anisoEntries">
|
<string-array name="anisoEntries">
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue