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