Compare commits

..

12 Commits

Author SHA1 Message Date
1c5e43502a Android 254 2024-02-18 00:57:06 +00:00
2d4ae8dce6 Merge yuzu-emu#13048 2024-02-18 00:57:06 +00:00
6a1bb4430c Merge yuzu-emu#13035 2024-02-18 00:57:06 +00:00
a1ff7c92bf Merge yuzu-emu#13034 2024-02-18 00:57:06 +00:00
b6121c8c97 Merge yuzu-emu#13032 2024-02-18 00:57:06 +00:00
ae9140a715 Merge yuzu-emu#13030 2024-02-18 00:57:06 +00:00
7a10fdd2f2 Merge yuzu-emu#13026 2024-02-18 00:57:06 +00:00
3007032b12 Merge yuzu-emu#13006 2024-02-18 00:57:06 +00:00
fb34d40a1c Merge yuzu-emu#13000 2024-02-18 00:57:05 +00:00
abcb021211 Merge yuzu-emu#12749 2024-02-18 00:57:05 +00:00
807fbad23c Merge yuzu-emu#12461 2024-02-18 00:57:05 +00:00
7a1e249314 Merge yuzu-emu#10529 2024-02-18 00:57:05 +00:00
293 changed files with 6068 additions and 7542 deletions

View File

@ -1,14 +1,16 @@
| Pull Request | Commit | Title | Author | Merged? | | Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----| |----|----|----|----|----|
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`2831f5dc6`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes | | [10529](https://github.com/yuzu-emu/yuzu//pull/10529) | [`368bf2211`](https://github.com/yuzu-emu/yuzu//pull/10529/files) | caches: make critical reclamation less eager and possible in more cases | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`acc26667b`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes | | [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13073](https://github.com/yuzu-emu/yuzu//pull/13073) | [`b5a17b501`](https://github.com/yuzu-emu/yuzu//pull/13073/files) | fsp: Migrate remaining interfaces to cmif serialization | [FearlessTobi](https://github.com/FearlessTobi/) | Yes | | [13000](https://github.com/yuzu-emu/yuzu//pull/13000) | [`461eaca7e`](https://github.com/yuzu-emu/yuzu//pull/13000/files) | device_memory_manager: skip unregistered interfaces on invalidate | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13081](https://github.com/yuzu-emu/yuzu//pull/13081) | [`197c4d325`](https://github.com/yuzu-emu/yuzu//pull/13081/files) | aoc: Migrate to use cmif serialization | [FearlessTobi](https://github.com/FearlessTobi/) | Yes | | [13006](https://github.com/yuzu-emu/yuzu//pull/13006) | [`3067bfd12`](https://github.com/yuzu-emu/yuzu//pull/13006/files) | buffer_cache: use mapped range with large vertex buffer size | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13096](https://github.com/yuzu-emu/yuzu//pull/13096) | [`0a8759057`](https://github.com/yuzu-emu/yuzu//pull/13096/files) | texture_cache: use two-pass collection for costly load resources | [liamwhite](https://github.com/liamwhite/) | Yes | | [13026](https://github.com/yuzu-emu/yuzu//pull/13026) | [`462ea921e`](https://github.com/yuzu-emu/yuzu//pull/13026/files) | shader_recompiler: fix non-const offset for arrayed image types | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13100](https://github.com/yuzu-emu/yuzu//pull/13100) | [`c04567fad`](https://github.com/yuzu-emu/yuzu//pull/13100/files) | audio: move to new ipc | [liamwhite](https://github.com/liamwhite/) | Yes | | [13030](https://github.com/yuzu-emu/yuzu//pull/13030) | [`4cbafc1ef`](https://github.com/yuzu-emu/yuzu//pull/13030/files) | service: audio: Rewrite IAudioController to new IPC | [german77](https://github.com/german77/) | Yes |
| [13115](https://github.com/yuzu-emu/yuzu//pull/13115) | [`89c2fd3d2`](https://github.com/yuzu-emu/yuzu//pull/13115/files) | olsc, pctl: move to new ipc | [liamwhite](https://github.com/liamwhite/) | Yes | | [13032](https://github.com/yuzu-emu/yuzu//pull/13032) | [`ec02a1cfe`](https://github.com/yuzu-emu/yuzu//pull/13032/files) | service: Implement functions needed by Qlaunch | [german77](https://github.com/german77/) | Yes |
| [13116](https://github.com/yuzu-emu/yuzu//pull/13116) | [`54ed837ad`](https://github.com/yuzu-emu/yuzu//pull/13116/files) | android: Flip AB/XY for 8Bitdo controllers | [t895](https://github.com/t895/) | Yes | | [13034](https://github.com/yuzu-emu/yuzu//pull/13034) | [`50ecad547`](https://github.com/yuzu-emu/yuzu//pull/13034/files) | android: Input mapping | [t895](https://github.com/t895/) | Yes |
| [13117](https://github.com/yuzu-emu/yuzu//pull/13117) | [`e85466c1a`](https://github.com/yuzu-emu/yuzu//pull/13117/files) | psc: stub overlay notification channel | [liamwhite](https://github.com/liamwhite/) | Yes | | [13035](https://github.com/yuzu-emu/yuzu//pull/13035) | [`a07f0883b`](https://github.com/yuzu-emu/yuzu//pull/13035/files) | vi: manage resources independently of nvnflinger and refactor | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13048](https://github.com/yuzu-emu/yuzu//pull/13048) | [`72d806db0`](https://github.com/yuzu-emu/yuzu//pull/13048/files) | ns: rewrite for new IPC | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break. End of merge log. You can find the original README.md below the break.

View File

@ -121,7 +121,6 @@ else()
-Wno-attributes -Wno-attributes
-Wno-invalid-offsetof -Wno-invalid-offsetof
-Wno-unused-parameter -Wno-unused-parameter
-Wno-missing-field-initializers
) )
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang

View File

@ -3,21 +3,24 @@
package org.yuzu.yuzu_emu package org.yuzu.yuzu_emu
import android.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.net.Uri import android.net.Uri
import android.os.Bundle
import android.text.Html import android.text.Html
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.view.Surface import android.view.Surface
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.annotation.Keep import androidx.annotation.Keep
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
import org.yuzu.yuzu_emu.utils.DocumentsTree import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
import org.yuzu.yuzu_emu.model.InstallResult import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.Patch import org.yuzu.yuzu_emu.model.Patch
import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.model.GameVerificationResult
@ -181,13 +184,46 @@ object NativeLibrary {
ErrorUnknown ErrorUnknown
} }
var coreErrorAlertResult = false private var coreErrorAlertResult = false
val coreErrorAlertLock = Object() private val coreErrorAlertLock = Object()
class CoreErrorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val title = requireArguments().serializable<String>("title")
val message = requireArguments().serializable<String>("message")
return MaterialAlertDialogBuilder(requireActivity())
.setTitle(title)
.setMessage(message)
.setPositiveButton(R.string.continue_button, null)
.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
coreErrorAlertResult = false
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
}
.create()
}
override fun onDismiss(dialog: DialogInterface) {
coreErrorAlertResult = true
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
}
companion object {
fun newInstance(title: String?, message: String?): CoreErrorDialogFragment {
val frag = CoreErrorDialogFragment()
val args = Bundle()
args.putString("title", title)
args.putString("message", message)
frag.arguments = args
return frag
}
}
}
private fun onCoreErrorImpl(title: String, message: String) { private fun onCoreErrorImpl(title: String, message: String) {
val emulationActivity = sEmulationActivity.get() val emulationActivity = sEmulationActivity.get()
if (emulationActivity == null) { if (emulationActivity == null) {
Log.error("[NativeLibrary] EmulationActivity not present") error("[NativeLibrary] EmulationActivity not present")
return return
} }
@ -203,7 +239,7 @@ object NativeLibrary {
fun onCoreError(error: CoreError?, details: String): Boolean { fun onCoreError(error: CoreError?, details: String): Boolean {
val emulationActivity = sEmulationActivity.get() val emulationActivity = sEmulationActivity.get()
if (emulationActivity == null) { if (emulationActivity == null) {
Log.error("[NativeLibrary] EmulationActivity not present") error("[NativeLibrary] EmulationActivity not present")
return false return false
} }
@ -234,7 +270,7 @@ object NativeLibrary {
} }
// Show the AlertDialog on the main thread. // Show the AlertDialog on the main thread.
emulationActivity.runOnUiThread { onCoreErrorImpl(title, message) } emulationActivity.runOnUiThread(Runnable { onCoreErrorImpl(title, message) })
// Wait for the lock to notify that it is complete. // Wait for the lock to notify that it is complete.
synchronized(coreErrorAlertLock) { coreErrorAlertLock.wait() } synchronized(coreErrorAlertLock) { coreErrorAlertLock.wait() }

View File

@ -80,14 +80,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
InputHandler.updateControllerData() InputHandler.updateControllerData()
val players = NativeConfig.getInputSettings(true) val playerOne = NativeConfig.getInputSettings(true)[0]
var hasConfiguredControllers = false if (!playerOne.hasMapping() && InputHandler.androidControllers.isNotEmpty()) {
players.forEach {
if (it.hasMapping()) {
hasConfiguredControllers = true
}
}
if (!hasConfiguredControllers && InputHandler.androidControllers.isNotEmpty()) {
var params: ParamPackage? = null var params: ParamPackage? = null
for (controller in InputHandler.registeredControllers) { for (controller in InputHandler.registeredControllers) {
if (controller.get("port", -1) == 0) { if (controller.get("port", -1) == 0) {

View File

@ -3,15 +3,15 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding
import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.model.Driver import org.yuzu.yuzu_emu.model.Driver
import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class DriverAdapter(private val driverViewModel: DriverViewModel) : class DriverAdapter(private val driverViewModel: DriverViewModel) :
@ -44,15 +44,25 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
} }
// Delay marquee by 3s // Delay marquee by 3s
title.marquee() title.postDelayed(
version.marquee() {
description.marquee() title.isSelected = true
title.ellipsize = TextUtils.TruncateAt.MARQUEE
version.isSelected = true
version.ellipsize = TextUtils.TruncateAt.MARQUEE
description.isSelected = true
description.ellipsize = TextUtils.TruncateAt.MARQUEE
},
3000
)
title.text = model.title title.text = model.title
version.text = model.version version.text = model.version
description.text = model.description description.text = model.description
buttonDelete.setVisible( if (model.title != binding.root.context.getString(R.string.system_gpu_driver)) {
model.title != binding.root.context.getString(R.string.system_gpu_driver) buttonDelete.visibility = View.VISIBLE
) } else {
buttonDelete.visibility = View.GONE
}
} }
} }
} }

View File

@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.net.Uri import android.net.Uri
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
@ -11,7 +12,6 @@ import org.yuzu.yuzu_emu.databinding.CardFolderBinding
import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment
import org.yuzu.yuzu_emu.model.GameDir import org.yuzu.yuzu_emu.model.GameDir
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) :
@ -29,7 +29,13 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
override fun bind(model: GameDir) { override fun bind(model: GameDir) {
binding.apply { binding.apply {
path.text = Uri.parse(model.uriString).path path.text = Uri.parse(model.uriString).path
path.marquee() path.postDelayed(
{
path.isSelected = true
path.ellipsize = TextUtils.TruncateAt.MARQUEE
},
3000
)
buttonEdit.setOnClickListener { buttonEdit.setOnClickListener {
GameFolderPropertiesDialogFragment.newInstance(model) GameFolderPropertiesDialogFragment.newInstance(model)

View File

@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.net.Uri import android.net.Uri
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
@ -26,7 +27,6 @@ import org.yuzu.yuzu_emu.databinding.CardGameBinding
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class GameAdapter(private val activity: AppCompatActivity) : class GameAdapter(private val activity: AppCompatActivity) :
@ -44,7 +44,14 @@ class GameAdapter(private val activity: AppCompatActivity) :
binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ") binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ")
binding.textGameTitle.marquee() binding.textGameTitle.postDelayed(
{
binding.textGameTitle.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.textGameTitle.isSelected = true
},
3000
)
binding.cardGame.setOnClickListener { onClick(model) } binding.cardGame.setOnClickListener { onClick(model) }
binding.cardGame.setOnLongClickListener { onLongClick(model) } binding.cardGame.setOnLongClickListener { onLongClick(model) }
} }

View File

@ -3,18 +3,21 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.GameProperty import org.yuzu.yuzu_emu.model.GameProperty
import org.yuzu.yuzu_emu.model.InstallableProperty import org.yuzu.yuzu_emu.model.InstallableProperty
import org.yuzu.yuzu_emu.model.SubmenuProperty import org.yuzu.yuzu_emu.model.SubmenuProperty
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class GamePropertiesAdapter( class GamePropertiesAdapter(
@ -73,15 +76,23 @@ class GamePropertiesAdapter(
) )
) )
binding.details.marquee() binding.details.postDelayed({
binding.details.isSelected = true
binding.details.ellipsize = TextUtils.TruncateAt.MARQUEE
}, 3000)
if (submenuProperty.details != null) { if (submenuProperty.details != null) {
binding.details.setVisible(true) binding.details.visibility = View.VISIBLE
binding.details.text = submenuProperty.details.invoke() binding.details.text = submenuProperty.details.invoke()
} else if (submenuProperty.detailsFlow != null) { } else if (submenuProperty.detailsFlow != null) {
binding.details.setVisible(true) binding.details.visibility = View.VISIBLE
submenuProperty.detailsFlow.collect(viewLifecycle) { binding.details.text = it } viewLifecycle.lifecycleScope.launch {
viewLifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
submenuProperty.detailsFlow.collect { binding.details.text = it }
}
}
} else { } else {
binding.details.setVisible(false) binding.details.visibility = View.GONE
} }
} }
} }
@ -101,10 +112,14 @@ class GamePropertiesAdapter(
) )
) )
binding.buttonInstall.setVisible(installableProperty.install != null) if (installableProperty.install != null) {
binding.buttonInstall.setOnClickListener { installableProperty.install?.invoke() } binding.buttonInstall.visibility = View.VISIBLE
binding.buttonExport.setVisible(installableProperty.export != null) binding.buttonInstall.setOnClickListener { installableProperty.install.invoke() }
binding.buttonExport.setOnClickListener { installableProperty.export?.invoke() } }
if (installableProperty.export != null) {
binding.buttonExport.visibility = View.VISIBLE
binding.buttonExport.setOnClickListener { installableProperty.export.invoke() }
}
} }
} }

View File

@ -3,19 +3,22 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.model.HomeSetting import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class HomeSettingAdapter( class HomeSettingAdapter(
@ -56,8 +59,18 @@ class HomeSettingAdapter(
binding.optionIcon.alpha = 0.5f binding.optionIcon.alpha = 0.5f
} }
model.details.collect(viewLifecycle) { updateOptionDetails(it) } viewLifecycle.lifecycleScope.launch {
binding.optionDetail.marquee() viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
model.details.collect { updateOptionDetails(it) }
}
}
binding.optionDetail.postDelayed(
{
binding.optionDetail.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.optionDetail.isSelected = true
},
3000
)
binding.root.setOnClickListener { onClick(model) } binding.root.setOnClickListener { onClick(model) }
} }
@ -77,7 +90,7 @@ class HomeSettingAdapter(
private fun updateOptionDetails(detailString: String) { private fun updateOptionDetails(detailString: String) {
if (detailString.isNotEmpty()) { if (detailString.isNotEmpty()) {
binding.optionDetail.text = detailString binding.optionDetail.text = detailString
binding.optionDetail.setVisible(true) binding.optionDetail.visibility = View.VISIBLE
} }
} }
} }

View File

@ -4,10 +4,10 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import org.yuzu.yuzu_emu.databinding.CardInstallableBinding import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
import org.yuzu.yuzu_emu.model.Installable import org.yuzu.yuzu_emu.model.Installable
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class InstallableAdapter(installables: List<Installable>) : class InstallableAdapter(installables: List<Installable>) :
@ -26,10 +26,14 @@ class InstallableAdapter(installables: List<Installable>) :
binding.title.setText(model.titleId) binding.title.setText(model.titleId)
binding.description.setText(model.descriptionId) binding.description.setText(model.descriptionId)
binding.buttonInstall.setVisible(model.install != null) if (model.install != null) {
binding.buttonInstall.setOnClickListener { model.install?.invoke() } binding.buttonInstall.visibility = View.VISIBLE
binding.buttonExport.setVisible(model.export != null) binding.buttonInstall.setOnClickListener { model.install.invoke() }
binding.buttonExport.setOnClickListener { model.export?.invoke() } }
if (model.export != null) {
binding.buttonExport.visibility = View.VISIBLE
binding.buttonExport.setOnClickListener { model.export.invoke() }
}
} }
} }
} }

View File

@ -4,12 +4,12 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
import org.yuzu.yuzu_emu.model.License import org.yuzu.yuzu_emu.model.License
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) : class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) :
@ -25,7 +25,7 @@ class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<Lic
binding.apply { binding.apply {
textSettingName.text = root.context.getString(model.titleId) textSettingName.text = root.context.getString(model.titleId)
textSettingDescription.text = root.context.getString(model.descriptionId) textSettingDescription.text = root.context.getString(model.descriptionId)
textSettingValue.setVisible(false) textSettingValue.visibility = View.GONE
root.setOnClickListener { onClick(model) } root.setOnClickListener { onClick(model) }
} }

View File

@ -5,6 +5,7 @@ package org.yuzu.yuzu_emu.adapters
import android.text.Html import android.text.Html
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
@ -16,7 +17,6 @@ import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage import org.yuzu.yuzu_emu.model.SetupPage
import org.yuzu.yuzu_emu.model.StepState import org.yuzu.yuzu_emu.model.StepState
import org.yuzu.yuzu_emu.utils.ViewUtils import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) : class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
@ -30,8 +30,8 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
AbstractViewHolder<SetupPage>(binding), SetupCallback { AbstractViewHolder<SetupPage>(binding), SetupCallback {
override fun bind(model: SetupPage) { override fun bind(model: SetupPage) {
if (model.stepCompleted.invoke() == StepState.COMPLETE) { if (model.stepCompleted.invoke() == StepState.COMPLETE) {
binding.buttonAction.setVisible(visible = false, gone = false) binding.buttonAction.visibility = View.INVISIBLE
binding.textConfirmation.setVisible(true) binding.textConfirmation.visibility = View.VISIBLE
} }
binding.icon.setImageDrawable( binding.icon.setImageDrawable(

View File

@ -64,17 +64,17 @@ data class PlayerInput(
fun hasMapping(): Boolean { fun hasMapping(): Boolean {
var hasMapping = false var hasMapping = false
buttons.forEach { buttons.forEach {
if (it != "[empty]" && it.isNotEmpty()) { if (it != "[empty]") {
hasMapping = true hasMapping = true
} }
} }
analogs.forEach { analogs.forEach {
if (it != "[empty]" && it.isNotEmpty()) { if (it != "[empty]") {
hasMapping = true hasMapping = true
} }
} }
motions.forEach { motions.forEach {
if (it != "[empty]" && it.isNotEmpty()) { if (it != "[empty]") {
hasMapping = true hasMapping = true
} }
} }

View File

@ -6,8 +6,7 @@ package org.yuzu.yuzu_emu.features.settings.model
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
enum class StringSetting(override val key: String) : AbstractStringSetting { enum class StringSetting(override val key: String) : AbstractStringSetting {
DRIVER_PATH("driver_path"), DRIVER_PATH("driver_path");
DEVICE_NAME("device_name");
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal) override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)

View File

@ -16,7 +16,6 @@ import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
/** /**
@ -76,9 +75,6 @@ abstract class SettingsItem(
get() = NativeLibrary.isRunning() && !setting.global && get() = NativeLibrary.isRunning() && !setting.global &&
!NativeConfig.isPerGameConfigLoaded() !NativeConfig.isPerGameConfigLoaded()
val clearable: Boolean
get() = !setting.global && NativeConfig.isPerGameConfigLoaded()
companion object { companion object {
const val TYPE_HEADER = 0 const val TYPE_HEADER = 0
const val TYPE_SWITCH = 1 const val TYPE_SWITCH = 1
@ -91,7 +87,6 @@ abstract class SettingsItem(
const val TYPE_INPUT = 8 const val TYPE_INPUT = 8
const val TYPE_INT_SINGLE_CHOICE = 9 const val TYPE_INT_SINGLE_CHOICE = 9
const val TYPE_INPUT_PROFILE = 10 const val TYPE_INPUT_PROFILE = 10
const val TYPE_STRING_INPUT = 11
const val FASTMEM_COMBINED = "fastmem_combined" const val FASTMEM_COMBINED = "fastmem_combined"
@ -110,7 +105,6 @@ abstract class SettingsItem(
// List of all general // List of all general
val settingsItems = HashMap<String, SettingsItem>().apply { val settingsItems = HashMap<String, SettingsItem>().apply {
put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.RENDERER_USE_SPEED_LIMIT, BooleanSetting.RENDERER_USE_SPEED_LIMIT,

View File

@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
class StringInputSetting(
setting: AbstractStringSetting,
@StringRes titleId: Int = 0,
titleString: String = "",
@StringRes descriptionId: Int = 0,
descriptionString: String = ""
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
override val type = TYPE_STRING_INPUT
fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal)
fun setSelectedValue(selection: String) =
(setting as AbstractStringSetting).setString(selection)
}

View File

@ -11,13 +11,16 @@ import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogInputProfilesBinding import org.yuzu.yuzu_emu.databinding.DialogInputProfilesBinding
import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.utils.collect
class InputProfileDialogFragment : DialogFragment() { class InputProfileDialogFragment : DialogFragment() {
private var position = 0 private var position = 0
@ -107,7 +110,9 @@ class InputProfileDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
settingsViewModel.shouldShowDeleteProfileDialog.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldShowDeleteProfileDialog.collect {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
MessageDialogFragment.newInstance( MessageDialogFragment.newInstance(
activity = requireActivity(), activity = requireActivity(),
@ -125,6 +130,8 @@ class InputProfileDialogFragment : DialogFragment() {
} }
} }
} }
}
}
companion object { companion object {
const val TAG = "InputProfileDialogFragment" const val TAG = "InputProfileDialogFragment"

View File

@ -13,9 +13,14 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.navArgs import androidx.navigation.navArgs
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import java.io.IOException import java.io.IOException
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
@ -65,25 +70,41 @@ class SettingsActivity : AppCompatActivity() {
) )
} }
settingsViewModel.shouldRecreate.collect( lifecycleScope.apply {
this, launch {
resetState = { settingsViewModel.setShouldRecreate(false) } repeatOnLifecycle(Lifecycle.State.CREATED) {
) { if (it) recreate() } settingsViewModel.shouldRecreate.collectLatest {
settingsViewModel.shouldNavigateBack.collect(
this,
resetState = { settingsViewModel.setShouldNavigateBack(false) }
) { if (it) navigateBack() }
settingsViewModel.shouldShowResetSettingsDialog.collect(
this,
resetState = { settingsViewModel.setShouldShowResetSettingsDialog(false) }
) {
if (it) { if (it) {
settingsViewModel.setShouldRecreate(false)
recreate()
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldNavigateBack.collectLatest {
if (it) {
settingsViewModel.setShouldNavigateBack(false)
navigateBack()
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldShowResetSettingsDialog.collectLatest {
if (it) {
settingsViewModel.setShouldShowResetSettingsDialog(false)
ResetSettingsDialogFragment().show( ResetSettingsDialogFragment().show(
supportFragmentManager, supportFragmentManager,
ResetSettingsDialogFragment.TAG ResetSettingsDialogFragment.TAG
) )
} }
} }
}
}
}
onBackPressedDispatcher.addCallback( onBackPressedDispatcher.addCallback(
this, this,

View File

@ -85,10 +85,6 @@ class SettingsAdapter(
InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this) InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
} }
SettingsItem.TYPE_STRING_INPUT -> {
StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
else -> { else -> {
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
} }
@ -396,15 +392,6 @@ class SettingsAdapter(
popup.show() popup.show()
} }
fun onStringInputClick(item: StringInputSetting, position: Int) {
SettingsDialogFragment.newInstance(
settingsViewModel,
item,
SettingsItem.TYPE_STRING_INPUT,
position
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
}
fun onLongClick(item: SettingsItem, position: Int): Boolean { fun onLongClick(item: SettingsItem, position: Int): Boolean {
SettingsDialogFragment.newInstance( SettingsDialogFragment.newInstance(
settingsViewModel, settingsViewModel,

View File

@ -11,10 +11,13 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
@ -24,10 +27,8 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.utils.ParamPackage import org.yuzu.yuzu_emu.utils.ParamPackage
import org.yuzu.yuzu_emu.utils.collect
class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener { class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener {
private var type = 0 private var type = 0
@ -39,7 +40,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
private val settingsViewModel: SettingsViewModel by activityViewModels() private val settingsViewModel: SettingsViewModel by activityViewModels()
private lateinit var sliderBinding: DialogSliderBinding private lateinit var sliderBinding: DialogSliderBinding
private lateinit var stringInputBinding: DialogEditTextBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -134,18 +134,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
.create() .create()
} }
SettingsItem.TYPE_STRING_INPUT -> {
stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
val item = settingsViewModel.clickedItem as StringInputSetting
stringInputBinding.editText.setText(item.getSelectedValue())
MaterialAlertDialogBuilder(requireContext())
.setTitle(item.title)
.setView(stringInputBinding.root)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
.create()
}
SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
val item = settingsViewModel.clickedItem as StringSingleChoiceSetting val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
MaterialAlertDialogBuilder(requireContext()) MaterialAlertDialogBuilder(requireContext())
@ -173,7 +161,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
): View? { ): View? {
return when (type) { return when (type) {
SettingsItem.TYPE_SLIDER -> sliderBinding.root SettingsItem.TYPE_SLIDER -> sliderBinding.root
SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root
else -> super.onCreateView(inflater, container, savedInstanceState) else -> super.onCreateView(inflater, container, savedInstanceState)
} }
} }
@ -182,15 +169,21 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
when (type) { when (type) {
SettingsItem.TYPE_SLIDER -> { SettingsItem.TYPE_SLIDER -> {
settingsViewModel.sliderTextValue.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.sliderTextValue.collect {
sliderBinding.textValue.text = it sliderBinding.textValue.text = it
} }
settingsViewModel.sliderProgress.collect(viewLifecycleOwner) { }
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.sliderProgress.collect {
sliderBinding.slider.value = it.toFloat() sliderBinding.slider.value = it.toFloat()
} }
} }
} }
} }
}
}
override fun onClick(dialog: DialogInterface, which: Int) { override fun onClick(dialog: DialogInterface, which: Int) {
when (settingsViewModel.clickedItem) { when (settingsViewModel.clickedItem) {
@ -216,13 +209,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
val sliderSetting = settingsViewModel.clickedItem as SliderSetting val sliderSetting = settingsViewModel.clickedItem as SliderSetting
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
} }
is StringInputSetting -> {
val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
stringInputSetting.setSelectedValue(
(stringInputBinding.editText.text ?: "").toString()
)
}
} }
closeDialog() closeDialog()
} }

View File

@ -13,17 +13,21 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class SettingsFragment : Fragment() { class SettingsFragment : Fragment() {
private lateinit var presenter: SettingsFragmentPresenter private lateinit var presenter: SettingsFragmentPresenter
@ -59,7 +63,8 @@ class SettingsFragment : Fragment() {
return binding.root return binding.root
} }
@SuppressLint("NotifyDataSetChanged") // This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector", "NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
settingsAdapter = SettingsAdapter(this, requireContext()) settingsAdapter = SettingsAdapter(this, requireContext())
@ -95,26 +100,50 @@ class SettingsFragment : Fragment() {
settingsViewModel.setShouldNavigateBack(true) settingsViewModel.setShouldNavigateBack(true)
} }
settingsViewModel.shouldReloadSettingsList.collect( viewLifecycleOwner.lifecycleScope.apply {
viewLifecycleOwner, launch {
resetState = { settingsViewModel.setShouldReloadSettingsList(false) } repeatOnLifecycle(Lifecycle.State.CREATED) {
) { if (it) presenter.loadSettingsList() } settingsViewModel.shouldReloadSettingsList.collectLatest {
settingsViewModel.adapterItemChanged.collect( if (it) {
viewLifecycleOwner, settingsViewModel.setShouldReloadSettingsList(false)
resetState = { settingsViewModel.setAdapterItemChanged(-1) } presenter.loadSettingsList()
) { if (it != -1) settingsAdapter?.notifyItemChanged(it) } }
settingsViewModel.datasetChanged.collect( }
viewLifecycleOwner, }
resetState = { settingsViewModel.setDatasetChanged(false) } }
) { if (it) settingsAdapter?.notifyDataSetChanged() } launch {
settingsViewModel.reloadListAndNotifyDataset.collect( repeatOnLifecycle(Lifecycle.State.STARTED) {
viewLifecycleOwner, settingsViewModel.adapterItemChanged.collect {
resetState = { settingsViewModel.setReloadListAndNotifyDataset(false) } if (it != -1) {
) { if (it) presenter.loadSettingsList(true) } settingsAdapter?.notifyItemChanged(it)
settingsViewModel.shouldShowResetInputDialog.collect( settingsViewModel.setAdapterItemChanged(-1)
viewLifecycleOwner, }
resetState = { settingsViewModel.setShouldShowResetInputDialog(false) } }
) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
settingsViewModel.datasetChanged.collect {
if (it) {
settingsAdapter?.notifyDataSetChanged()
settingsViewModel.setDatasetChanged(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.reloadListAndNotifyDataset.collectLatest {
if (it) {
settingsViewModel.setReloadListAndNotifyDataset(false)
presenter.loadSettingsList(true)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldShowResetInputDialog.collectLatest {
if (it) { if (it) {
MessageDialogFragment.newInstance( MessageDialogFragment.newInstance(
activity = requireActivity(), activity = requireActivity(),
@ -126,6 +155,10 @@ class SettingsFragment : Fragment() {
}, },
negativeAction = {} negativeAction = {}
).show(parentFragmentManager, MessageDialogFragment.TAG) ).show(parentFragmentManager, MessageDialogFragment.TAG)
settingsViewModel.setShouldShowResetInputDialog(false)
}
}
}
} }
} }

View File

@ -23,7 +23,6 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.view.* import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
@ -154,7 +153,6 @@ class SettingsFragmentPresenter(
private fun addSystemSettings(sl: ArrayList<SettingsItem>) { private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
sl.apply { sl.apply {
add(StringSetting.DEVICE_NAME.key)
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
add(ShortSetting.RENDERER_SPEED_LIMIT.key) add(ShortSetting.RENDERER_SPEED_LIMIT.key)
add(BooleanSetting.USE_DOCKED_MODE.key) add(BooleanSetting.USE_DOCKED_MODE.key)
@ -780,7 +778,7 @@ class SettingsFragmentPresenter(
playerIndex: Int, playerIndex: Int,
paramName: String, paramName: String,
stick: NativeAnalog, stick: NativeAnalog,
defaultValue: Float defaultValue: Int
): AbstractIntSetting = ): AbstractIntSetting =
object : AbstractIntSetting { object : AbstractIntSetting {
val params get() = NativeInput.getStickParam(playerIndex, stick) val params get() = NativeInput.getStickParam(playerIndex, stick)
@ -788,7 +786,7 @@ class SettingsFragmentPresenter(
override val key = "" override val key = ""
override fun getInt(needsGlobal: Boolean): Int = override fun getInt(needsGlobal: Boolean): Int =
(params.get(paramName, defaultValue) * 100).toInt() (params.get(paramName, 0.15f) * 100).toInt()
override fun setInt(value: Int) { override fun setInt(value: Int) {
val tempParams = params val tempParams = params
@ -796,12 +794,12 @@ class SettingsFragmentPresenter(
NativeInput.setStickParam(playerIndex, stick, tempParams) NativeInput.setStickParam(playerIndex, stick, tempParams)
} }
override val defaultValue = (defaultValue * 100).toInt() override val defaultValue = defaultValue
override fun getValueAsString(needsGlobal: Boolean): String = override fun getValueAsString(needsGlobal: Boolean): String =
getInt(needsGlobal).toString() getInt(needsGlobal).toString()
override fun reset() = setInt(this.defaultValue) override fun reset() = setInt(defaultValue)
} }
private fun getExtraStickSettings( private fun getExtraStickSettings(
@ -811,11 +809,11 @@ class SettingsFragmentPresenter(
val stickIsController = val stickIsController =
NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog)) NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
val modifierRangeSetting = val modifierRangeSetting =
getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f) getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50)
val stickRangeSetting = val stickRangeSetting =
getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f) getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95)
val stickDeadzoneSetting = val stickDeadzoneSetting =
getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f) getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15)
val out = mutableListOf<SettingsItem>().apply { val out = mutableListOf<SettingsItem>().apply {
if (stickIsController) { if (stickIsController) {

View File

@ -15,17 +15,19 @@ import androidx.core.view.updatePadding
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.divider.MaterialDividerItemDecoration import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
import info.debatty.java.stringsimilarity.Cosine import info.debatty.java.stringsimilarity.Cosine
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class SettingsSearchFragment : Fragment() { class SettingsSearchFragment : Fragment() {
private var _binding: FragmentSettingsSearchBinding? = null private var _binding: FragmentSettingsSearchBinding? = null
@ -81,12 +83,16 @@ class SettingsSearchFragment : Fragment() {
search() search()
binding.settingsList.smoothScrollToPosition(0) binding.settingsList.smoothScrollToPosition(0)
} }
settingsViewModel.shouldReloadSettingsList.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldReloadSettingsList.collect {
if (it) { if (it) {
settingsViewModel.setShouldReloadSettingsList(false) settingsViewModel.setShouldReloadSettingsList(false)
search() search()
} }
} }
}
}
search() search()
@ -100,9 +106,10 @@ class SettingsSearchFragment : Fragment() {
private fun search() { private fun search() {
val searchTerm = binding.searchText.text.toString().lowercase() val searchTerm = binding.searchText.text.toString().lowercase()
binding.clearButton.setVisible(visible = searchTerm.isNotEmpty(), gone = false) binding.clearButton.visibility =
if (searchTerm.isEmpty()) View.INVISIBLE else View.VISIBLE
if (searchTerm.isEmpty()) { if (searchTerm.isEmpty()) {
binding.noResultsView.setVisible(visible = false, gone = false) binding.noResultsView.visibility = View.VISIBLE
settingsAdapter?.submitList(emptyList()) settingsAdapter?.submitList(emptyList())
return return
} }
@ -129,7 +136,8 @@ class SettingsSearchFragment : Fragment() {
optionalSetting optionalSetting
} }
settingsAdapter?.submitList(sortedList) settingsAdapter?.submitList(sortedList)
binding.noResultsView.setVisible(visible = sortedList.isEmpty(), gone = false) binding.noResultsView.visibility =
if (sortedList.isEmpty()) View.VISIBLE else View.INVISIBLE
} }
private fun focusSearch() { private fun focusSearch() {

View File

@ -13,7 +13,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.NativeConfig
class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -22,16 +22,27 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as DateTimeSetting setting = item as DateTimeSetting
binding.textSettingName.text = item.title binding.textSettingName.text = item.title
binding.textSettingDescription.setVisible(item.description.isNotEmpty()) if (setting.description.isNotEmpty()) {
binding.textSettingDescription.text = item.description binding.textSettingDescription.text = item.description
binding.textSettingValue.setVisible(true) binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
val epochTime = setting.getValue() val epochTime = setting.getValue()
val instant = Instant.ofEpochMilli(epochTime * 1000) val instant = Instant.ofEpochMilli(epochTime * 1000)
val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")) val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingValue.text = dateFormatter.format(zonedTime) binding.textSettingValue.text = dateFormatter.format(zonedTime)
binding.buttonClear.setVisible(setting.clearable) binding.buttonClear.visibility = if (setting.setting.global ||
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View File

@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -21,10 +20,10 @@ class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: Setti
binding.textSettingValue.text = binding.textSettingValue.text =
setting.getCurrentProfile().ifEmpty { binding.root.context.getString(R.string.not_set) } setting.getCurrentProfile().ifEmpty { binding.root.context.getString(R.string.not_set) }
binding.textSettingDescription.setVisible(false) binding.textSettingDescription.visibility = View.GONE
binding.buttonClear.setVisible(false) binding.buttonClear.visibility = View.GONE
binding.icon.setVisible(false) binding.icon.visibility = View.GONE
binding.buttonClear.setVisible(false) binding.buttonClear.visibility = View.GONE
} }
override fun onClick(clicked: View) = override fun onClick(clicked: View) =

View File

@ -12,7 +12,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.InputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.ModifierInputSetting import org.yuzu.yuzu_emu.features.settings.model.view.ModifierInputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: SettingsAdapter) : class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -23,26 +22,38 @@ class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: Setting
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
binding.textSettingValue.text = setting.getSelectedValue() binding.textSettingValue.text = setting.getSelectedValue()
when (item) { binding.buttonOptions.visibility = when (item) {
is AnalogInputSetting -> { is AnalogInputSetting -> {
val param = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) val param = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog)
binding.buttonOptions.setVisible( if (
param.get("engine", "") == "analog_from_button" || param.get("engine", "") == "analog_from_button" ||
param.has("axis_x") || param.has("axis_y") param.has("axis_x") || param.has("axis_y")
) ) {
View.VISIBLE
} else {
View.GONE
}
} }
is ButtonInputSetting -> { is ButtonInputSetting -> {
val param = NativeInput.getButtonParam(item.playerIndex, item.nativeButton) val param = NativeInput.getButtonParam(item.playerIndex, item.nativeButton)
binding.buttonOptions.setVisible( if (
param.has("code") || param.has("button") || param.has("hat") || param.has("code") || param.has("button") || param.has("hat") ||
param.has("axis") param.has("axis")
) ) {
View.VISIBLE
} else {
View.GONE
}
} }
is ModifierInputSetting -> { is ModifierInputSetting -> {
val params = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) val params = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog)
binding.buttonOptions.setVisible(params.has("modifier")) if (params.has("modifier")) {
View.VISIBLE
} else {
View.GONE
}
} }
} }

View File

@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -17,8 +16,8 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as RunnableSetting setting = item as RunnableSetting
binding.icon.setVisible(setting.iconId != 0)
if (setting.iconId != 0) { if (setting.iconId != 0) {
binding.icon.visibility = View.VISIBLE
binding.icon.setImageDrawable( binding.icon.setImageDrawable(
ResourcesCompat.getDrawable( ResourcesCompat.getDrawable(
binding.icon.resources, binding.icon.resources,
@ -26,13 +25,19 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
binding.icon.context.theme binding.icon.context.theme
) )
) )
} else {
binding.icon.visibility = View.GONE
} }
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) if (setting.description.isNotEmpty()) {
binding.textSettingDescription.text = item.description binding.textSettingDescription.setText(item.descriptionId)
binding.textSettingValue.setVisible(false) binding.textSettingDescription.visibility = View.VISIBLE
binding.buttonClear.setVisible(false) } else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.GONE
binding.buttonClear.visibility = View.GONE
setStyle(setting.isEditable, binding) setStyle(setting.isEditable, binding)
} }

View File

@ -10,7 +10,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.NativeConfig
class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -19,10 +19,14 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item setting = item
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(item.description.isNotEmpty()) if (item.description.isNotEmpty()) {
binding.textSettingDescription.text = item.description binding.textSettingDescription.text = item.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.setVisible(true) binding.textSettingValue.visibility = View.VISIBLE
when (item) { when (item) {
is SingleChoiceSetting -> { is SingleChoiceSetting -> {
val resMgr = binding.textSettingValue.context.resources val resMgr = binding.textSettingValue.context.resources
@ -44,10 +48,16 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
} }
} }
if (binding.textSettingValue.text.isEmpty()) { if (binding.textSettingValue.text.isEmpty()) {
binding.textSettingValue.setVisible(false) binding.textSettingValue.visibility = View.GONE
} }
binding.buttonClear.setVisible(setting.clearable) binding.buttonClear.visibility = if (setting.setting.global ||
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View File

@ -9,7 +9,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.NativeConfig
class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -18,16 +18,26 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as SliderSetting setting = item as SliderSetting
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(item.description.isNotEmpty()) if (item.description.isNotEmpty()) {
binding.textSettingDescription.text = setting.description binding.textSettingDescription.text = setting.description
binding.textSettingValue.setVisible(true) binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
binding.textSettingValue.text = String.format( binding.textSettingValue.text = String.format(
binding.textSettingValue.context.getString(R.string.value_with_units), binding.textSettingValue.context.getString(R.string.value_with_units),
setting.getSelectedValue(), setting.getSelectedValue(),
setting.units setting.units
) )
binding.buttonClear.setVisible(setting.clearable) binding.buttonClear.visibility = if (setting.setting.global ||
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View File

@ -1,45 +0,0 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var setting: StringInputSetting
override fun bind(item: SettingsItem) {
setting = item as StringInputSetting
binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.text = setting.description
binding.textSettingValue.setVisible(true)
binding.textSettingValue.text = setting.getSelectedValue()
binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
if (setting.isEditable) {
adapter.onStringInputClick(setting, bindingAdapterPosition)
}
}
override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) {
return adapter.onLongClick(setting, bindingAdapterPosition)
}
return false
}
}

View File

@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -17,8 +16,8 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as SubmenuSetting setting = item as SubmenuSetting
binding.icon.setVisible(setting.iconId != 0)
if (setting.iconId != 0) { if (setting.iconId != 0) {
binding.icon.visibility = View.VISIBLE
binding.icon.setImageDrawable( binding.icon.setImageDrawable(
ResourcesCompat.getDrawable( ResourcesCompat.getDrawable(
binding.icon.resources, binding.icon.resources,
@ -26,13 +25,19 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
binding.icon.context.theme binding.icon.context.theme
) )
) )
} else {
binding.icon.visibility = View.GONE
} }
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) if (setting.description.isNotEmpty()) {
binding.textSettingDescription.text = setting.description binding.textSettingDescription.text = setting.description
binding.textSettingValue.setVisible(false) binding.textSettingDescription.visibility = View.VISIBLE
binding.buttonClear.setVisible(false) } else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.GONE
binding.buttonClear.visibility = View.GONE
} }
override fun onClick(clicked: View) { override fun onClick(clicked: View) {

View File

@ -9,7 +9,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible import org.yuzu.yuzu_emu.utils.NativeConfig
class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -19,8 +19,12 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as SwitchSetting setting = item as SwitchSetting
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(setting.description.isNotEmpty()) if (setting.description.isNotEmpty()) {
binding.textSettingDescription.text = setting.description binding.textSettingDescription.text = setting.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.switchWidget.setOnCheckedChangeListener(null) binding.switchWidget.setOnCheckedChangeListener(null)
binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal) binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal)
@ -28,7 +32,13 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition) adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
} }
binding.buttonClear.setVisible(setting.clearable) binding.buttonClear.visibility = if (setting.setting.global ||
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View File

@ -3,6 +3,7 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -15,6 +16,9 @@ import androidx.core.view.updatePadding
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -28,7 +32,6 @@ import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.AddonUtil import org.yuzu.yuzu_emu.utils.AddonUtil
import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.File import java.io.File
class AddonsFragment : Fragment() { class AddonsFragment : Fragment() {
@ -57,6 +60,8 @@ class AddonsFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = false) homeViewModel.setNavigationVisibility(visible = false, animated = false)
@ -73,17 +78,27 @@ class AddonsFragment : Fragment() {
adapter = AddonAdapter(addonViewModel) adapter = AddonAdapter(addonViewModel)
} }
addonViewModel.addonList.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.addonList.collect {
(binding.listAddons.adapter as AddonAdapter).submitList(it) (binding.listAddons.adapter as AddonAdapter).submitList(it)
} }
addonViewModel.showModInstallPicker.collect( }
viewLifecycleOwner, }
resetState = { addonViewModel.showModInstallPicker(false) } launch {
) { if (it) installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) } repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.showModNoticeDialog.collect( addonViewModel.showModInstallPicker.collect {
viewLifecycleOwner, if (it) {
resetState = { addonViewModel.showModNoticeDialog(false) } installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
) { addonViewModel.showModInstallPicker(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.showModNoticeDialog.collect {
if (it) { if (it) {
MessageDialogFragment.newInstance( MessageDialogFragment.newInstance(
requireActivity(), requireActivity(),
@ -94,12 +109,14 @@ class AddonsFragment : Fragment() {
negativeAction = {}, negativeAction = {},
negativeButtonTitleId = R.string.close negativeButtonTitleId = R.string.close
).show(parentFragmentManager, MessageDialogFragment.TAG) ).show(parentFragmentManager, MessageDialogFragment.TAG)
addonViewModel.showModNoticeDialog(false)
} }
} }
addonViewModel.addonToDelete.collect( }
viewLifecycleOwner, }
resetState = { addonViewModel.setAddonToDelete(null) } launch {
) { repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.addonToDelete.collect {
if (it != null) { if (it != null) {
MessageDialogFragment.newInstance( MessageDialogFragment.newInstance(
requireActivity(), requireActivity(),
@ -108,6 +125,10 @@ class AddonsFragment : Fragment() {
positiveAction = { addonViewModel.onDeleteAddon(it) }, positiveAction = { addonViewModel.onDeleteAddon(it) },
negativeAction = {} negativeAction = {}
).show(parentFragmentManager, MessageDialogFragment.TAG) ).show(parentFragmentManager, MessageDialogFragment.TAG)
addonViewModel.setAddonToDelete(null)
}
}
}
} }
} }

View File

@ -1,47 +0,0 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
class CoreErrorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
MaterialAlertDialogBuilder(requireActivity())
.setTitle(requireArguments().getString(TITLE))
.setMessage(requireArguments().getString(MESSAGE))
.setPositiveButton(R.string.continue_button, null)
.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
NativeLibrary.coreErrorAlertResult = false
synchronized(NativeLibrary.coreErrorAlertLock) {
NativeLibrary.coreErrorAlertLock.notify()
}
}
.create()
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
NativeLibrary.coreErrorAlertResult = true
synchronized(NativeLibrary.coreErrorAlertLock) { NativeLibrary.coreErrorAlertLock.notify() }
}
companion object {
const val TITLE = "Title"
const val MESSAGE = "Message"
fun newInstance(title: String, message: String): CoreErrorDialogFragment {
val frag = CoreErrorDialogFragment()
val args = Bundle()
args.putString(TITLE, title)
args.putString(MESSAGE, message)
frag.arguments = args
return frag
}
}
}

View File

@ -3,6 +3,7 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -13,6 +14,9 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
@ -31,7 +35,6 @@ import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@ -60,6 +63,8 @@ class DriverManagerFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true) homeViewModel.setNavigationVisibility(visible = false, animated = true)
@ -84,8 +89,15 @@ class DriverManagerFragment : Fragment() {
} }
} }
driverViewModel.showClearButton.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.apply {
binding.toolbarDrivers.menu.findItem(R.id.menu_driver_use_global).isVisible = it launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
driverViewModel.showClearButton.collect {
binding.toolbarDrivers.menu
.findItem(R.id.menu_driver_use_global).isVisible = it
}
}
}
} }
} }

View File

@ -10,11 +10,14 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.collect
class DriversLoadingDialogFragment : DialogFragment() { class DriversLoadingDialogFragment : DialogFragment() {
private val driverViewModel: DriverViewModel by activityViewModels() private val driverViewModel: DriverViewModel by activityViewModels()
@ -41,7 +44,13 @@ class DriversLoadingDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) { if (it) dismiss() } viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isInteractionAllowed.collect { if (it) dismiss() }
}
}
}
} }
companion object { companion object {

View File

@ -32,6 +32,9 @@ import androidx.drawerlayout.widget.DrawerLayout
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.window.layout.FoldingFeature import androidx.window.layout.FoldingFeature
@ -39,6 +42,9 @@ import androidx.window.layout.WindowInfoTracker
import androidx.window.layout.WindowLayoutInfo import androidx.window.layout.WindowLayoutInfo
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
@ -57,7 +63,6 @@ import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.overlay.model.OverlayControl import org.yuzu.yuzu_emu.overlay.model.OverlayControl
import org.yuzu.yuzu_emu.overlay.model.OverlayLayout import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
import org.yuzu.yuzu_emu.utils.* import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import java.lang.NullPointerException import java.lang.NullPointerException
class EmulationFragment : Fragment(), SurfaceHolder.Callback { class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@ -85,6 +90,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (context is EmulationActivity) { if (context is EmulationActivity) {
emulationActivity = context emulationActivity = context
NativeLibrary.setEmulationActivity(context) NativeLibrary.setEmulationActivity(context)
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(context)
.windowLayoutInfo(context)
.collect { updateFoldableLayout(context, it) }
}
}
} else { } else {
throw IllegalStateException("EmulationFragment must have EmulationActivity parent") throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
} }
@ -155,6 +168,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
if (requireActivity().isFinishing) { if (requireActivity().isFinishing) {
@ -335,11 +350,19 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.loadingTitle.isSelected = true binding.loadingTitle.isSelected = true
binding.loadingText.isSelected = true binding.loadingText.isSelected = true
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(requireContext()) WindowInfoTracker.getOrCreate(requireContext())
.windowLayoutInfo(requireActivity()).collect(viewLifecycleOwner) { .windowLayoutInfo(requireActivity())
.collect {
updateFoldableLayout(requireActivity() as EmulationActivity, it) updateFoldableLayout(requireActivity() as EmulationActivity, it)
} }
emulationViewModel.shaderProgress.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.shaderProgress.collectLatest {
if (it > 0 && it != emulationViewModel.totalShaders.value) { if (it > 0 && it != emulationViewModel.totalShaders.value) {
binding.loadingProgressIndicator.isIndeterminate = false binding.loadingProgressIndicator.isIndeterminate = false
@ -353,16 +376,36 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.loadingProgressIndicator.isIndeterminate = true binding.loadingProgressIndicator.isIndeterminate = true
} }
} }
emulationViewModel.totalShaders.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.totalShaders.collectLatest {
binding.loadingProgressIndicator.max = it binding.loadingProgressIndicator.max = it
} }
emulationViewModel.shaderMessage.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.shaderMessage.collectLatest {
if (it.isNotEmpty()) { if (it.isNotEmpty()) {
binding.loadingText.text = it binding.loadingText.text = it
} }
} }
}
emulationViewModel.emulationStarted.collect(viewLifecycleOwner) { }
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isInteractionAllowed.collect {
if (it) {
startEmulation()
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.emulationStarted.collectLatest {
if (it) { if (it) {
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt()) binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
ViewUtils.showView(binding.surfaceInputOverlay) ViewUtils.showView(binding.surfaceInputOverlay)
@ -375,7 +418,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
updateThermalOverlay() updateThermalOverlay()
} }
} }
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.isEmulationStopping.collectLatest {
if (it) { if (it) {
binding.loadingText.setText(R.string.shutting_down) binding.loadingText.setText(R.string.shutting_down)
ViewUtils.showView(binding.loadingIndicator) ViewUtils.showView(binding.loadingIndicator)
@ -383,7 +430,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
ViewUtils.hideView(binding.showFpsText) ViewUtils.hideView(binding.showFpsText)
} }
} }
emulationViewModel.drawerOpen.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.drawerOpen.collect {
if (it) { if (it) {
binding.drawerLayout.open() binding.drawerLayout.open()
binding.inGameMenu.requestFocus() binding.inGameMenu.requestFocus()
@ -391,7 +442,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.drawerLayout.close() binding.drawerLayout.close()
} }
} }
emulationViewModel.programChanged.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.programChanged.collect {
if (it != 0) { if (it != 0) {
emulationViewModel.setEmulationStarted(false) emulationViewModel.setEmulationStarted(false)
binding.drawerLayout.close() binding.drawerLayout.close()
@ -401,7 +456,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
ViewUtils.showView(binding.loadingIndicator) ViewUtils.showView(binding.loadingIndicator)
} }
} }
emulationViewModel.emulationStopped.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.emulationStopped.collect {
if (it && emulationViewModel.programChanged.value != -1) { if (it && emulationViewModel.programChanged.value != -1) {
if (perfStatsUpdater != null) { if (perfStatsUpdater != null) {
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
@ -411,9 +470,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
emulationViewModel.setEmulationStopped(false) emulationViewModel.setEmulationStopped(false)
} }
} }
}
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) { }
if (it) startEmulation()
} }
} }
@ -442,12 +500,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.drawerLayout.close() binding.drawerLayout.close()
} }
if (showInputOverlay) { if (showInputOverlay) {
binding.surfaceInputOverlay.setVisible(visible = false, gone = false) binding.surfaceInputOverlay.visibility = View.INVISIBLE
} }
} else { } else {
binding.surfaceInputOverlay.setVisible( if (showInputOverlay && emulationViewModel.emulationStarted.value) {
showInputOverlay && emulationViewModel.emulationStarted.value binding.surfaceInputOverlay.visibility = View.VISIBLE
) } else {
binding.surfaceInputOverlay.visibility = View.INVISIBLE
}
if (!isInFoldableLayout) { if (!isInFoldableLayout) {
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
binding.surfaceInputOverlay.layout = OverlayLayout.Portrait binding.surfaceInputOverlay.layout = OverlayLayout.Portrait
@ -484,9 +544,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
private fun updateShowFpsOverlay() { private fun updateShowFpsOverlay() {
val showOverlay = BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean() if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) {
binding.showFpsText.setVisible(showOverlay)
if (showOverlay) {
val SYSTEM_FPS = 0 val SYSTEM_FPS = 0
val FPS = 1 val FPS = 1
val FRAMETIME = 2 val FRAMETIME = 2
@ -506,17 +564,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
perfStatsUpdateHandler.post(perfStatsUpdater!!) perfStatsUpdateHandler.post(perfStatsUpdater!!)
binding.showFpsText.visibility = View.VISIBLE
} else { } else {
if (perfStatsUpdater != null) { if (perfStatsUpdater != null) {
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
} }
binding.showFpsText.visibility = View.GONE
} }
} }
private fun updateThermalOverlay() { private fun updateThermalOverlay() {
val showOverlay = BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean() if (BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()) {
binding.showThermalsText.setVisible(showOverlay)
if (showOverlay) {
thermalStatsUpdater = { thermalStatsUpdater = {
if (emulationViewModel.emulationStarted.value && if (emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value !emulationViewModel.isEmulationStopping.value
@ -538,10 +596,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
thermalStatsUpdateHandler.post(thermalStatsUpdater!!) thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
binding.showThermalsText.visibility = View.VISIBLE
} else { } else {
if (thermalStatsUpdater != null) { if (thermalStatsUpdater != null) {
thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!) thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!)
} }
binding.showThermalsText.visibility = View.GONE
} }
} }
@ -810,12 +870,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
} }
binding.doneControlConfig.setVisible(true) binding.doneControlConfig.visibility = View.VISIBLE
binding.surfaceInputOverlay.setIsInEditMode(true) binding.surfaceInputOverlay.setIsInEditMode(true)
} }
private fun stopConfiguringControls() { private fun stopConfiguringControls() {
binding.doneControlConfig.setVisible(false) binding.doneControlConfig.visibility = View.GONE
binding.surfaceInputOverlay.setIsInEditMode(false) binding.surfaceInputOverlay.setIsInEditMode(false)
// Unlock the orientation if it was locked for editing // Unlock the orientation if it was locked for editing
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) { if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) {

View File

@ -13,6 +13,9 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
@ -24,7 +27,6 @@ import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class GameFoldersFragment : Fragment() { class GameFoldersFragment : Fragment() {
private var _binding: FragmentFoldersBinding? = null private var _binding: FragmentFoldersBinding? = null
@ -68,9 +70,13 @@ class GameFoldersFragment : Fragment() {
adapter = FolderAdapter(requireActivity(), gamesViewModel) adapter = FolderAdapter(requireActivity(), gamesViewModel)
} }
gamesViewModel.folders.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.folders.collect {
(binding.listFolders.adapter as FolderAdapter).submitList(it) (binding.listFolders.adapter as FolderAdapter).submitList(it)
} }
}
}
val mainActivity = requireActivity() as MainActivity val mainActivity = requireActivity() as MainActivity
binding.buttonAdd.setOnClickListener { binding.buttonAdd.setOnClickListener {

View File

@ -27,7 +27,6 @@ import org.yuzu.yuzu_emu.databinding.FragmentGameInfoBinding
import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.model.GameVerificationResult
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.GameMetadata import org.yuzu.yuzu_emu.utils.GameMetadata
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class GameInfoFragment : Fragment() { class GameInfoFragment : Fragment() {
@ -86,7 +85,7 @@ class GameInfoFragment : Fragment() {
copyToClipboard(getString(R.string.developer), args.game.developer) copyToClipboard(getString(R.string.developer), args.game.developer)
} }
} else { } else {
developer.setVisible(false) developer.visibility = View.GONE
} }
version.setHint(R.string.version) version.setHint(R.string.version)

View File

@ -3,9 +3,11 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager import android.content.pm.ShortcutManager
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -16,7 +18,9 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
@ -42,9 +46,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.MemoryUtil import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
@ -74,6 +76,8 @@ class GamePropertiesFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true) homeViewModel.setNavigationVisibility(visible = false, animated = true)
@ -103,7 +107,13 @@ class GamePropertiesFragment : Fragment() {
GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen) GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen)
binding.title.text = args.game.title binding.title.text = args.game.title
binding.title.marquee() binding.title.postDelayed(
{
binding.title.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.title.isSelected = true
},
3000
)
binding.buttonStart.setOnClickListener { binding.buttonStart.setOnClickListener {
LaunchGameDialogFragment.newInstance(args.game) LaunchGameDialogFragment.newInstance(args.game)
@ -112,14 +122,28 @@ class GamePropertiesFragment : Fragment() {
reloadList() reloadList()
homeViewModel.openImportSaves.collect( viewLifecycleOwner.lifecycleScope.apply {
viewLifecycleOwner, launch {
resetState = { homeViewModel.setOpenImportSaves(false) } repeatOnLifecycle(Lifecycle.State.STARTED) {
) { if (it) importSaves.launch(arrayOf("application/zip")) } homeViewModel.openImportSaves.collect {
homeViewModel.reloadPropertiesList.collect( if (it) {
viewLifecycleOwner, importSaves.launch(arrayOf("application/zip"))
resetState = { homeViewModel.reloadPropertiesList(false) } homeViewModel.setOpenImportSaves(false)
) { if (it) reloadList() } }
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
homeViewModel.reloadPropertiesList.collect {
if (it) {
reloadList()
homeViewModel.reloadPropertiesList(false)
}
}
}
}
}
setInsets() setInsets()
} }

View File

@ -14,6 +14,9 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
@ -32,7 +35,6 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.math.BigInteger import java.math.BigInteger
@ -73,12 +75,16 @@ class InstallableFragment : Fragment() {
binding.root.findNavController().popBackStack() binding.root.findNavController().popBackStack()
} }
homeViewModel.openImportSaves.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.openImportSaves.collect {
if (it) { if (it) {
importSaves.launch(arrayOf("application/zip")) importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false) homeViewModel.setOpenImportSaves(false)
} }
} }
}
}
val installables = listOf( val installables = listOf(
Installable( Installable(

View File

@ -13,13 +13,15 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.TaskViewModel import org.yuzu.yuzu_emu.model.TaskViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class ProgressDialogFragment : DialogFragment() { class ProgressDialogFragment : DialogFragment() {
private val taskViewModel: TaskViewModel by activityViewModels() private val taskViewModel: TaskViewModel by activityViewModels()
@ -62,7 +64,10 @@ class ProgressDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.message.isSelected = true binding.message.isSelected = true
taskViewModel.isComplete.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.isComplete.collect {
if (it) { if (it) {
dismiss() dismiss()
when (val result = taskViewModel.result.value) { when (val result = taskViewModel.result.value) {
@ -84,12 +89,20 @@ class ProgressDialogFragment : DialogFragment() {
taskViewModel.clear() taskViewModel.clear()
} }
} }
taskViewModel.cancelled.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.cancelled.collect {
if (it) { if (it) {
dialog?.setTitle(R.string.cancelling) dialog?.setTitle(R.string.cancelling)
} }
} }
taskViewModel.progress.collect(viewLifecycleOwner) { }
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.progress.collect {
if (it != 0.0) { if (it != 0.0) {
binding.progressBar.apply { binding.progressBar.apply {
isIndeterminate = false isIndeterminate = false
@ -102,11 +115,22 @@ class ProgressDialogFragment : DialogFragment() {
} }
} }
} }
taskViewModel.message.collect(viewLifecycleOwner) { }
binding.message.setVisible(it.isNotEmpty()) }
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.message.collect {
if (it.isEmpty()) {
binding.message.visibility = View.GONE
} else {
binding.message.visibility = View.VISIBLE
binding.message.text = it binding.message.text = it
} }
} }
}
}
}
}
// By default, the ProgressDialog will immediately dismiss itself upon a button being pressed. // By default, the ProgressDialog will immediately dismiss itself upon a button being pressed.
// Setting the OnClickListener again after the dialog is shown overrides this behavior. // Setting the OnClickListener again after the dialog is shown overrides this behavior.

View File

@ -3,6 +3,7 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
@ -17,9 +18,14 @@ import androidx.core.view.updatePadding
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import info.debatty.java.stringsimilarity.Jaccard import info.debatty.java.stringsimilarity.Jaccard
import info.debatty.java.stringsimilarity.JaroWinkler import info.debatty.java.stringsimilarity.JaroWinkler
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import java.util.Locale import java.util.Locale
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
@ -29,8 +35,6 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class SearchFragment : Fragment() { class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null private var _binding: FragmentSearchBinding? = null
@ -54,6 +58,8 @@ class SearchFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = true, animated = true) homeViewModel.setNavigationVisibility(visible = true, animated = true)
@ -75,18 +81,42 @@ class SearchFragment : Fragment() {
binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() } binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() }
binding.searchText.doOnTextChanged { text: CharSequence?, _: Int, _: Int, _: Int -> binding.searchText.doOnTextChanged { text: CharSequence?, _: Int, _: Int, _: Int ->
binding.clearButton.setVisible(text.toString().isNotEmpty()) if (text.toString().isNotEmpty()) {
binding.clearButton.visibility = View.VISIBLE
} else {
binding.clearButton.visibility = View.INVISIBLE
}
filterAndSearch() filterAndSearch()
} }
gamesViewModel.searchFocused.collect( viewLifecycleOwner.lifecycleScope.apply {
viewLifecycleOwner, launch {
resetState = { gamesViewModel.setSearchFocused(false) } repeatOnLifecycle(Lifecycle.State.CREATED) {
) { if (it) focusSearch() } gamesViewModel.searchFocused.collect {
gamesViewModel.games.collect(viewLifecycleOwner) { filterAndSearch() } if (it) {
gamesViewModel.searchedGames.collect(viewLifecycleOwner) { focusSearch()
gamesViewModel.setSearchFocused(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.games.collectLatest { filterAndSearch() }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.searchedGames.collect {
(binding.gridGamesSearch.adapter as GameAdapter).submitList(it) (binding.gridGamesSearch.adapter as GameAdapter).submitList(it)
binding.noResultsView.setVisible(it.isNotEmpty()) if (it.isEmpty()) {
binding.noResultsView.visibility = View.VISIBLE
} else {
binding.noResultsView.visibility = View.GONE
}
}
}
}
} }
binding.clearButton.setOnClickListener { binding.searchText.setText("") } binding.clearButton.setOnClickListener { binding.searchText.setText("") }

View File

@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.Manifest import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -22,6 +23,9 @@ import androidx.core.view.isVisible
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
@ -42,8 +46,6 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class SetupFragment : Fragment() { class SetupFragment : Fragment() {
private var _binding: FragmentSetupBinding? = null private var _binding: FragmentSetupBinding? = null
@ -75,6 +77,8 @@ class SetupFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
mainActivity = requireActivity() as MainActivity mainActivity = requireActivity() as MainActivity
@ -206,14 +210,28 @@ class SetupFragment : Fragment() {
) )
} }
homeViewModel.shouldPageForward.collect( viewLifecycleOwner.lifecycleScope.apply {
viewLifecycleOwner, launch {
resetState = { homeViewModel.setShouldPageForward(false) } repeatOnLifecycle(Lifecycle.State.CREATED) {
) { if (it) pageForward() } homeViewModel.shouldPageForward.collect {
homeViewModel.gamesDirSelected.collect( if (it) {
viewLifecycleOwner, pageForward()
resetState = { homeViewModel.setGamesDirSelected(false) } homeViewModel.setShouldPageForward(false)
) { if (it) gamesDirCallback.onStepCompleted() } }
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.gamesDirSelected.collect {
if (it) {
gamesDirCallback.onStepCompleted()
homeViewModel.setGamesDirSelected(false)
}
}
}
}
}
binding.viewPager2.apply { binding.viewPager2.apply {
adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages) adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages)
@ -274,8 +292,12 @@ class SetupFragment : Fragment() {
val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY) val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY)
hasBeenWarned = savedInstanceState.getBooleanArray(KEY_HAS_BEEN_WARNED)!! hasBeenWarned = savedInstanceState.getBooleanArray(KEY_HAS_BEEN_WARNED)!!
binding.buttonNext.setVisible(nextIsVisible) if (nextIsVisible) {
binding.buttonBack.setVisible(backIsVisible) binding.buttonNext.visibility = View.VISIBLE
}
if (backIsVisible) {
binding.buttonBack.visibility = View.VISIBLE
}
} else { } else {
hasBeenWarned = BooleanArray(pages.size) hasBeenWarned = BooleanArray(pages.size)
} }

View File

@ -28,7 +28,6 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.input.model.NativeAnalog import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
import org.yuzu.yuzu_emu.features.input.model.NativeButton import org.yuzu.yuzu_emu.features.input.model.NativeButton
import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.overlay.model.OverlayControl import org.yuzu.yuzu_emu.overlay.model.OverlayControl
@ -100,9 +99,11 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
} }
var shouldUpdateView = false var shouldUpdateView = false
val playerIndex = when (NativeInput.getStyleIndex(0)) { val playerIndex =
NpadStyleIndex.Handheld -> 8 if (NativeInput.isHandheldOnly()) {
else -> 0 NativeInput.ConsoleDevice
} else {
NativeInput.Player1Device
} }
for (button in overlayButtons) { for (button in overlayButtons) {
@ -663,7 +664,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
val overlayControlData = NativeConfig.getOverlayControlData() val overlayControlData = NativeConfig.getOverlayControlData()
overlayControlData.forEach { overlayControlData.forEach {
it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false
} }
NativeConfig.setOverlayControlData(overlayControlData) NativeConfig.setOverlayControlData(overlayControlData)

View File

@ -3,6 +3,7 @@
package org.yuzu.yuzu_emu.ui package org.yuzu.yuzu_emu.ui
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -13,16 +14,19 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.GameAdapter import org.yuzu.yuzu_emu.adapters.GameAdapter
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class GamesFragment : Fragment() { class GamesFragment : Fragment() {
private var _binding: FragmentGamesBinding? = null private var _binding: FragmentGamesBinding? = null
@ -40,6 +44,8 @@ class GamesFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = true, animated = true) homeViewModel.setNavigationVisibility(visible = true, animated = true)
@ -82,28 +88,49 @@ class GamesFragment : Fragment() {
} }
} }
gamesViewModel.isReloading.collect(viewLifecycleOwner) { viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.isReloading.collect {
binding.swipeRefresh.isRefreshing = it binding.swipeRefresh.isRefreshing = it
binding.noticeText.setVisible( if (gamesViewModel.games.value.isEmpty() && !it) {
visible = gamesViewModel.games.value.isEmpty() && !it, binding.noticeText.visibility = View.VISIBLE
gone = false } else {
) binding.noticeText.visibility = View.INVISIBLE
} }
gamesViewModel.games.collect(viewLifecycleOwner) { }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.games.collectLatest {
(binding.gridGames.adapter as GameAdapter).submitList(it) (binding.gridGames.adapter as GameAdapter).submitList(it)
} }
gamesViewModel.shouldSwapData.collect( }
viewLifecycleOwner, }
resetState = { gamesViewModel.setShouldSwapData(false) } launch {
) { repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.shouldSwapData.collect {
if (it) { if (it) {
(binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value) (binding.gridGames.adapter as GameAdapter).submitList(
gamesViewModel.games.value
)
gamesViewModel.setShouldSwapData(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.shouldScrollToTop.collect {
if (it) {
scrollToTop()
gamesViewModel.setShouldScrollToTop(false)
}
}
}
} }
} }
gamesViewModel.shouldScrollToTop.collect(
viewLifecycleOwner,
resetState = { gamesViewModel.setShouldScrollToTop(false) }
) { if (it) scrollToTop() }
setInsets() setInsets()
} }

View File

@ -19,6 +19,9 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
@ -27,6 +30,7 @@ import com.google.android.material.color.MaterialColors
import com.google.android.material.navigation.NavigationBarView import com.google.android.material.navigation.NavigationBarView
import java.io.File import java.io.File
import java.io.FilenameFilter import java.io.FilenameFilter
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
@ -43,7 +47,6 @@ import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.TaskState import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.model.TaskViewModel import org.yuzu.yuzu_emu.model.TaskViewModel
import org.yuzu.yuzu_emu.utils.* import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
@ -136,22 +139,41 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
// Prevents navigation from being drawn for a short time on recreation if set to hidden // Prevents navigation from being drawn for a short time on recreation if set to hidden
if (!homeViewModel.navigationVisible.value.first) { if (!homeViewModel.navigationVisible.value.first) {
binding.navigationView.setVisible(visible = false, gone = false) binding.navigationView.visibility = View.INVISIBLE
binding.statusBarShade.setVisible(visible = false, gone = false) binding.statusBarShade.visibility = View.INVISIBLE
} }
homeViewModel.navigationVisible.collect(this) { showNavigation(it.first, it.second) } lifecycleScope.apply {
homeViewModel.statusBarShadeVisible.collect(this) { showStatusBarShade(it) } launch {
homeViewModel.contentToInstall.collect( repeatOnLifecycle(Lifecycle.State.CREATED) {
this, homeViewModel.navigationVisible.collect { showNavigation(it.first, it.second) }
resetState = { homeViewModel.setContentToInstall(null) } }
) { }
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.statusBarShadeVisible.collect { showStatusBarShade(it) }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.contentToInstall.collect {
if (it != null) { if (it != null) {
installContent(it) installContent(it)
homeViewModel.setContentToInstall(null)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.checkKeys.collect {
if (it) {
checkKeys()
homeViewModel.setCheckKeys(false)
}
}
} }
} }
homeViewModel.checkKeys.collect(this, resetState = { homeViewModel.setCheckKeys(false) }) {
if (it) checkKeys()
} }
setInsets() setInsets()
@ -192,14 +214,18 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private fun showNavigation(visible: Boolean, animated: Boolean) { private fun showNavigation(visible: Boolean, animated: Boolean) {
if (!animated) { if (!animated) {
binding.navigationView.setVisible(visible) if (visible) {
binding.navigationView.visibility = View.VISIBLE
} else {
binding.navigationView.visibility = View.INVISIBLE
}
return return
} }
val smallLayout = resources.getBoolean(R.bool.small_layout) val smallLayout = resources.getBoolean(R.bool.small_layout)
binding.navigationView.animate().apply { binding.navigationView.animate().apply {
if (visible) { if (visible) {
binding.navigationView.setVisible(true) binding.navigationView.visibility = View.VISIBLE
duration = 300 duration = 300
interpolator = PathInterpolator(0.05f, 0.7f, 0.1f, 1f) interpolator = PathInterpolator(0.05f, 0.7f, 0.1f, 1f)
@ -238,7 +264,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
}.withEndAction { }.withEndAction {
if (!visible) { if (!visible) {
binding.navigationView.setVisible(visible = false, gone = false) binding.navigationView.visibility = View.INVISIBLE
} }
}.start() }.start()
} }
@ -246,7 +272,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private fun showStatusBarShade(visible: Boolean) { private fun showStatusBarShade(visible: Boolean) {
binding.statusBarShade.animate().apply { binding.statusBarShade.animate().apply {
if (visible) { if (visible) {
binding.statusBarShade.setVisible(true) binding.statusBarShade.visibility = View.VISIBLE
binding.statusBarShade.translationY = binding.statusBarShade.height.toFloat() * -2 binding.statusBarShade.translationY = binding.statusBarShade.height.toFloat() * -2
duration = 300 duration = 300
translationY(0f) translationY(0f)
@ -258,7 +284,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
}.withEndAction { }.withEndAction {
if (!visible) { if (!visible) {
binding.statusBarShade.setVisible(visible = false, gone = false) binding.statusBarShade.visibility = View.INVISIBLE
} }
}.start() }.start()
} }
@ -498,8 +524,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
this@MainActivity, this@MainActivity,
titleId = R.string.content_install_notice, titleId = R.string.content_install_notice,
descriptionId = R.string.content_install_notice_description, descriptionId = R.string.content_install_notice_description,
positiveAction = { homeViewModel.setContentToInstall(documents) }, positiveAction = { homeViewModel.setContentToInstall(documents) }
negativeAction = {}
) )
} }
}.show(supportFragmentManager, ProgressDialogFragment.TAG) }.show(supportFragmentManager, ProgressDialogFragment.TAG)

View File

@ -1,38 +0,0 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
/**
* Collects this [Flow] with a given [LifecycleOwner].
* @param scope [LifecycleOwner] that this [Flow] will be collected with.
* @param repeatState When to repeat collection on this [Flow].
* @param resetState Optional lambda to reset state of an underlying [MutableStateFlow] after
* [stateCollector] has been run.
* @param stateCollector Lambda that receives new state.
*/
inline fun <reified T> Flow<T>.collect(
scope: LifecycleOwner,
repeatState: Lifecycle.State = Lifecycle.State.CREATED,
crossinline resetState: () -> Unit = {},
crossinline stateCollector: (state: T) -> Unit
) {
scope.apply {
lifecycleScope.launch {
repeatOnLifecycle(repeatState) {
this@collect.collect {
stateCollector(it)
resetState()
}
}
}
}
}

View File

@ -3,10 +3,8 @@
package org.yuzu.yuzu_emu.utils package org.yuzu.yuzu_emu.utils
import android.text.TextUtils
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
object ViewUtils { object ViewUtils {
fun showView(view: View, length: Long = 300) { fun showView(view: View, length: Long = 300) {
@ -59,35 +57,4 @@ object ViewUtils {
} }
this.layoutParams = layoutParams this.layoutParams = layoutParams
} }
/**
* Shows or hides a view.
* @param visible Whether a view will be made View.VISIBLE or View.INVISIBLE/GONE.
* @param gone Optional parameter for hiding a view. Uses View.GONE if true and View.INVISIBLE otherwise.
*/
fun View.setVisible(visible: Boolean, gone: Boolean = true) {
visibility = if (visible) {
View.VISIBLE
} else {
if (gone) {
View.GONE
} else {
View.INVISIBLE
}
}
}
/**
* Starts a marquee on some text.
* @param delay Optional parameter for changing the start delay. 3 seconds of delay by default.
*/
fun TextView.marquee(delay: Long = 3000) {
ellipsize = null
marqueeRepeatLimit = -1
isSingleLine = true
postDelayed({
ellipsize = TextUtils.TruncateAt.MARQUEE
isSelected = true
}, delay)
}
} }

View File

@ -23,22 +23,6 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
window_info.render_surface = reinterpret_cast<void*>(surface); window_info.render_surface = reinterpret_cast<void*>(surface);
} }
void EmuWindow_Android::OnTouchPressed(int id, float x, float y) {
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchPressed(touch_x,
touch_y, id);
}
void EmuWindow_Android::OnTouchMoved(int id, float x, float y) {
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchMoved(touch_x,
touch_y, id);
}
void EmuWindow_Android::OnTouchReleased(int id) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(id);
}
void EmuWindow_Android::OnFrameDisplayed() { void EmuWindow_Android::OnFrameDisplayed() {
if (!m_first_frame) { if (!m_first_frame) {
Common::Android::RunJNIOnFiber<void>( Common::Android::RunJNIOnFiber<void>(

View File

@ -38,10 +38,6 @@ public:
void OnSurfaceChanged(ANativeWindow* surface); void OnSurfaceChanged(ANativeWindow* surface);
void OnFrameDisplayed() override; void OnFrameDisplayed() override;
void OnTouchPressed(int id, float x, float y);
void OnTouchMoved(int id, float x, float y);
void OnTouchReleased(int id);
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override {
return {std::make_unique<GraphicsContext_Android>(m_driver_library)}; return {std::make_unique<GraphicsContext_Android>(m_driver_library)};
} }

View File

@ -292,9 +292,6 @@ void EmulationSession::ShutdownEmulation() {
// Unload user input. // Unload user input.
m_system.HIDCore().UnloadInputDevices(); m_system.HIDCore().UnloadInputDevices();
// Enable all controllers
m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
// Shutdown the main emulated process // Shutdown the main emulated process
if (m_load_result == Core::SystemResultStatus::Success) { if (m_load_result == Core::SystemResultStatus::Success) {
m_system.DetachDebugger(); m_system.DetachDebugger();
@ -407,9 +404,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
const size_t program_index, const size_t program_index,
const bool frontend_initiated) { const bool frontend_initiated) {
MicroProfileOnThreadCreate("EmuThread"); MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT { SCOPE_EXIT({ MicroProfileShutdown(); });
MicroProfileShutdown();
};
LOG_INFO(Frontend, "starting"); LOG_INFO(Frontend, "starting");
@ -418,9 +413,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
return Core::SystemResultStatus::ErrorLoader; return Core::SystemResultStatus::ErrorLoader;
} }
SCOPE_EXIT { SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
EmulationSession::GetInstance().ShutdownEmulation();
};
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
frontend_initiated); frontend_initiated);
@ -668,7 +661,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
ASSERT(user_id); ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1, {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1,
user_id->AsU128(), 0); user_id->AsU128(), 0);
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
@ -836,8 +829,8 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
FileSys::OpenMode::Read); FileSys::OpenMode::Read);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id, {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
user_id->AsU128(), 0); program_id, user_id->AsU128(), 0);
return Common::Android::ToJString(env, user_save_data_path); return Common::Android::ToJString(env, user_save_data_path);
} }

View File

@ -102,50 +102,8 @@ void ApplyControllerConfig(size_t player_index,
} }
} }
std::vector<s32> GetSupportedStyles(int player_index) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
const auto npad_style_set = hid_core.GetSupportedStyleTag();
std::vector<s32> supported_indexes;
if (npad_style_set.fullkey == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey));
}
if (npad_style_set.joycon_dual == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual));
}
if (npad_style_set.joycon_left == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft));
}
if (npad_style_set.joycon_right == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight));
}
if (player_index == 0 && npad_style_set.handheld == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld));
}
if (npad_style_set.gamecube == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube));
}
return supported_indexes;
}
void ConnectController(size_t player_index, bool connected) { void ConnectController(size_t player_index, bool connected) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) {
auto supported_styles = GetSupportedStyles(player_index);
auto controller_style = controller->GetNpadStyleIndex(true);
auto style = std::find(supported_styles.begin(), supported_styles.end(),
static_cast<int>(controller_style));
if (style == supported_styles.end() && !supported_styles.empty()) {
controller->SetNpadStyleIndex(
static_cast<Core::HID::NpadStyleIndex>(supported_styles[0]));
}
});
if (player_index == 0) { if (player_index == 0) {
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
@ -232,7 +190,8 @@ void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchPressed(JNIEnv* e
jint j_id, jfloat j_x_axis, jint j_id, jfloat j_x_axis,
jfloat j_y_axis) { jfloat j_y_axis) {
if (EmulationSession::GetInstance().IsRunning()) { if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnTouchPressed(j_id, j_x_axis, j_y_axis); EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchPressed(
j_id, j_x_axis, j_y_axis);
} }
} }
@ -240,14 +199,15 @@ void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchMoved(JNIEnv* env
jint j_id, jfloat j_x_axis, jint j_id, jfloat j_x_axis,
jfloat j_y_axis) { jfloat j_y_axis) {
if (EmulationSession::GetInstance().IsRunning()) { if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnTouchMoved(j_id, j_x_axis, j_y_axis); EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchMoved(
j_id, j_x_axis, j_y_axis);
} }
} }
void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchReleased(JNIEnv* env, jobject j_obj, void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchReleased(JNIEnv* env, jobject j_obj,
jint j_id) { jint j_id) {
if (EmulationSession::GetInstance().IsRunning()) { if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnTouchReleased(j_id); EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(j_id);
} }
} }
@ -564,10 +524,36 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv
jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl( jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
JNIEnv* env, jobject j_obj, jint j_player_index) { JNIEnv* env, jobject j_obj, jint j_player_index) {
auto supported_styles = GetSupportedStyles(j_player_index); auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
jintArray j_supported_indexes = env->NewIntArray(supported_styles.size()); const auto npad_style_set = hid_core.GetSupportedStyleTag();
env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(), std::vector<s32> supported_indexes;
supported_styles.data()); if (npad_style_set.fullkey == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey));
}
if (npad_style_set.joycon_dual == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual));
}
if (npad_style_set.joycon_left == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft));
}
if (npad_style_set.joycon_right == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight));
}
if (j_player_index == 0 && npad_style_set.handheld == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld));
}
if (npad_style_set.gamecube == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube));
}
jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size());
env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(),
supported_indexes.data());
return j_supported_indexes; return j_supported_indexes;
} }

View File

@ -39,7 +39,10 @@
style="@style/TextAppearance.Material3.TitleMedium" style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart" android:textAlignment="viewStart"
tools:text="@string/select_gpu_driver_default" /> tools:text="@string/select_gpu_driver_default" />
@ -49,7 +52,10 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart" android:textAlignment="viewStart"
tools:text="@string/install_gpu_driver_description" /> tools:text="@string/install_gpu_driver_description" />
@ -59,7 +65,10 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart" android:textAlignment="viewStart"
tools:text="@string/install_gpu_driver_description" /> tools:text="@string/install_gpu_driver_description" />

View File

@ -21,7 +21,10 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start" android:layout_gravity="center_vertical|start"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart" android:textAlignment="viewStart"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/button_layout" app:layout_constraintEnd_toStartOf="@+id/button_layout"

View File

@ -40,7 +40,10 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="center" android:textAlignment="center"
android:textSize="14sp" android:textSize="14sp"
app:layout_constraintEnd_toEndOf="@+id/image_game_screen" app:layout_constraintEnd_toEndOf="@+id/image_game_screen"

View File

@ -59,6 +59,9 @@
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textSize="14sp" android:textSize="14sp"
android:textStyle="bold" android:textStyle="bold"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="none"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:visibility="gone" android:visibility="gone"

View File

@ -76,7 +76,10 @@
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:layout_marginBottom="12dp" android:layout_marginBottom="12dp"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="center" android:textAlignment="center"
tools:text="deko_basic" /> tools:text="deko_basic" />

View File

@ -209,7 +209,6 @@
<string name="value_with_units">%1$s%2$s</string> <string name="value_with_units">%1$s%2$s</string>
<!-- System settings strings --> <!-- System settings strings -->
<string name="device_name">Device name</string>
<string name="use_docked_mode">Docked Mode</string> <string name="use_docked_mode">Docked Mode</string>
<string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string> <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string>
<string name="emulated_region">Emulated region</string> <string name="emulated_region">Emulated region</string>

View File

@ -73,15 +73,16 @@ void Manager::BufferReleaseAndRegister() {
} }
} }
u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names,
[[maybe_unused]] const u32 max_count,
[[maybe_unused]] const bool filter) { [[maybe_unused]] const bool filter) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
LinkToManager(); LinkToManager();
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)}; auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
if (!input_devices.empty() && !names.empty()) { if (input_devices.size() > 1) {
names[0] = Renderer::AudioDevice::AudioDeviceName("Uac"); names.emplace_back("Uac");
return 1; return 1;
} }
return 0; return 0;

View File

@ -60,11 +60,13 @@ public:
* Get a list of audio in device names. * Get a list of audio in device names.
* *
* @param names - Output container to write names to. * @param names - Output container to write names to.
* @param max_count - Maximum number of device names to write. Unused
* @param filter - Should the list be filtered? Unused. * @param filter - Should the list be filtered? Unused.
* *
* @return Number of names written. * @return Number of names written.
*/ */
u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter); u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count,
bool filter);
/// Core system /// Core system
Core::System& system; Core::System& system;

View File

@ -146,11 +146,11 @@ public:
break; break;
} }
tags[released++] = tag;
if (released >= tags.size()) { if (released >= tags.size()) {
break; break;
} }
tags[released++] = tag;
} }
return released; return released;

View File

@ -28,8 +28,8 @@ OpusDecoder::~OpusDecoder() {
} }
} }
Result OpusDecoder::Initialize(const OpusParametersEx& params, Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920}; auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size; shared_buffer_size = transfer_memory_size;
shared_buffer = std::make_unique<u8[]>(shared_buffer_size); shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
@ -59,7 +59,7 @@ Result OpusDecoder::Initialize(const OpusParametersEx& params,
R_SUCCEED(); R_SUCCEED();
} }
Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params, Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920}; auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size; shared_buffer_size = transfer_memory_size;

View File

@ -22,10 +22,10 @@ public:
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_); explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
~OpusDecoder(); ~OpusDecoder();
Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size);
Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size); u64 transfer_memory_size);
Result Initialize(const OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count, Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
std::span<const u8> input_data, std::span<u8> output_data, bool reset); std::span<const u8> input_data, std::span<u8> output_data, bool reset);
Result SetContext([[maybe_unused]] std::span<const u8> context); Result SetContext([[maybe_unused]] std::span<const u8> context);

View File

@ -38,7 +38,7 @@ OpusDecoderManager::OpusDecoderManager(Core::System& system_)
} }
} }
Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) { Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) {
OpusParametersEx ex{ OpusParametersEx ex{
.sample_rate = params.sample_rate, .sample_rate = params.sample_rate,
.channel_count = params.channel_count, .channel_count = params.channel_count,
@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32&
R_RETURN(GetWorkBufferSizeExEx(ex, out_size)); R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
} }
Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) { Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) {
R_RETURN(GetWorkBufferSizeExEx(params, out_size)); R_RETURN(GetWorkBufferSizeExEx(params, out_size));
} }
Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) { Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) {
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount); R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params,
R_SUCCEED(); R_SUCCEED();
} }
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params,
u32& out_size) { u64& out_size) {
OpusMultiStreamParametersEx ex{ OpusMultiStreamParametersEx ex{
.sample_rate = params.sample_rate, .sample_rate = params.sample_rate,
.channel_count = params.channel_count, .channel_count = params.channel_count,
@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStream
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size)); R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
} }
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx( Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params,
const OpusMultiStreamParametersEx& params, u32& out_size) { u64& out_size) {
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size)); R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
} }
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx( Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params,
const OpusMultiStreamParametersEx& params, u32& out_size) { u64& out_size) {
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount); R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count, R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,

View File

@ -22,19 +22,17 @@ public:
return hardware_opus; return hardware_opus;
} }
Result GetWorkBufferSize(const OpusParameters& params, u32& out_size); Result GetWorkBufferSize(OpusParameters& params, u64& out_size);
Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size); Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size);
Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size); Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size);
Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size); Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size);
Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params, Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size);
u32& out_size); Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size);
Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params,
u32& out_size);
private: private:
Core::System& system; Core::System& system;
HardwareOpus hardware_opus; HardwareOpus hardware_opus;
std::array<u32, MaxChannels> required_workbuffer_sizes{}; std::array<u64, MaxChannels> required_workbuffer_sizes{};
}; };
} // namespace AudioCore::OpusDecoder } // namespace AudioCore::OpusDecoder

View File

@ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_)
opus_decoder.SetSharedMemory(shared_memory); opus_decoder.SetSharedMemory(shared_memory);
} }
u32 HardwareOpus::GetWorkBufferSize(u32 channel) { u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
if (!opus_decoder.IsRunning()) { if (!opus_decoder.IsRunning()) {
return 0; return 0;
} }
@ -55,10 +55,10 @@ u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg); ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
return 0; return 0;
} }
return static_cast<u32>(shared_memory.dsp_return_data[0]); return shared_memory.dsp_return_data[0];
} }
u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = total_stream_count; shared_memory.host_send_data[0] = total_stream_count;
shared_memory.host_send_data[1] = stereo_stream_count; shared_memory.host_send_data[1] = stereo_stream_count;
@ -70,7 +70,7 @@ u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg); ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
return 0; return 0;
} }
return static_cast<u32>(shared_memory.dsp_return_data[0]); return shared_memory.dsp_return_data[0];
} }
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
@ -94,9 +94,8 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count,
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 total_stream_count, u32 total_stream_count,
u32 stereo_stream_count, u32 stereo_stream_count, void* mappings,
const void* mappings, void* buffer, void* buffer, u64 buffer_size) {
u64 buffer_size) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = (u64)buffer; shared_memory.host_send_data[0] = (u64)buffer;
shared_memory.host_send_data[1] = buffer_size; shared_memory.host_send_data[1] = buffer_size;

View File

@ -16,14 +16,14 @@ class HardwareOpus {
public: public:
HardwareOpus(Core::System& system); HardwareOpus(Core::System& system);
u32 GetWorkBufferSize(u32 channel); u64 GetWorkBufferSize(u32 channel);
u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count); u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
u64 buffer_size); u64 buffer_size);
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 totaL_stream_count, u32 stereo_stream_count, u32 totaL_stream_count, u32 stereo_stream_count,
const void* mappings, void* buffer, u64 buffer_size); void* mappings, void* buffer, u64 buffer_size);
Result ShutdownDecodeObject(void* buffer, u64 buffer_size); Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size); Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size, Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,

View File

@ -20,7 +20,7 @@ struct OpusParametersEx {
/* 0x00 */ u32 sample_rate; /* 0x00 */ u32 sample_rate;
/* 0x04 */ u32 channel_count; /* 0x04 */ u32 channel_count;
/* 0x08 */ bool use_large_frame_size; /* 0x08 */ bool use_large_frame_size;
/* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7); /* 0x09 */ INSERT_PADDING_BYTES(7);
}; // size = 0x10 }; // size = 0x10
static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!"); static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
@ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx {
/* 0x08 */ u32 total_stream_count; /* 0x08 */ u32 total_stream_count;
/* 0x0C */ u32 stereo_stream_count; /* 0x0C */ u32 stereo_stream_count;
/* 0x10 */ bool use_large_frame_size; /* 0x10 */ bool use_large_frame_size;
/* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7); /* 0x11 */ INSERT_PADDING_BYTES(7);
/* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings; /* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
}; // size = 0x118 }; // size = 0x118
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118, static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,

View File

@ -36,7 +36,8 @@ AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id
: output_sink{system.AudioCore().GetOutputSink()}, : output_sink{system.AudioCore().GetOutputSink()},
applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {} applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const { u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
const size_t max_count) const {
std::span<const AudioDeviceName> names{}; std::span<const AudioDeviceName> names{};
if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) { if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
@ -45,18 +46,19 @@ u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) cons
names = device_names; names = device_names;
} }
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))}; const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))};
for (u32 i = 0; i < out_count; i++) { for (u32 i = 0; i < out_count; i++) {
out_buffer[i] = names[i]; out_buffer.push_back(names[i]);
} }
return out_count; return out_count;
} }
u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const { u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer,
const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))}; const size_t max_count) const {
const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
for (u32 i = 0; i < out_count; i++) { for (u32 i = 0; i < out_count; i++) {
out_buffer[i] = output_device_names[i]; out_buffer.push_back(output_device_names[i]);
} }
return out_count; return out_count;
} }

View File

@ -36,18 +36,20 @@ public:
* Get a list of the available output devices. * Get a list of the available output devices.
* *
* @param out_buffer - Output buffer to write the available device names. * @param out_buffer - Output buffer to write the available device names.
* @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written. * @return Number of device names written.
*/ */
u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const; u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
/** /**
* Get a list of the available output devices. * Get a list of the available output devices.
* Different to above somehow... * Different to above somehow...
* *
* @param out_buffer - Output buffer to write the available device names. * @param out_buffer - Output buffer to write the available device names.
* @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written. * @return Number of device names written.
*/ */
u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const; u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
/** /**
* Set the volume of all streams in the backend sink. * Set the volume of all streams in the backend sink.

View File

@ -17,8 +17,9 @@ Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* ren
Result Renderer::Initialize(const AudioRendererParameterInternal& params, Result Renderer::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, Kernel::KTransferMemory* transfer_memory,
const u64 transfer_memory_size, Kernel::KProcess* process_handle, const u64 transfer_memory_size, const u32 process_handle,
const u64 applet_resource_user_id, const s32 session_id) { Kernel::KProcess& process, const u64 applet_resource_user_id,
const s32 session_id) {
if (params.execution_mode == ExecutionMode::Auto) { if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(system)) { if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio, LOG_ERROR(Service_Audio,
@ -29,7 +30,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
} }
initialized = true; initialized = true;
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
applet_resource_user_id, session_id); applet_resource_user_id, session_id);
return ResultSuccess; return ResultSuccess;

View File

@ -38,14 +38,14 @@ public:
* @param params - Input parameters to initialize the system with. * @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused. * @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused. * @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. * @param process_handle - Process handle, also used for memory. Unused.
* @param applet_resource_user_id - Applet id for this renderer. Unused. * @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer. * @param session_id - Session id of this renderer.
* @return Result code. * @return Result code.
*/ */
Result Initialize(const AudioRendererParameterInternal& params, Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
Kernel::KProcess* process_handle, u64 applet_resource_user_id, u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
s32 session_id); s32 session_id);
/** /**

View File

@ -18,7 +18,7 @@
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_, InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_) const u32 process_handle_, BehaviorInfo& behaviour_)
: input{input_.data() + sizeof(UpdateDataHeader)}, : input{input_.data() + sizeof(UpdateDataHeader)},
input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)}, input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>( output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>(

View File

@ -8,10 +8,6 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/audio/errors.h" #include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
class BehaviorInfo; class BehaviorInfo;
class VoiceContext; class VoiceContext;
@ -43,8 +39,8 @@ class InfoUpdater {
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!"); static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
public: public:
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle,
Kernel::KProcess* process_handle, BehaviorInfo& behaviour); BehaviorInfo& behaviour);
/** /**
* Update the voice channel resources. * Update the voice channel resources.
@ -201,7 +197,7 @@ private:
/// Expected output size, see CheckConsumedSize /// Expected output size, see CheckConsumedSize
u64 expected_output_size; u64 expected_output_size;
/// Unused /// Unused
Kernel::KProcess* process_handle; u32 process_handle;
/// Behaviour /// Behaviour
BehaviorInfo& behaviour; BehaviorInfo& behaviour;
}; };

View File

@ -8,11 +8,11 @@
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_) PoolMapper::PoolMapper(u32 process_handle_, bool force_map_)
: process_handle{process_handle_}, force_map{force_map_} {} : process_handle{process_handle_}, force_map{force_map_} {}
PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_, PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_,
u32 pool_count_, bool force_map_) bool force_map_)
: process_handle{process_handle_}, pool_infos{pool_infos_.data()}, : process_handle{process_handle_}, pool_infos{pool_infos_.data()},
pool_count{pool_count_}, force_map{force_map_} {} pool_count{pool_count_}, force_map{force_map_} {}
@ -106,17 +106,15 @@ bool PoolMapper::IsForceMapEnabled() const {
return force_map; return force_map;
} }
Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const { u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
switch (pool->GetLocation()) { switch (pool->GetLocation()) {
case MemoryPoolInfo::Location::CPU: case MemoryPoolInfo::Location::CPU:
return process_handle; return process_handle;
case MemoryPoolInfo::Location::DSP: case MemoryPoolInfo::Location::DSP:
// return Kernel::Svc::CurrentProcess; return Kernel::Svc::CurrentProcess;
return nullptr;
} }
LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!"); LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
// return Kernel::Svc::CurrentProcess; return Kernel::Svc::CurrentProcess;
return nullptr;
} }
bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr, bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr,
@ -149,14 +147,14 @@ bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const
} }
bool PoolMapper::Unmap(MemoryPoolInfo& pool) const { bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
[[maybe_unused]] Kernel::KProcess* handle{}; [[maybe_unused]] u32 handle{0};
switch (pool.GetLocation()) { switch (pool.GetLocation()) {
case MemoryPoolInfo::Location::CPU: case MemoryPoolInfo::Location::CPU:
handle = process_handle; handle = process_handle;
break; break;
case MemoryPoolInfo::Location::DSP: case MemoryPoolInfo::Location::DSP:
// handle = Kernel::Svc::CurrentProcess; handle = Kernel::Svc::CurrentProcess;
break; break;
} }
// nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size); // nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);

View File

@ -10,10 +10,6 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/audio/errors.h" #include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
class AddressInfo; class AddressInfo;
@ -22,9 +18,9 @@ class AddressInfo;
*/ */
class PoolMapper { class PoolMapper {
public: public:
explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map); explicit PoolMapper(u32 process_handle, bool force_map);
explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos, explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count,
u32 pool_count, bool force_map); bool force_map);
/** /**
* Clear the usage state for all given pools. * Clear the usage state for all given pools.
@ -102,7 +98,7 @@ public:
* @return CurrentProcessHandle if location == DSP, * @return CurrentProcessHandle if location == DSP,
* the PoolMapper's process_handle if location == CPU * the PoolMapper's process_handle if location == CPU
*/ */
Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const; u32 GetProcessHandle(const MemoryPoolInfo* pool) const;
/** /**
* Map the given region with the given handle. This is a no-op. * Map the given region with the given handle. This is a no-op.
@ -171,7 +167,7 @@ public:
private: private:
/// Process handle for this mapper, used when location == CPU /// Process handle for this mapper, used when location == CPU
Kernel::KProcess* process_handle{}; u32 process_handle;
/// List of memory pools assigned to this mapper /// List of memory pools assigned to this mapper
MemoryPoolInfo* pool_infos{}; MemoryPoolInfo* pool_infos{};
/// The number of pools /// The number of pools

View File

@ -102,8 +102,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_)
Result System::Initialize(const AudioRendererParameterInternal& params, Result System::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
Kernel::KProcess* process_handle_, u64 applet_resource_user_id_, u32 process_handle_, Kernel::KProcess& process_,
s32 session_id_) { u64 applet_resource_user_id_, s32 session_id_) {
if (!CheckValidRevision(params.revision)) { if (!CheckValidRevision(params.revision)) {
return Service::Audio::ResultInvalidRevision; return Service::Audio::ResultInvalidRevision;
} }
@ -119,6 +119,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
behavior.SetUserLibRevision(params.revision); behavior.SetUserLibRevision(params.revision);
process_handle = process_handle_; process_handle = process_handle_;
process = &process_;
applet_resource_user_id = applet_resource_user_id_; applet_resource_user_id = applet_resource_user_id_;
session_id = session_id_; session_id = session_id_;
@ -131,8 +132,7 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
render_device = params.rendering_device; render_device = params.rendering_device;
execution_mode = params.execution_mode; execution_mode = params.execution_mode;
process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size);
transfer_memory_size);
// Note: We're not actually using the transfer memory because it's a pain to code for. // Note: We're not actually using the transfer memory because it's a pain to code for.
// Allocate the memory normally instead and hope the game doesn't try to read anything back // Allocate the memory normally instead and hope the game doesn't try to read anything back
@ -616,7 +616,7 @@ void System::SendCommandToDsp() {
static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 * static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
(static_cast<f32>(render_time_limit_percent) / 100.0f))}; (static_cast<f32>(render_time_limit_percent) / 100.0f))};
audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit, audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
applet_resource_user_id, process_handle, applet_resource_user_id, process,
reset_command_buffers); reset_command_buffers);
reset_command_buffers = false; reset_command_buffers = false;
command_buffer_size = command_size; command_buffer_size = command_size;

View File

@ -74,14 +74,14 @@ public:
* @param params - Input parameters to initialize the system with. * @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused. * @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused. * @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. * @param process_handle - Process handle, also used for memory. Unused.
* @param applet_resource_user_id - Applet id for this renderer. Unused. * @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer. * @param session_id - Session id of this renderer.
* @return Result code. * @return Result code.
*/ */
Result Initialize(const AudioRendererParameterInternal& params, Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
Kernel::KProcess* process_handle, u64 applet_resource_user_id, u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
s32 session_id); s32 session_id);
/** /**
@ -278,7 +278,9 @@ private:
/// Does what locks do /// Does what locks do
std::mutex lock{}; std::mutex lock{};
/// Process this audio render is operating within, used for memory reads/writes. /// Process this audio render is operating within, used for memory reads/writes.
Kernel::KProcess* process_handle{}; Kernel::KProcess* process{};
/// Handle for the process for this system, unused
u32 process_handle{};
/// Applet resource id for this system, unused /// Applet resource id for this system, unused
u64 applet_resource_user_id{}; u64 applet_resource_user_id{};
/// Controls performance input and output /// Controls performance input and output

View File

@ -357,9 +357,7 @@ bool IsCubebSuitable() {
return false; return false;
} }
SCOPE_EXIT { SCOPE_EXIT({ cubeb_destroy(ctx); });
cubeb_destroy(ctx);
};
#ifdef _WIN32 #ifdef _WIN32
if (SUCCEEDED(com_init_result)) { if (SUCCEEDED(com_init_result)) {

View File

@ -20,10 +20,10 @@
namespace AudioCore::Sink { namespace AudioCore::Sink {
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
SCOPE_EXIT { SCOPE_EXIT({
queue.enqueue(buffer); queue.enqueue(buffer);
++queued_buffers; ++queued_buffers;
}; });
if (type == StreamType::In) { if (type == StreamType::In) {
return; return;

View File

@ -20,9 +20,7 @@ std::string DemangleSymbol(const std::string& mangled) {
} }
char* demangled = nullptr; char* demangled = nullptr;
SCOPE_EXIT { SCOPE_EXIT({ std::free(demangled); });
std::free(demangled);
};
if (is_itanium(mangled)) { if (is_itanium(mangled)) {
demangled = llvm::itaniumDemangle(mangled.c_str()); demangled = llvm::itaniumDemangle(mangled.c_str());

View File

@ -430,11 +430,11 @@ public:
explicit Impl(size_t backing_size_, size_t virtual_size_) explicit Impl(size_t backing_size_, size_t virtual_size_)
: backing_size{backing_size_}, virtual_size{virtual_size_} { : backing_size{backing_size_}, virtual_size{virtual_size_} {
bool good = false; bool good = false;
SCOPE_EXIT { SCOPE_EXIT({
if (!good) { if (!good) {
Release(); Release();
} }
}; });
long page_size = sysconf(_SC_PAGESIZE); long page_size = sysconf(_SC_PAGESIZE);
if (page_size != 0x1000) { if (page_size != 0x1000) {

View File

@ -24,10 +24,10 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c
out_entry->block_size = page_size; out_entry->block_size = page_size;
// Regardless of whether the page was mapped, advance on exit. // Regardless of whether the page was mapped, advance on exit.
SCOPE_EXIT { SCOPE_EXIT({
context->next_page += 1; context->next_page += 1;
context->next_offset += page_size; context->next_offset += page_size;
}; });
// Validate that we can read the actual entry. // Validate that we can read the actual entry.
const auto page = context->next_page; const auto page = context->next_page;

View File

@ -7,61 +7,29 @@
#include "common/common_funcs.h" #include "common/common_funcs.h"
namespace detail { namespace detail {
template <class F> template <typename Func>
class ScopeGuard { struct ScopeExitHelper {
YUZU_NON_COPYABLE(ScopeGuard); explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {}
~ScopeExitHelper() {
private:
F f;
bool active;
public:
constexpr ScopeGuard(F f_) : f(std::move(f_)), active(true) {}
constexpr ~ScopeGuard() {
if (active) { if (active) {
f(); func();
} }
} }
constexpr void Cancel() {
void Cancel() {
active = false; active = false;
} }
constexpr ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) { Func func;
rhs.Cancel(); bool active{true};
}
ScopeGuard& operator=(ScopeGuard&& rhs) = delete;
}; };
template <class F> template <typename Func>
constexpr ScopeGuard<F> MakeScopeGuard(F f) { ScopeExitHelper<Func> ScopeExit(Func&& func) {
return ScopeGuard<F>(std::move(f)); return ScopeExitHelper<Func>(std::forward<Func>(func));
} }
enum class ScopeGuardOnExit {};
template <typename F>
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
return ScopeGuard<F>(std::forward<F>(f));
}
} // namespace detail } // namespace detail
#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__)
#else
#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__)
#endif
/**
* This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
* used when the caller might want to cancel the ScopeExit.
*/
#define SCOPE_GUARD detail::ScopeGuardOnExit() + [&]()
/** /**
* This macro allows you to conveniently specify a block of code that will run on scope exit. Handy * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
* for doing ad-hoc clean-up tasks in a function with multiple returns. * for doing ad-hoc clean-up tasks in a function with multiple returns.
@ -70,7 +38,7 @@ constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
* \code * \code
* const int saved_val = g_foo; * const int saved_val = g_foo;
* g_foo = 55; * g_foo = 55;
* SCOPE_EXIT{ g_foo = saved_val; }; * SCOPE_EXIT({ g_foo = saved_val; });
* *
* if (Bar()) { * if (Bar()) {
* return 0; * return 0;
@ -79,4 +47,10 @@ constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
* } * }
* \endcode * \endcode
*/ */
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD #define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body)
/**
* This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
* used when the caller might want to cancel the ScopeExit.
*/
#define SCOPE_GUARD(body) detail::ScopeExit([&]() body)

View File

@ -384,12 +384,6 @@ struct Values {
AstcRecompression::Bc3, AstcRecompression::Bc3,
"astc_recompression", "astc_recompression",
Category::RendererAdvanced}; Category::RendererAdvanced};
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
VramUsageMode::Conservative,
VramUsageMode::Conservative,
VramUsageMode::Aggressive,
"vram_usage_mode",
Category::RendererAdvanced};
SwitchableSetting<bool> async_presentation{linkage, SwitchableSetting<bool> async_presentation{linkage,
#ifdef ANDROID #ifdef ANDROID
true, true,

View File

@ -122,8 +122,6 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed); ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL, Vulkan, Null); ENUM(RendererBackend, OpenGL, Vulkan, Null);
ENUM(ShaderBackend, Glsl, Glasm, SpirV); ENUM(ShaderBackend, Glsl, Glasm, SpirV);

View File

@ -38,10 +38,6 @@ std::string StringFromBuffer(std::span<const u8> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
} }
std::string StringFromBuffer(std::span<const char> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
// Turns " hej " into "hej". Also handles tabs. // Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string& str) { std::string StripSpaces(const std::string& str) {
const std::size_t s = str.find_first_not_of(" \t\r\n"); const std::size_t s = str.find_first_not_of(" \t\r\n");

View File

@ -19,7 +19,6 @@ namespace Common {
[[nodiscard]] std::string ToUpper(std::string str); [[nodiscard]] std::string ToUpper(std::string str);
[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data); [[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
[[nodiscard]] std::string StringFromBuffer(std::span<const char> data);
[[nodiscard]] std::string StripSpaces(const std::string& s); [[nodiscard]] std::string StripSpaces(const std::string& s);
[[nodiscard]] std::string StripQuotes(const std::string& s); [[nodiscard]] std::string StripQuotes(const std::string& s);

View File

@ -2,8 +2,8 @@
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
add_library(core STATIC add_library(core STATIC
arm/arm_interface.cpp
arm/arm_interface.h arm/arm_interface.h
arm/arm_interface.cpp
arm/debug.cpp arm/debug.cpp
arm/debug.h arm/debug.h
arm/exclusive_monitor.cpp arm/exclusive_monitor.cpp
@ -37,10 +37,10 @@ add_library(core STATIC
debugger/gdbstub.h debugger/gdbstub.h
debugger/gdbstub_arch.cpp debugger/gdbstub_arch.cpp
debugger/gdbstub_arch.h debugger/gdbstub_arch.h
device_memory.cpp
device_memory.h
device_memory_manager.h device_memory_manager.h
device_memory_manager.inc device_memory_manager.inc
device_memory.cpp
device_memory.h
file_sys/bis_factory.cpp file_sys/bis_factory.cpp
file_sys/bis_factory.h file_sys/bis_factory.h
file_sys/card_image.cpp file_sys/card_image.cpp
@ -58,14 +58,9 @@ add_library(core STATIC
file_sys/fs_operate_range.h file_sys/fs_operate_range.h
file_sys/fs_path.h file_sys/fs_path.h
file_sys/fs_path_utility.h file_sys/fs_path_utility.h
file_sys/fs_save_data_types.h
file_sys/fs_string_util.h file_sys/fs_string_util.h
file_sys/fsa/fs_i_directory.h
file_sys/fsa/fs_i_file.h
file_sys/fsa/fs_i_filesystem.h
file_sys/fsmitm_romfsbuild.cpp file_sys/fsmitm_romfsbuild.cpp
file_sys/fsmitm_romfsbuild.h file_sys/fsmitm_romfsbuild.h
file_sys/fssrv/fssrv_sf_path.h
file_sys/fssystem/fs_i_storage.h file_sys/fssystem/fs_i_storage.h
file_sys/fssystem/fs_types.h file_sys/fssystem/fs_types.h
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@ -395,20 +390,6 @@ add_library(core STATIC
hle/service/acc/errors.h hle/service/acc/errors.h
hle/service/acc/profile_manager.cpp hle/service/acc/profile_manager.cpp
hle/service/acc/profile_manager.h hle/service/acc/profile_manager.h
hle/service/am/am.cpp
hle/service/am/am.h
hle/service/am/am_results.h
hle/service/am/am_types.h
hle/service/am/applet.cpp
hle/service/am/applet.h
hle/service/am/applet_data_broker.cpp
hle/service/am/applet_data_broker.h
hle/service/am/applet_manager.cpp
hle/service/am/applet_manager.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/display_layer_manager.cpp
hle/service/am/display_layer_manager.h
hle/service/am/frontend/applet_cabinet.cpp hle/service/am/frontend/applet_cabinet.cpp
hle/service/am/frontend/applet_cabinet.h hle/service/am/frontend/applet_cabinet.h
hle/service/am/frontend/applet_controller.cpp hle/service/am/frontend/applet_controller.cpp
@ -430,6 +411,20 @@ add_library(core STATIC
hle/service/am/frontend/applet_web_browser_types.h hle/service/am/frontend/applet_web_browser_types.h
hle/service/am/frontend/applets.cpp hle/service/am/frontend/applets.cpp
hle/service/am/frontend/applets.h hle/service/am/frontend/applets.h
hle/service/am/am.cpp
hle/service/am/am.h
hle/service/am/am_results.h
hle/service/am/am_types.h
hle/service/am/applet.cpp
hle/service/am/applet.h
hle/service/am/applet_manager.cpp
hle/service/am/applet_data_broker.cpp
hle/service/am/applet_data_broker.h
hle/service/am/applet_manager.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/display_layer_manager.cpp
hle/service/am/display_layer_manager.h
hle/service/am/hid_registration.cpp hle/service/am/hid_registration.cpp
hle/service/am/hid_registration.h hle/service/am/hid_registration.h
hle/service/am/library_applet_storage.cpp hle/service/am/library_applet_storage.cpp
@ -446,10 +441,10 @@ add_library(core STATIC
hle/service/am/service/application_creator.h hle/service/am/service/application_creator.h
hle/service/am/service/application_functions.cpp hle/service/am/service/application_functions.cpp
hle/service/am/service/application_functions.h hle/service/am/service/application_functions.h
hle/service/am/service/application_proxy.cpp
hle/service/am/service/application_proxy.h
hle/service/am/service/application_proxy_service.cpp hle/service/am/service/application_proxy_service.cpp
hle/service/am/service/application_proxy_service.h hle/service/am/service/application_proxy_service.h
hle/service/am/service/application_proxy.cpp
hle/service/am/service/application_proxy.h
hle/service/am/service/audio_controller.cpp hle/service/am/service/audio_controller.cpp
hle/service/am/service/audio_controller.h hle/service/am/service/audio_controller.h
hle/service/am/service/common_state_getter.cpp hle/service/am/service/common_state_getter.cpp
@ -478,53 +473,53 @@ add_library(core STATIC
hle/service/am/service/process_winding_controller.h hle/service/am/service/process_winding_controller.h
hle/service/am/service/self_controller.cpp hle/service/am/service/self_controller.cpp
hle/service/am/service/self_controller.h hle/service/am/service/self_controller.h
hle/service/am/service/storage.cpp
hle/service/am/service/storage.h
hle/service/am/service/storage_accessor.cpp hle/service/am/service/storage_accessor.cpp
hle/service/am/service/storage_accessor.h hle/service/am/service/storage_accessor.h
hle/service/am/service/storage.cpp
hle/service/am/service/storage.h
hle/service/am/service/system_applet_proxy.cpp hle/service/am/service/system_applet_proxy.cpp
hle/service/am/service/system_applet_proxy.h hle/service/am/service/system_applet_proxy.h
hle/service/am/service/window_controller.cpp hle/service/am/service/window_controller.cpp
hle/service/am/service/window_controller.h hle/service/am/service/window_controller.h
hle/service/aoc/addon_content_manager.cpp hle/service/aoc/aoc_u.cpp
hle/service/aoc/addon_content_manager.h hle/service/aoc/aoc_u.h
hle/service/aoc/purchase_event_manager.cpp
hle/service/aoc/purchase_event_manager.h
hle/service/apm/apm.cpp hle/service/apm/apm.cpp
hle/service/apm/apm.h hle/service/apm/apm.h
hle/service/apm/apm_controller.cpp hle/service/apm/apm_controller.cpp
hle/service/apm/apm_controller.h hle/service/apm/apm_controller.h
hle/service/apm/apm_interface.cpp hle/service/apm/apm_interface.cpp
hle/service/apm/apm_interface.h hle/service/apm/apm_interface.h
hle/service/audio/audio_controller.cpp hle/service/audio/audin_u.cpp
hle/service/audio/audio_controller.h hle/service/audio/audin_u.h
hle/service/audio/audio_device.cpp
hle/service/audio/audio_device.h
hle/service/audio/audio_in_manager.cpp
hle/service/audio/audio_in_manager.h
hle/service/audio/audio_in.cpp
hle/service/audio/audio_in.h
hle/service/audio/audio_out_manager.cpp
hle/service/audio/audio_out_manager.h
hle/service/audio/audio_out.cpp
hle/service/audio/audio_out.h
hle/service/audio/audio_renderer_manager.cpp
hle/service/audio/audio_renderer_manager.h
hle/service/audio/audio_renderer.cpp
hle/service/audio/audio_renderer.h
hle/service/audio/audio.cpp hle/service/audio/audio.cpp
hle/service/audio/audio.h hle/service/audio/audio.h
hle/service/audio/audio_controller.cpp
hle/service/audio/audio_controller.h
hle/service/audio/audout_u.cpp
hle/service/audio/audout_u.h
hle/service/audio/audrec_a.cpp
hle/service/audio/audrec_a.h
hle/service/audio/audrec_u.cpp
hle/service/audio/audrec_u.h
hle/service/audio/audren_u.cpp
hle/service/audio/audren_u.h
hle/service/audio/errors.h hle/service/audio/errors.h
hle/service/audio/final_output_recorder_manager_for_applet.cpp hle/service/audio/hwopus.cpp
hle/service/audio/final_output_recorder_manager_for_applet.h hle/service/audio/hwopus.h
hle/service/audio/final_output_recorder_manager.cpp
hle/service/audio/final_output_recorder_manager.h
hle/service/audio/hardware_opus_decoder_manager.cpp
hle/service/audio/hardware_opus_decoder_manager.h
hle/service/audio/hardware_opus_decoder.cpp
hle/service/audio/hardware_opus_decoder.h
hle/service/bcat/backend/backend.cpp hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h hle/service/bcat/backend/backend.h
hle/service/bcat/news/newly_arrived_event_holder.cpp
hle/service/bcat/news/newly_arrived_event_holder.h
hle/service/bcat/news/news_data_service.cpp
hle/service/bcat/news/news_data_service.h
hle/service/bcat/news/news_database_service.cpp
hle/service/bcat/news/news_database_service.h
hle/service/bcat/news/news_service.cpp
hle/service/bcat/news/news_service.h
hle/service/bcat/news/overwrite_event_holder.cpp
hle/service/bcat/news/overwrite_event_holder.h
hle/service/bcat/news/service_creator.cpp
hle/service/bcat/news/service_creator.h
hle/service/bcat/bcat.cpp hle/service/bcat/bcat.cpp
hle/service/bcat/bcat.h hle/service/bcat/bcat.h
hle/service/bcat/bcat_result.h hle/service/bcat/bcat_result.h
@ -540,18 +535,6 @@ add_library(core STATIC
hle/service/bcat/delivery_cache_progress_service.h hle/service/bcat/delivery_cache_progress_service.h
hle/service/bcat/delivery_cache_storage_service.cpp hle/service/bcat/delivery_cache_storage_service.cpp
hle/service/bcat/delivery_cache_storage_service.h hle/service/bcat/delivery_cache_storage_service.h
hle/service/bcat/news/newly_arrived_event_holder.cpp
hle/service/bcat/news/newly_arrived_event_holder.h
hle/service/bcat/news/news_data_service.cpp
hle/service/bcat/news/news_data_service.h
hle/service/bcat/news/news_database_service.cpp
hle/service/bcat/news/news_database_service.h
hle/service/bcat/news/news_service.cpp
hle/service/bcat/news/news_service.h
hle/service/bcat/news/overwrite_event_holder.cpp
hle/service/bcat/news/overwrite_event_holder.h
hle/service/bcat/news/service_creator.cpp
hle/service/bcat/news/service_creator.h
hle/service/bcat/service_creator.cpp hle/service/bcat/service_creator.cpp
hle/service/bcat/service_creator.h hle/service/bcat/service_creator.h
hle/service/bpc/bpc.cpp hle/service/bpc/bpc.cpp
@ -560,16 +543,6 @@ add_library(core STATIC
hle/service/btdrv/btdrv.h hle/service/btdrv/btdrv.h
hle/service/btm/btm.cpp hle/service/btm/btm.cpp
hle/service/btm/btm.h hle/service/btm/btm.h
hle/service/btm/btm_debug.cpp
hle/service/btm/btm_debug.h
hle/service/btm/btm_system.cpp
hle/service/btm/btm_system.h
hle/service/btm/btm_system_core.cpp
hle/service/btm/btm_system_core.h
hle/service/btm/btm_user.cpp
hle/service/btm/btm_user.h
hle/service/btm/btm_user_core.cpp
hle/service/btm/btm_user_core.h
hle/service/caps/caps.cpp hle/service/caps/caps.cpp
hle/service/caps/caps.h hle/service/caps/caps.h
hle/service/caps/caps_a.cpp hle/service/caps/caps_a.cpp
@ -612,10 +585,6 @@ add_library(core STATIC
hle/service/filesystem/fsp/fs_i_file.h hle/service/filesystem/fsp/fs_i_file.h
hle/service/filesystem/fsp/fs_i_filesystem.cpp hle/service/filesystem/fsp/fs_i_filesystem.cpp
hle/service/filesystem/fsp/fs_i_filesystem.h hle/service/filesystem/fsp/fs_i_filesystem.h
hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
hle/service/filesystem/fsp/fs_i_storage.cpp hle/service/filesystem/fsp/fs_i_storage.cpp
hle/service/filesystem/fsp/fs_i_storage.h hle/service/filesystem/fsp/fs_i_storage.h
hle/service/filesystem/fsp/fsp_ldr.cpp hle/service/filesystem/fsp/fsp_ldr.cpp
@ -624,11 +593,13 @@ add_library(core STATIC
hle/service/filesystem/fsp/fsp_pr.h hle/service/filesystem/fsp/fsp_pr.h
hle/service/filesystem/fsp/fsp_srv.cpp hle/service/filesystem/fsp/fsp_srv.cpp
hle/service/filesystem/fsp/fsp_srv.h hle/service/filesystem/fsp/fsp_srv.h
hle/service/filesystem/fsp/fsp_types.h hle/service/filesystem/fsp/fsp_util.h
hle/service/filesystem/romfs_controller.cpp hle/service/filesystem/romfs_controller.cpp
hle/service/filesystem/romfs_controller.h hle/service/filesystem/romfs_controller.h
hle/service/filesystem/save_data_controller.cpp hle/service/filesystem/save_data_controller.cpp
hle/service/filesystem/save_data_controller.h hle/service/filesystem/save_data_controller.h
hle/service/fgm/fgm.cpp
hle/service/fgm/fgm.h
hle/service/friend/friend.cpp hle/service/friend/friend.cpp
hle/service/friend/friend.h hle/service/friend/friend.h
hle/service/friend/friend_interface.cpp hle/service/friend/friend_interface.cpp
@ -788,10 +759,10 @@ add_library(core STATIC
hle/service/ns/factory_reset_interface.h hle/service/ns/factory_reset_interface.h
hle/service/ns/language.cpp hle/service/ns/language.cpp
hle/service/ns/language.h hle/service/ns/language.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/ns_results.h hle/service/ns/ns_results.h
hle/service/ns/ns_types.h hle/service/ns/ns_types.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/platform_service_manager.cpp hle/service/ns/platform_service_manager.cpp
hle/service/ns/platform_service_manager.h hle/service/ns/platform_service_manager.h
hle/service/ns/query_service.cpp hle/service/ns/query_service.cpp
@ -862,12 +833,12 @@ add_library(core STATIC
hle/service/nvnflinger/consumer_listener.h hle/service/nvnflinger/consumer_listener.h
hle/service/nvnflinger/graphic_buffer_producer.cpp hle/service/nvnflinger/graphic_buffer_producer.cpp
hle/service/nvnflinger/graphic_buffer_producer.h hle/service/nvnflinger/graphic_buffer_producer.h
hle/service/nvnflinger/hardware_composer.cpp
hle/service/nvnflinger/hardware_composer.h
hle/service/nvnflinger/hos_binder_driver.cpp
hle/service/nvnflinger/hos_binder_driver.h
hle/service/nvnflinger/hos_binder_driver_server.cpp hle/service/nvnflinger/hos_binder_driver_server.cpp
hle/service/nvnflinger/hos_binder_driver_server.h hle/service/nvnflinger/hos_binder_driver_server.h
hle/service/nvnflinger/hos_binder_driver.cpp
hle/service/nvnflinger/hos_binder_driver.h
hle/service/nvnflinger/hardware_composer.cpp
hle/service/nvnflinger/hardware_composer.h
hle/service/nvnflinger/hwc_layer.h hle/service/nvnflinger/hwc_layer.h
hle/service/nvnflinger/nvnflinger.cpp hle/service/nvnflinger/nvnflinger.cpp
hle/service/nvnflinger/nvnflinger.h hle/service/nvnflinger/nvnflinger.h
@ -881,20 +852,8 @@ add_library(core STATIC
hle/service/nvnflinger/ui/graphic_buffer.cpp hle/service/nvnflinger/ui/graphic_buffer.cpp
hle/service/nvnflinger/ui/graphic_buffer.h hle/service/nvnflinger/ui/graphic_buffer.h
hle/service/nvnflinger/window.h hle/service/nvnflinger/window.h
hle/service/olsc/daemon_controller.cpp
hle/service/olsc/daemon_controller.h
hle/service/olsc/native_handle_holder.cpp
hle/service/olsc/native_handle_holder.h
hle/service/olsc/olsc_service_for_application.cpp
hle/service/olsc/olsc_service_for_application.h
hle/service/olsc/olsc_service_for_system_service.cpp
hle/service/olsc/olsc_service_for_system_service.h
hle/service/olsc/olsc.cpp hle/service/olsc/olsc.cpp
hle/service/olsc/olsc.h hle/service/olsc/olsc.h
hle/service/olsc/remote_storage_controller.cpp
hle/service/olsc/remote_storage_controller.h
hle/service/olsc/transfer_task_list_controller.cpp
hle/service/olsc/transfer_task_list_controller.h
hle/service/omm/omm.cpp hle/service/omm/omm.cpp
hle/service/omm/omm.h hle/service/omm/omm.h
hle/service/omm/operation_mode_manager.cpp hle/service/omm/operation_mode_manager.cpp
@ -905,44 +864,25 @@ add_library(core STATIC
hle/service/omm/power_state_interface.h hle/service/omm/power_state_interface.h
hle/service/os/event.cpp hle/service/os/event.cpp
hle/service/os/event.h hle/service/os/event.h
hle/service/os/multi_wait.cpp
hle/service/os/multi_wait.h
hle/service/os/multi_wait_holder.cpp hle/service/os/multi_wait_holder.cpp
hle/service/os/multi_wait_holder.h hle/service/os/multi_wait_holder.h
hle/service/os/multi_wait_utils.h hle/service/os/multi_wait_utils.h
hle/service/os/multi_wait.cpp
hle/service/os/multi_wait.h
hle/service/os/mutex.cpp hle/service/os/mutex.cpp
hle/service/os/mutex.h hle/service/os/mutex.h
hle/service/pcie/pcie.cpp hle/service/pcie/pcie.cpp
hle/service/pcie/pcie.h hle/service/pcie/pcie.h
hle/service/pctl/parental_control_service_factory.cpp
hle/service/pctl/parental_control_service_factory.h
hle/service/pctl/parental_control_service.cpp
hle/service/pctl/parental_control_service.h
hle/service/pctl/pctl.cpp hle/service/pctl/pctl.cpp
hle/service/pctl/pctl.h hle/service/pctl/pctl.h
hle/service/pctl/pctl_results.h hle/service/pctl/pctl_module.cpp
hle/service/pctl/pctl_types.h hle/service/pctl/pctl_module.h
hle/service/pcv/pcv.cpp hle/service/pcv/pcv.cpp
hle/service/pcv/pcv.h hle/service/pcv/pcv.h
hle/service/pm/pm.cpp hle/service/pm/pm.cpp
hle/service/pm/pm.h hle/service/pm/pm.h
hle/service/prepo/prepo.cpp hle/service/prepo/prepo.cpp
hle/service/prepo/prepo.h hle/service/prepo/prepo.h
hle/service/psc/ovln/ovln_types.h
hle/service/psc/ovln/receiver_service.cpp
hle/service/psc/ovln/receiver_service.h
hle/service/psc/ovln/receiver.cpp
hle/service/psc/ovln/receiver.h
hle/service/psc/ovln/sender_service.cpp
hle/service/psc/ovln/sender_service.h
hle/service/psc/ovln/sender.cpp
hle/service/psc/ovln/sender.h
hle/service/psc/pm_control.cpp
hle/service/psc/pm_control.h
hle/service/psc/pm_module.cpp
hle/service/psc/pm_module.h
hle/service/psc/pm_service.cpp
hle/service/psc/pm_service.h
hle/service/psc/psc.cpp hle/service/psc/psc.cpp
hle/service/psc/psc.h hle/service/psc/psc.h
hle/service/psc/time/alarms.cpp hle/service/psc/time/alarms.cpp
@ -966,17 +906,15 @@ add_library(core STATIC
hle/service/psc/time/common.cpp hle/service/psc/time/common.cpp
hle/service/psc/time/common.h hle/service/psc/time/common.h
hle/service/psc/time/errors.h hle/service/psc/time/errors.h
hle/service/psc/time/manager.h
hle/service/psc/time/power_state_request_manager.cpp
hle/service/psc/time/power_state_request_manager.h
hle/service/psc/time/power_state_service.cpp
hle/service/psc/time/power_state_service.h
hle/service/psc/time/service_manager.cpp
hle/service/psc/time/service_manager.h
hle/service/psc/time/shared_memory.cpp hle/service/psc/time/shared_memory.cpp
hle/service/psc/time/shared_memory.h hle/service/psc/time/shared_memory.h
hle/service/psc/time/static.cpp hle/service/psc/time/static.cpp
hle/service/psc/time/static.h hle/service/psc/time/static.h
hle/service/psc/time/manager.h
hle/service/psc/time/power_state_service.cpp
hle/service/psc/time/power_state_service.h
hle/service/psc/time/service_manager.cpp
hle/service/psc/time/service_manager.h
hle/service/psc/time/steady_clock.cpp hle/service/psc/time/steady_clock.cpp
hle/service/psc/time/steady_clock.h hle/service/psc/time/steady_clock.h
hle/service/psc/time/system_clock.cpp hle/service/psc/time/system_clock.cpp
@ -985,6 +923,8 @@ add_library(core STATIC
hle/service/psc/time/time_zone.h hle/service/psc/time/time_zone.h
hle/service/psc/time/time_zone_service.cpp hle/service/psc/time/time_zone_service.cpp
hle/service/psc/time/time_zone_service.h hle/service/psc/time/time_zone_service.h
hle/service/psc/time/power_state_request_manager.cpp
hle/service/psc/time/power_state_request_manager.h
hle/service/ptm/psm.cpp hle/service/ptm/psm.cpp
hle/service/ptm/psm.h hle/service/ptm/psm.h
hle/service/ptm/ptm.cpp hle/service/ptm/ptm.cpp
@ -1003,19 +943,19 @@ add_library(core STATIC
hle/service/service.h hle/service/service.h
hle/service/services.cpp hle/service/services.cpp
hle/service/services.h hle/service/services.h
hle/service/set/setting_formats/appln_settings.cpp
hle/service/set/setting_formats/appln_settings.h
hle/service/set/setting_formats/device_settings.cpp
hle/service/set/setting_formats/device_settings.h
hle/service/set/setting_formats/system_settings.cpp
hle/service/set/setting_formats/system_settings.h
hle/service/set/setting_formats/private_settings.cpp
hle/service/set/setting_formats/private_settings.h
hle/service/set/factory_settings_server.cpp hle/service/set/factory_settings_server.cpp
hle/service/set/factory_settings_server.h hle/service/set/factory_settings_server.h
hle/service/set/firmware_debug_settings_server.cpp hle/service/set/firmware_debug_settings_server.cpp
hle/service/set/firmware_debug_settings_server.h hle/service/set/firmware_debug_settings_server.h
hle/service/set/key_code_map.h hle/service/set/key_code_map.h
hle/service/set/setting_formats/appln_settings.cpp
hle/service/set/setting_formats/appln_settings.h
hle/service/set/setting_formats/device_settings.cpp
hle/service/set/setting_formats/device_settings.h
hle/service/set/setting_formats/private_settings.cpp
hle/service/set/setting_formats/private_settings.h
hle/service/set/setting_formats/system_settings.cpp
hle/service/set/setting_formats/system_settings.h
hle/service/set/settings.cpp hle/service/set/settings.cpp
hle/service/set/settings.h hle/service/set/settings.h
hle/service/set/settings_server.cpp hle/service/set/settings_server.cpp
@ -1058,10 +998,10 @@ add_library(core STATIC
hle/service/vi/conductor.h hle/service/vi/conductor.h
hle/service/vi/container.cpp hle/service/vi/container.cpp
hle/service/vi/container.h hle/service/vi/container.h
hle/service/vi/display.h
hle/service/vi/display_list.h hle/service/vi/display_list.h
hle/service/vi/layer.h hle/service/vi/display.h
hle/service/vi/layer_list.h hle/service/vi/layer_list.h
hle/service/vi/layer.h
hle/service/vi/manager_display_service.cpp hle/service/vi/manager_display_service.cpp
hle/service/vi/manager_display_service.h hle/service/vi/manager_display_service.h
hle/service/vi/manager_root_service.cpp hle/service/vi/manager_root_service.cpp
@ -1074,10 +1014,10 @@ add_library(core STATIC
hle/service/vi/system_display_service.h hle/service/vi/system_display_service.h
hle/service/vi/system_root_service.cpp hle/service/vi/system_root_service.cpp
hle/service/vi/system_root_service.h hle/service/vi/system_root_service.h
hle/service/vi/vi.cpp
hle/service/vi/vi.h
hle/service/vi/vi_results.h hle/service/vi/vi_results.h
hle/service/vi/vi_types.h hle/service/vi/vi_types.h
hle/service/vi/vi.cpp
hle/service/vi/vi.h
hle/service/vi/vsync_manager.cpp hle/service/vi/vsync_manager.cpp
hle/service/vi/vsync_manager.h hle/service/vi/vsync_manager.h
internal_network/network.cpp internal_network/network.cpp

View File

@ -199,10 +199,10 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
data.host_context = Common::Fiber::ThreadToFiber(); data.host_context = Common::Fiber::ThreadToFiber();
// Cleanup // Cleanup
SCOPE_EXIT { SCOPE_EXIT({
data.host_context->Exit(); data.host_context->Exit();
MicroProfileOnThreadExit(); MicroProfileOnThreadExit();
}; });
// Running // Running
if (!gpu_barrier->Sync(token)) { if (!gpu_barrier->Sync(token)) {

View File

@ -391,12 +391,12 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o
std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
const auto current_vaddr = const auto current_vaddr =
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset); static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
SCOPE_EXIT{ SCOPE_EXIT({
page_index += next_pages; page_index += next_pages;
page_offset = 0; page_offset = 0;
increment(copy_amount); increment(copy_amount);
remaining_size -= copy_amount; remaining_size -= copy_amount;
}; });
auto phys_addr = compressed_physical_ptr[page_index]; auto phys_addr = compressed_physical_ptr[page_index];
if (phys_addr == 0) { if (phys_addr == 0) {

View File

@ -64,8 +64,8 @@ struct RawNACP {
u64_le cache_storage_size; u64_le cache_storage_size;
u64_le cache_storage_journal_size; u64_le cache_storage_journal_size;
u64_le cache_storage_data_and_journal_max_size; u64_le cache_storage_data_and_journal_max_size;
u16_le cache_storage_max_index; u64_le cache_storage_max_index;
INSERT_PADDING_BYTES(0xE76); INSERT_PADDING_BYTES(0xE70);
}; };
static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size.");

View File

@ -3,10 +3,6 @@
#pragma once #pragma once
#include <string_view>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace FileSys { namespace FileSys {
constexpr inline size_t EntryNameLengthMax = 0x300; constexpr inline size_t EntryNameLengthMax = 0x300;

View File

@ -23,8 +23,6 @@ enum class OpenDirectoryMode : u64 {
File = (1 << 1), File = (1 << 1),
All = (Directory | File), All = (Directory | File),
NotRequireFileSize = (1ULL << 31),
}; };
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode) DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
@ -38,29 +36,4 @@ enum class CreateOption : u8 {
BigFile = (1 << 0), BigFile = (1 << 0),
}; };
struct FileSystemAttribute {
u8 dir_entry_name_length_max_defined;
u8 file_entry_name_length_max_defined;
u8 dir_path_name_length_max_defined;
u8 file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x5);
u8 utf16_dir_entry_name_length_max_defined;
u8 utf16_file_entry_name_length_max_defined;
u8 utf16_dir_path_name_length_max_defined;
u8 utf16_file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x18);
s32 dir_entry_name_length_max;
s32 file_entry_name_length_max;
s32 dir_path_name_length_max;
s32 file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x5);
s32 utf16_dir_entry_name_length_max;
s32 utf16_file_entry_name_length_max;
s32 utf16_dir_path_name_length_max;
s32 utf16_file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x18);
INSERT_PADDING_WORDS_NOINIT(0x1);
};
static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
} // namespace FileSys } // namespace FileSys

View File

@ -10,7 +10,7 @@ namespace FileSys {
constexpr size_t RequiredAlignment = alignof(u64); constexpr size_t RequiredAlignment = alignof(u64);
inline void* AllocateUnsafe(size_t size) { void* AllocateUnsafe(size_t size) {
// Allocate // Allocate
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment}); void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
@ -21,16 +21,16 @@ inline void* AllocateUnsafe(size_t size) {
return ptr; return ptr;
} }
inline void DeallocateUnsafe(void* ptr, size_t size) { void DeallocateUnsafe(void* ptr, size_t size) {
// Deallocate the pointer // Deallocate the pointer
::operator delete(ptr, std::align_val_t{RequiredAlignment}); ::operator delete(ptr, std::align_val_t{RequiredAlignment});
} }
inline void* Allocate(size_t size) { void* Allocate(size_t size) {
return AllocateUnsafe(size); return AllocateUnsafe(size);
} }
inline void Deallocate(void* ptr, size_t size) { void Deallocate(void* ptr, size_t size) {
// If the pointer is non-null, deallocate it // If the pointer is non-null, deallocate it
if (ptr != nullptr) { if (ptr != nullptr) {
DeallocateUnsafe(ptr, size); DeallocateUnsafe(ptr, size);

View File

@ -381,7 +381,7 @@ public:
// Check that it's possible for us to remove a child // Check that it's possible for us to remove a child
auto* p = m_write_buffer.Get(); auto* p = m_write_buffer.Get();
s32 len = static_cast<s32>(std::strlen(p)); s32 len = std::strlen(p);
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented); R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
// Handle a trailing separator // Handle a trailing separator

View File

@ -426,9 +426,8 @@ public:
R_SUCCEED(); R_SUCCEED();
} }
static constexpr Result Normalize(char* dst, size_t* out_len, const char* path, static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size,
size_t max_out_size, bool is_windows_path, bool is_windows_path, bool is_drive_relative_path,
bool is_drive_relative_path,
bool allow_all_characters = false) { bool allow_all_characters = false) {
// Use StringTraits names for remainder of scope // Use StringTraits names for remainder of scope
using namespace StringTraits; using namespace StringTraits;
@ -448,7 +447,7 @@ public:
char* replacement_path = nullptr; char* replacement_path = nullptr;
size_t replacement_path_size = 0; size_t replacement_path_size = 0;
SCOPE_EXIT { SCOPE_EXIT({
if (replacement_path != nullptr) { if (replacement_path != nullptr) {
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
delete[] replacement_path; delete[] replacement_path;
@ -456,7 +455,7 @@ public:
Deallocate(replacement_path, replacement_path_size); Deallocate(replacement_path, replacement_path_size);
} }
} }
}; });
// Perform path replacement, if necessary // Perform path replacement, if necessary
if (IsParentDirectoryPathReplacementNeeded(cur_path)) { if (IsParentDirectoryPathReplacementNeeded(cur_path)) {
@ -1103,7 +1102,7 @@ public:
R_SUCCEED(); R_SUCCEED();
} }
static constexpr Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len, static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
const PathFlags& flags) { const PathFlags& flags) {
// Use StringTraits names for remainder of scope // Use StringTraits names for remainder of scope
using namespace StringTraits; using namespace StringTraits;
@ -1200,7 +1199,7 @@ public:
const size_t replaced_src_len = path_len - (src - path); const size_t replaced_src_len = path_len - (src - path);
char* replaced_src = nullptr; char* replaced_src = nullptr;
SCOPE_EXIT { SCOPE_EXIT({
if (replaced_src != nullptr) { if (replaced_src != nullptr) {
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
delete[] replaced_src; delete[] replaced_src;
@ -1208,7 +1207,7 @@ public:
Deallocate(replaced_src, replaced_src_len); Deallocate(replaced_src, replaced_src_len);
} }
} }
}; });
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
replaced_src = new char[replaced_src_len]; replaced_src = new char[replaced_src_len];

View File

@ -1,175 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <fmt/format.h>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace FileSys {
using SaveDataId = u64;
using SystemSaveDataId = u64;
using SystemBcatSaveDataId = SystemSaveDataId;
using ProgramId = u64;
enum class SaveDataSpaceId : u8 {
System = 0,
User = 1,
SdSystem = 2,
Temporary = 3,
SdUser = 4,
ProperSystem = 100,
SafeMode = 101,
};
enum class SaveDataType : u8 {
System = 0,
Account = 1,
Bcat = 2,
Device = 3,
Temporary = 4,
Cache = 5,
SystemBcat = 6,
};
enum class SaveDataRank : u8 {
Primary = 0,
Secondary = 1,
};
struct SaveDataSize {
u64 normal;
u64 journal;
};
static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size.");
using UserId = u128;
static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable.");
static_assert(sizeof(UserId) == 0x10, "UserId has invalid size.");
constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
constexpr inline UserId InvalidUserId = {};
enum class SaveDataFlags : u32 {
None = (0 << 0),
KeepAfterResettingSystemSaveData = (1 << 0),
KeepAfterRefurbishment = (1 << 1),
KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
NeedsSecureDelete = (1 << 3),
};
enum class SaveDataMetaType : u8 {
None = 0,
Thumbnail = 1,
ExtensionContext = 2,
};
struct SaveDataMetaInfo {
u32 size;
SaveDataMetaType type;
INSERT_PADDING_BYTES(0xB);
};
static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>,
"Data type must be trivially copyable.");
static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size.");
struct SaveDataCreationInfo {
s64 size;
s64 journal_size;
s64 block_size;
u64 owner_id;
u32 flags;
SaveDataSpaceId space_id;
bool pseudo;
INSERT_PADDING_BYTES(0x1A);
};
static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>,
"Data type must be trivially copyable.");
static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size.");
struct SaveDataAttribute {
ProgramId program_id;
UserId user_id;
SystemSaveDataId system_save_data_id;
SaveDataType type;
SaveDataRank rank;
u16 index;
INSERT_PADDING_BYTES(0x1C);
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id, u16 index,
SaveDataRank rank) {
return {
.program_id = program_id,
.user_id = user_id,
.system_save_data_id = system_save_data_id,
.type = type,
.rank = rank,
.index = index,
};
}
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id, u16 index) {
return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
}
static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
SystemSaveDataId system_save_data_id) {
return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
}
std::string DebugInfo() const {
return fmt::format(
"[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
"rank={}, index={}]",
program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type),
static_cast<u8>(rank), index);
}
};
static_assert(sizeof(SaveDataAttribute) == 0x40);
static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
}
constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank,
lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id,
rhs.type, rhs.rank, rhs.index);
}
constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
return !(lhs == rhs);
}
struct SaveDataExtraData {
SaveDataAttribute attr;
u64 owner_id;
s64 timestamp;
u32 flags;
INSERT_PADDING_BYTES(4);
s64 available_size;
s64 journal_size;
s64 commit_id;
INSERT_PADDING_BYTES(0x190);
};
static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size.");
static_assert(std::is_trivially_copyable_v<SaveDataExtraData>,
"Data type must be trivially copyable.");
struct HashSalt {
static constexpr size_t Size = 32;
std::array<u8, Size> value;
};
static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
static_assert(sizeof(HashSalt) == HashSalt::Size);
} // namespace FileSys

View File

@ -19,11 +19,6 @@ constexpr int Strlen(const T* str) {
return length; return length;
} }
template <typename T>
constexpr int Strnlen(const T* str, std::size_t count) {
return Strnlen(str, static_cast<int>(count));
}
template <typename T> template <typename T>
constexpr int Strnlen(const T* str, int count) { constexpr int Strnlen(const T* str, int count) {
ASSERT(str != nullptr); ASSERT(str != nullptr);
@ -37,11 +32,6 @@ constexpr int Strnlen(const T* str, int count) {
return length; return length;
} }
template <typename T>
constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
return Strncmp(lhs, rhs, static_cast<int>(count));
}
template <typename T> template <typename T>
constexpr int Strncmp(const T* lhs, const T* rhs, int count) { constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
ASSERT(lhs != nullptr); ASSERT(lhs != nullptr);
@ -61,11 +51,6 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
return l - r; return l - r;
} }
template <typename T>
static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
return Strlcpy<T>(dst, src, static_cast<int>(count));
}
template <typename T> template <typename T>
static constexpr int Strlcpy(T* dst, const T* src, int count) { static constexpr int Strlcpy(T* dst, const T* src, int count) {
ASSERT(dst != nullptr); ASSERT(dst != nullptr);

Some files were not shown because too many files have changed in this diff Show More