diff options
| author | 2023-08-30 16:24:46 -0400 | |
|---|---|---|
| committer | 2023-08-30 16:24:46 -0400 | |
| commit | a2f0caefd46df4a550adfb35c1f319becca1ffdb (patch) | |
| tree | 12776fe4b53271faeda62f534d313f2a1fbfd929 | |
| parent | Merge pull request #11419 from FearlessTobi/hwopus-2 (diff) | |
| parent | android: Separate emulation states from emulation mutex (diff) | |
| download | yuzu-a2f0caefd46df4a550adfb35c1f319becca1ffdb.tar.gz yuzu-a2f0caefd46df4a550adfb35c1f319becca1ffdb.tar.xz yuzu-a2f0caefd46df4a550adfb35c1f319becca1ffdb.zip | |
Merge pull request #11405 from t895/emulation-loading
android: Emulation loading UI and fixes
28 files changed, 393 insertions, 237 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 5a7cf4ed7..c8706d7a6 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | |||
| @@ -22,9 +22,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil.exists | |||
| 22 | import org.yuzu.yuzu_emu.utils.FileUtil.getFileSize | 22 | import org.yuzu.yuzu_emu.utils.FileUtil.getFileSize |
| 23 | import org.yuzu.yuzu_emu.utils.FileUtil.isDirectory | 23 | import org.yuzu.yuzu_emu.utils.FileUtil.isDirectory |
| 24 | import org.yuzu.yuzu_emu.utils.FileUtil.openContentUri | 24 | import org.yuzu.yuzu_emu.utils.FileUtil.openContentUri |
| 25 | import org.yuzu.yuzu_emu.utils.Log.error | 25 | import org.yuzu.yuzu_emu.utils.Log |
| 26 | import org.yuzu.yuzu_emu.utils.Log.verbose | ||
| 27 | import org.yuzu.yuzu_emu.utils.Log.warning | ||
| 28 | import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable | 26 | import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable |
| 29 | 27 | ||
| 30 | /** | 28 | /** |
| @@ -465,7 +463,7 @@ object NativeLibrary { | |||
| 465 | 463 | ||
| 466 | val emulationActivity = sEmulationActivity.get() | 464 | val emulationActivity = sEmulationActivity.get() |
| 467 | if (emulationActivity == null) { | 465 | if (emulationActivity == null) { |
| 468 | warning("[NativeLibrary] EmulationActivity is null, can't exit.") | 466 | Log.warning("[NativeLibrary] EmulationActivity is null, can't exit.") |
| 469 | return | 467 | return |
| 470 | } | 468 | } |
| 471 | 469 | ||
| @@ -490,15 +488,27 @@ object NativeLibrary { | |||
| 490 | } | 488 | } |
| 491 | 489 | ||
| 492 | fun setEmulationActivity(emulationActivity: EmulationActivity?) { | 490 | fun setEmulationActivity(emulationActivity: EmulationActivity?) { |
| 493 | verbose("[NativeLibrary] Registering EmulationActivity.") | 491 | Log.verbose("[NativeLibrary] Registering EmulationActivity.") |
| 494 | sEmulationActivity = WeakReference(emulationActivity) | 492 | sEmulationActivity = WeakReference(emulationActivity) |
| 495 | } | 493 | } |
| 496 | 494 | ||
| 497 | fun clearEmulationActivity() { | 495 | fun clearEmulationActivity() { |
| 498 | verbose("[NativeLibrary] Unregistering EmulationActivity.") | 496 | Log.verbose("[NativeLibrary] Unregistering EmulationActivity.") |
| 499 | sEmulationActivity.clear() | 497 | sEmulationActivity.clear() |
| 500 | } | 498 | } |
| 501 | 499 | ||
| 500 | @Keep | ||
| 501 | @JvmStatic | ||
| 502 | fun onEmulationStarted() { | ||
| 503 | sEmulationActivity.get()!!.onEmulationStarted() | ||
| 504 | } | ||
| 505 | |||
| 506 | @Keep | ||
| 507 | @JvmStatic | ||
| 508 | fun onEmulationStopped(status: Int) { | ||
| 509 | sEmulationActivity.get()!!.onEmulationStopped(status) | ||
| 510 | } | ||
| 511 | |||
| 502 | /** | 512 | /** |
| 503 | * Logs the Yuzu version, Android version and, CPU. | 513 | * Logs the Yuzu version, Android version and, CPU. |
| 504 | */ | 514 | */ |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index dbd602a1d..bbd328c71 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt | |||
| @@ -28,6 +28,7 @@ import android.view.Surface | |||
| 28 | import android.view.View | 28 | import android.view.View |
| 29 | import android.view.inputmethod.InputMethodManager | 29 | import android.view.inputmethod.InputMethodManager |
| 30 | import android.widget.Toast | 30 | import android.widget.Toast |
| 31 | import androidx.activity.viewModels | ||
| 31 | import androidx.appcompat.app.AppCompatActivity | 32 | import androidx.appcompat.app.AppCompatActivity |
| 32 | import androidx.core.view.WindowCompat | 33 | import androidx.core.view.WindowCompat |
| 33 | import androidx.core.view.WindowInsetsCompat | 34 | import androidx.core.view.WindowInsetsCompat |
| @@ -41,6 +42,7 @@ import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding | |||
| 41 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 42 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 42 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | 43 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 43 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 44 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 45 | import org.yuzu.yuzu_emu.model.EmulationViewModel | ||
| 44 | import org.yuzu.yuzu_emu.model.Game | 46 | import org.yuzu.yuzu_emu.model.Game |
| 45 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper | 47 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper |
| 46 | import org.yuzu.yuzu_emu.utils.ForegroundService | 48 | import org.yuzu.yuzu_emu.utils.ForegroundService |
| @@ -70,8 +72,11 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 70 | private val actionMute = "ACTION_EMULATOR_MUTE" | 72 | private val actionMute = "ACTION_EMULATOR_MUTE" |
| 71 | private val actionUnmute = "ACTION_EMULATOR_UNMUTE" | 73 | private val actionUnmute = "ACTION_EMULATOR_UNMUTE" |
| 72 | 74 | ||
| 75 | private val emulationViewModel: EmulationViewModel by viewModels() | ||
| 76 | |||
| 73 | override fun onDestroy() { | 77 | override fun onDestroy() { |
| 74 | stopForegroundService(this) | 78 | stopForegroundService(this) |
| 79 | emulationViewModel.clear() | ||
| 75 | super.onDestroy() | 80 | super.onDestroy() |
| 76 | } | 81 | } |
| 77 | 82 | ||
| @@ -416,6 +421,16 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 416 | } | 421 | } |
| 417 | } | 422 | } |
| 418 | 423 | ||
| 424 | fun onEmulationStarted() { | ||
| 425 | emulationViewModel.setEmulationStarted(true) | ||
| 426 | } | ||
| 427 | |||
| 428 | fun onEmulationStopped(status: Int) { | ||
| 429 | if (status == 0) { | ||
| 430 | finish() | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 419 | private fun startMotionSensorListener() { | 434 | private fun startMotionSensorListener() { |
| 420 | val sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager | 435 | val sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager |
| 421 | val gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) | 436 | val gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index e91277d35..13359ef36 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.adapters | 4 | package org.yuzu.yuzu_emu.adapters |
| 5 | 5 | ||
| 6 | import android.graphics.Bitmap | ||
| 7 | import android.graphics.BitmapFactory | ||
| 8 | import android.net.Uri | 6 | import android.net.Uri |
| 9 | import android.text.TextUtils | 7 | import android.text.TextUtils |
| 10 | import android.view.LayoutInflater | 8 | import android.view.LayoutInflater |
| @@ -15,23 +13,20 @@ import android.widget.Toast | |||
| 15 | import androidx.appcompat.app.AppCompatActivity | 13 | import androidx.appcompat.app.AppCompatActivity |
| 16 | import androidx.documentfile.provider.DocumentFile | 14 | import androidx.documentfile.provider.DocumentFile |
| 17 | import androidx.lifecycle.ViewModelProvider | 15 | import androidx.lifecycle.ViewModelProvider |
| 18 | import androidx.lifecycle.lifecycleScope | ||
| 19 | import androidx.navigation.findNavController | 16 | import androidx.navigation.findNavController |
| 20 | import androidx.preference.PreferenceManager | 17 | import androidx.preference.PreferenceManager |
| 21 | import androidx.recyclerview.widget.AsyncDifferConfig | 18 | import androidx.recyclerview.widget.AsyncDifferConfig |
| 22 | import androidx.recyclerview.widget.DiffUtil | 19 | import androidx.recyclerview.widget.DiffUtil |
| 23 | import androidx.recyclerview.widget.ListAdapter | 20 | import androidx.recyclerview.widget.ListAdapter |
| 24 | import androidx.recyclerview.widget.RecyclerView | 21 | import androidx.recyclerview.widget.RecyclerView |
| 25 | import coil.load | ||
| 26 | import kotlinx.coroutines.launch | ||
| 27 | import org.yuzu.yuzu_emu.HomeNavigationDirections | 22 | import org.yuzu.yuzu_emu.HomeNavigationDirections |
| 28 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 29 | import org.yuzu.yuzu_emu.R | 23 | import org.yuzu.yuzu_emu.R |
| 30 | import org.yuzu.yuzu_emu.YuzuApplication | 24 | import org.yuzu.yuzu_emu.YuzuApplication |
| 31 | import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder | 25 | import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder |
| 32 | import org.yuzu.yuzu_emu.databinding.CardGameBinding | 26 | import org.yuzu.yuzu_emu.databinding.CardGameBinding |
| 33 | import org.yuzu.yuzu_emu.model.Game | 27 | import org.yuzu.yuzu_emu.model.Game |
| 34 | import org.yuzu.yuzu_emu.model.GamesViewModel | 28 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 29 | import org.yuzu.yuzu_emu.utils.GameIconUtils | ||
| 35 | 30 | ||
| 36 | class GameAdapter(private val activity: AppCompatActivity) : | 31 | class GameAdapter(private val activity: AppCompatActivity) : |
| 37 | ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()), | 32 | ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()), |
| @@ -98,12 +93,7 @@ class GameAdapter(private val activity: AppCompatActivity) : | |||
| 98 | this.game = game | 93 | this.game = game |
| 99 | 94 | ||
| 100 | binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP | 95 | binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP |
| 101 | activity.lifecycleScope.launch { | 96 | GameIconUtils.loadGameIcon(game, binding.imageGameScreen) |
| 102 | val bitmap = decodeGameIcon(game.path) | ||
| 103 | binding.imageGameScreen.load(bitmap) { | ||
| 104 | error(R.drawable.default_icon) | ||
| 105 | } | ||
| 106 | } | ||
| 107 | 97 | ||
| 108 | binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ") | 98 | binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ") |
| 109 | 99 | ||
| @@ -126,14 +116,4 @@ class GameAdapter(private val activity: AppCompatActivity) : | |||
| 126 | return oldItem == newItem | 116 | return oldItem == newItem |
| 127 | } | 117 | } |
| 128 | } | 118 | } |
| 129 | |||
| 130 | private fun decodeGameIcon(uri: String): Bitmap? { | ||
| 131 | val data = NativeLibrary.getIcon(uri) | ||
| 132 | return BitmapFactory.decodeByteArray( | ||
| 133 | data, | ||
| 134 | 0, | ||
| 135 | data.size, | ||
| 136 | BitmapFactory.Options() | ||
| 137 | ) | ||
| 138 | } | ||
| 139 | } | 119 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt index a18efef19..6f4b5b13f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt | |||
| @@ -4,43 +4,43 @@ | |||
| 4 | package org.yuzu.yuzu_emu.disk_shader_cache | 4 | package org.yuzu.yuzu_emu.disk_shader_cache |
| 5 | 5 | ||
| 6 | import androidx.annotation.Keep | 6 | import androidx.annotation.Keep |
| 7 | import androidx.lifecycle.ViewModelProvider | ||
| 7 | import org.yuzu.yuzu_emu.NativeLibrary | 8 | import org.yuzu.yuzu_emu.NativeLibrary |
| 8 | import org.yuzu.yuzu_emu.R | 9 | import org.yuzu.yuzu_emu.R |
| 9 | import org.yuzu.yuzu_emu.disk_shader_cache.ui.ShaderProgressDialogFragment | 10 | import org.yuzu.yuzu_emu.activities.EmulationActivity |
| 11 | import org.yuzu.yuzu_emu.model.EmulationViewModel | ||
| 12 | import org.yuzu.yuzu_emu.utils.Log | ||
| 10 | 13 | ||
| 11 | @Keep | 14 | @Keep |
| 12 | object DiskShaderCacheProgress { | 15 | object DiskShaderCacheProgress { |
| 13 | val finishLock = Object() | 16 | private lateinit var emulationViewModel: EmulationViewModel |
| 14 | private lateinit var fragment: ShaderProgressDialogFragment | ||
| 15 | 17 | ||
| 16 | private fun prepareDialog() { | 18 | private fun prepareViewModel() { |
| 17 | val emulationActivity = NativeLibrary.sEmulationActivity.get()!! | 19 | emulationViewModel = |
| 18 | emulationActivity.runOnUiThread { | 20 | ViewModelProvider( |
| 19 | fragment = ShaderProgressDialogFragment.newInstance( | 21 | NativeLibrary.sEmulationActivity.get() as EmulationActivity |
| 20 | emulationActivity.getString(R.string.loading), | 22 | )[EmulationViewModel::class.java] |
| 21 | emulationActivity.getString(R.string.preparing_shaders) | ||
| 22 | ) | ||
| 23 | fragment.show( | ||
| 24 | emulationActivity.supportFragmentManager, | ||
| 25 | ShaderProgressDialogFragment.TAG | ||
| 26 | ) | ||
| 27 | } | ||
| 28 | synchronized(finishLock) { finishLock.wait() } | ||
| 29 | } | 23 | } |
| 30 | 24 | ||
| 31 | @JvmStatic | 25 | @JvmStatic |
| 32 | fun loadProgress(stage: Int, progress: Int, max: Int) { | 26 | fun loadProgress(stage: Int, progress: Int, max: Int) { |
| 33 | val emulationActivity = NativeLibrary.sEmulationActivity.get() | 27 | val emulationActivity = NativeLibrary.sEmulationActivity.get() |
| 34 | ?: error("[DiskShaderCacheProgress] EmulationActivity not present") | 28 | if (emulationActivity == null) { |
| 35 | 29 | Log.error("[DiskShaderCacheProgress] EmulationActivity not present") | |
| 36 | when (LoadCallbackStage.values()[stage]) { | 30 | return |
| 37 | LoadCallbackStage.Prepare -> prepareDialog() | 31 | } |
| 38 | LoadCallbackStage.Build -> fragment.onUpdateProgress( | 32 | |
| 39 | emulationActivity.getString(R.string.building_shaders), | 33 | emulationActivity.runOnUiThread { |
| 40 | progress, | 34 | when (LoadCallbackStage.values()[stage]) { |
| 41 | max | 35 | LoadCallbackStage.Prepare -> prepareViewModel() |
| 42 | ) | 36 | LoadCallbackStage.Build -> emulationViewModel.updateProgress( |
| 43 | LoadCallbackStage.Complete -> fragment.dismiss() | 37 | emulationActivity.getString(R.string.building_shaders), |
| 38 | progress, | ||
| 39 | max | ||
| 40 | ) | ||
| 41 | |||
| 42 | LoadCallbackStage.Complete -> {} | ||
| 43 | } | ||
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ShaderProgressViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ShaderProgressViewModel.kt deleted file mode 100644 index bf6f0366d..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ShaderProgressViewModel.kt +++ /dev/null | |||
| @@ -1,31 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.disk_shader_cache | ||
| 5 | |||
| 6 | import androidx.lifecycle.LiveData | ||
| 7 | import androidx.lifecycle.MutableLiveData | ||
| 8 | import androidx.lifecycle.ViewModel | ||
| 9 | |||
| 10 | class ShaderProgressViewModel : ViewModel() { | ||
| 11 | private val _progress = MutableLiveData(0) | ||
| 12 | val progress: LiveData<Int> get() = _progress | ||
| 13 | |||
| 14 | private val _max = MutableLiveData(0) | ||
| 15 | val max: LiveData<Int> get() = _max | ||
| 16 | |||
| 17 | private val _message = MutableLiveData("") | ||
| 18 | val message: LiveData<String> get() = _message | ||
| 19 | |||
| 20 | fun setProgress(progress: Int) { | ||
| 21 | _progress.postValue(progress) | ||
| 22 | } | ||
| 23 | |||
| 24 | fun setMax(max: Int) { | ||
| 25 | _max.postValue(max) | ||
| 26 | } | ||
| 27 | |||
| 28 | fun setMessage(msg: String) { | ||
| 29 | _message.postValue(msg) | ||
| 30 | } | ||
| 31 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt deleted file mode 100644 index 8a8e0a6e8..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt +++ /dev/null | |||
| @@ -1,103 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.disk_shader_cache.ui | ||
| 5 | |||
| 6 | import android.app.Dialog | ||
| 7 | import android.os.Bundle | ||
| 8 | import android.view.LayoutInflater | ||
| 9 | import android.view.View | ||
| 10 | import android.view.ViewGroup | ||
| 11 | import androidx.appcompat.app.AlertDialog | ||
| 12 | import androidx.fragment.app.DialogFragment | ||
| 13 | import androidx.lifecycle.ViewModelProvider | ||
| 14 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||
| 15 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding | ||
| 16 | import org.yuzu.yuzu_emu.disk_shader_cache.DiskShaderCacheProgress | ||
| 17 | import org.yuzu.yuzu_emu.disk_shader_cache.ShaderProgressViewModel | ||
| 18 | |||
| 19 | class ShaderProgressDialogFragment : DialogFragment() { | ||
| 20 | private var _binding: DialogProgressBarBinding? = null | ||
| 21 | private val binding get() = _binding!! | ||
| 22 | |||
| 23 | private lateinit var alertDialog: AlertDialog | ||
| 24 | |||
| 25 | private lateinit var shaderProgressViewModel: ShaderProgressViewModel | ||
| 26 | |||
| 27 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { | ||
| 28 | _binding = DialogProgressBarBinding.inflate(layoutInflater) | ||
| 29 | shaderProgressViewModel = | ||
| 30 | ViewModelProvider(requireActivity())[ShaderProgressViewModel::class.java] | ||
| 31 | |||
| 32 | val title = requireArguments().getString(TITLE) | ||
| 33 | val message = requireArguments().getString(MESSAGE) | ||
| 34 | |||
| 35 | isCancelable = false | ||
| 36 | alertDialog = MaterialAlertDialogBuilder(requireActivity()) | ||
| 37 | .setView(binding.root) | ||
| 38 | .setTitle(title) | ||
| 39 | .setMessage(message) | ||
| 40 | .create() | ||
| 41 | return alertDialog | ||
| 42 | } | ||
| 43 | |||
| 44 | override fun onCreateView( | ||
| 45 | inflater: LayoutInflater, | ||
| 46 | container: ViewGroup?, | ||
| 47 | savedInstanceState: Bundle? | ||
| 48 | ): View { | ||
| 49 | return binding.root | ||
| 50 | } | ||
| 51 | |||
| 52 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
| 53 | super.onViewCreated(view, savedInstanceState) | ||
| 54 | shaderProgressViewModel.progress.observe(viewLifecycleOwner) { progress -> | ||
| 55 | binding.progressBar.progress = progress | ||
| 56 | setUpdateText() | ||
| 57 | } | ||
| 58 | shaderProgressViewModel.max.observe(viewLifecycleOwner) { max -> | ||
| 59 | binding.progressBar.max = max | ||
| 60 | setUpdateText() | ||
| 61 | } | ||
| 62 | shaderProgressViewModel.message.observe(viewLifecycleOwner) { msg -> | ||
| 63 | alertDialog.setMessage(msg) | ||
| 64 | } | ||
| 65 | synchronized(DiskShaderCacheProgress.finishLock) { | ||
| 66 | DiskShaderCacheProgress.finishLock.notifyAll() | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | override fun onDestroyView() { | ||
| 71 | super.onDestroyView() | ||
| 72 | _binding = null | ||
| 73 | } | ||
| 74 | |||
| 75 | fun onUpdateProgress(msg: String, progress: Int, max: Int) { | ||
| 76 | shaderProgressViewModel.setProgress(progress) | ||
| 77 | shaderProgressViewModel.setMax(max) | ||
| 78 | shaderProgressViewModel.setMessage(msg) | ||
| 79 | } | ||
| 80 | |||
| 81 | private fun setUpdateText() { | ||
| 82 | binding.progressText.text = String.format( | ||
| 83 | "%d/%d", | ||
| 84 | shaderProgressViewModel.progress.value, | ||
| 85 | shaderProgressViewModel.max.value | ||
| 86 | ) | ||
| 87 | } | ||
| 88 | |||
| 89 | companion object { | ||
| 90 | const val TAG = "ProgressDialogFragment" | ||
| 91 | const val TITLE = "title" | ||
| 92 | const val MESSAGE = "message" | ||
| 93 | |||
| 94 | fun newInstance(title: String, message: String): ShaderProgressDialogFragment { | ||
| 95 | val frag = ShaderProgressDialogFragment() | ||
| 96 | val args = Bundle() | ||
| 97 | args.putString(TITLE, title) | ||
| 98 | args.putString(MESSAGE, message) | ||
| 99 | frag.arguments = args | ||
| 100 | return frag | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 53f19c4f8..944ae652e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt | |||
| @@ -24,8 +24,9 @@ import androidx.core.content.res.ResourcesCompat | |||
| 24 | import androidx.core.graphics.Insets | 24 | import androidx.core.graphics.Insets |
| 25 | import androidx.core.view.ViewCompat | 25 | import androidx.core.view.ViewCompat |
| 26 | import androidx.core.view.WindowInsetsCompat | 26 | import androidx.core.view.WindowInsetsCompat |
| 27 | import androidx.core.view.isVisible | 27 | import androidx.drawerlayout.widget.DrawerLayout |
| 28 | import androidx.fragment.app.Fragment | 28 | import androidx.fragment.app.Fragment |
| 29 | import androidx.fragment.app.activityViewModels | ||
| 29 | import androidx.lifecycle.Lifecycle | 30 | import androidx.lifecycle.Lifecycle |
| 30 | import androidx.lifecycle.lifecycleScope | 31 | import androidx.lifecycle.lifecycleScope |
| 31 | import androidx.lifecycle.repeatOnLifecycle | 32 | import androidx.lifecycle.repeatOnLifecycle |
| @@ -50,6 +51,7 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting | |||
| 50 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 51 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 51 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 52 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 52 | import org.yuzu.yuzu_emu.model.Game | 53 | import org.yuzu.yuzu_emu.model.Game |
| 54 | import org.yuzu.yuzu_emu.model.EmulationViewModel | ||
| 53 | import org.yuzu.yuzu_emu.overlay.InputOverlay | 55 | import org.yuzu.yuzu_emu.overlay.InputOverlay |
| 54 | import org.yuzu.yuzu_emu.utils.* | 56 | import org.yuzu.yuzu_emu.utils.* |
| 55 | 57 | ||
| @@ -66,6 +68,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 66 | 68 | ||
| 67 | private lateinit var game: Game | 69 | private lateinit var game: Game |
| 68 | 70 | ||
| 71 | private val emulationViewModel: EmulationViewModel by activityViewModels() | ||
| 72 | |||
| 69 | private var isInFoldableLayout = false | 73 | private var isInFoldableLayout = false |
| 70 | 74 | ||
| 71 | override fun onAttach(context: Context) { | 75 | override fun onAttach(context: Context) { |
| @@ -130,9 +134,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 130 | binding.showFpsText.setTextColor(Color.YELLOW) | 134 | binding.showFpsText.setTextColor(Color.YELLOW) |
| 131 | binding.doneControlConfig.setOnClickListener { stopConfiguringControls() } | 135 | binding.doneControlConfig.setOnClickListener { stopConfiguringControls() } |
| 132 | 136 | ||
| 133 | // Setup overlay. | 137 | binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) |
| 134 | updateShowFpsOverlay() | ||
| 135 | |||
| 136 | binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text = | 138 | binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text = |
| 137 | game.title | 139 | game.title |
| 138 | binding.inGameMenu.setNavigationItemSelectedListener { | 140 | binding.inGameMenu.setNavigationItemSelectedListener { |
| @@ -174,7 +176,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 174 | 176 | ||
| 175 | R.id.menu_exit -> { | 177 | R.id.menu_exit -> { |
| 176 | emulationState.stop() | 178 | emulationState.stop() |
| 177 | requireActivity().finish() | 179 | emulationViewModel.setIsEmulationStopping(true) |
| 180 | binding.drawerLayout.close() | ||
| 181 | binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) | ||
| 178 | true | 182 | true |
| 179 | } | 183 | } |
| 180 | 184 | ||
| @@ -188,6 +192,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 188 | requireActivity(), | 192 | requireActivity(), |
| 189 | object : OnBackPressedCallback(true) { | 193 | object : OnBackPressedCallback(true) { |
| 190 | override fun handleOnBackPressed() { | 194 | override fun handleOnBackPressed() { |
| 195 | if (!NativeLibrary.isRunning()) { | ||
| 196 | return | ||
| 197 | } | ||
| 198 | |||
| 191 | if (binding.drawerLayout.isOpen) { | 199 | if (binding.drawerLayout.isOpen) { |
| 192 | binding.drawerLayout.close() | 200 | binding.drawerLayout.close() |
| 193 | } else { | 201 | } else { |
| @@ -204,6 +212,54 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 204 | .collect { updateFoldableLayout(requireActivity() as EmulationActivity, it) } | 212 | .collect { updateFoldableLayout(requireActivity() as EmulationActivity, it) } |
| 205 | } | 213 | } |
| 206 | } | 214 | } |
| 215 | |||
| 216 | GameIconUtils.loadGameIcon(game, binding.loadingImage) | ||
| 217 | binding.loadingTitle.text = game.title | ||
| 218 | binding.loadingTitle.isSelected = true | ||
| 219 | binding.loadingText.isSelected = true | ||
| 220 | |||
| 221 | emulationViewModel.shaderProgress.observe(viewLifecycleOwner) { | ||
| 222 | if (it > 0 && it != emulationViewModel.totalShaders.value!!) { | ||
| 223 | binding.loadingProgressIndicator.isIndeterminate = false | ||
| 224 | |||
| 225 | if (it < binding.loadingProgressIndicator.max) { | ||
| 226 | binding.loadingProgressIndicator.progress = it | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | if (it == emulationViewModel.totalShaders.value!!) { | ||
| 231 | binding.loadingText.setText(R.string.loading) | ||
| 232 | binding.loadingProgressIndicator.isIndeterminate = true | ||
| 233 | } | ||
| 234 | } | ||
| 235 | emulationViewModel.totalShaders.observe(viewLifecycleOwner) { | ||
| 236 | binding.loadingProgressIndicator.max = it | ||
| 237 | } | ||
| 238 | emulationViewModel.shaderMessage.observe(viewLifecycleOwner) { | ||
| 239 | if (it.isNotEmpty()) { | ||
| 240 | binding.loadingText.text = it | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | emulationViewModel.emulationStarted.observe(viewLifecycleOwner) { started -> | ||
| 245 | if (started) { | ||
| 246 | binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED) | ||
| 247 | ViewUtils.showView(binding.surfaceInputOverlay) | ||
| 248 | ViewUtils.hideView(binding.loadingIndicator) | ||
| 249 | |||
| 250 | // Setup overlay | ||
| 251 | updateShowFpsOverlay() | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | emulationViewModel.isEmulationStopping.observe(viewLifecycleOwner) { | ||
| 256 | if (it) { | ||
| 257 | binding.loadingText.setText(R.string.shutting_down) | ||
| 258 | ViewUtils.showView(binding.loadingIndicator) | ||
| 259 | ViewUtils.hideView(binding.inputContainer) | ||
| 260 | ViewUtils.hideView(binding.showFpsText) | ||
| 261 | } | ||
| 262 | } | ||
| 207 | } | 263 | } |
| 208 | 264 | ||
| 209 | override fun onConfigurationChanged(newConfig: Configuration) { | 265 | override fun onConfigurationChanged(newConfig: Configuration) { |
| @@ -213,11 +269,21 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 213 | binding.drawerLayout.close() | 269 | binding.drawerLayout.close() |
| 214 | } | 270 | } |
| 215 | if (EmulationMenuSettings.showOverlay) { | 271 | if (EmulationMenuSettings.showOverlay) { |
| 216 | binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.isVisible = false } | 272 | binding.surfaceInputOverlay.post { |
| 273 | binding.surfaceInputOverlay.visibility = View.VISIBLE | ||
| 274 | } | ||
| 217 | } | 275 | } |
| 218 | } else { | 276 | } else { |
| 219 | if (EmulationMenuSettings.showOverlay) { | 277 | if (EmulationMenuSettings.showOverlay && |
| 220 | binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.isVisible = true } | 278 | emulationViewModel.emulationStarted.value == true |
| 279 | ) { | ||
| 280 | binding.surfaceInputOverlay.post { | ||
| 281 | binding.surfaceInputOverlay.visibility = View.VISIBLE | ||
| 282 | } | ||
| 283 | } else { | ||
| 284 | binding.surfaceInputOverlay.post { | ||
| 285 | binding.surfaceInputOverlay.visibility = View.INVISIBLE | ||
| 286 | } | ||
| 221 | } | 287 | } |
| 222 | if (!isInFoldableLayout) { | 288 | if (!isInFoldableLayout) { |
| 223 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { | 289 | if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { |
| @@ -226,9 +292,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 226 | binding.surfaceInputOverlay.layout = InputOverlay.LANDSCAPE | 292 | binding.surfaceInputOverlay.layout = InputOverlay.LANDSCAPE |
| 227 | } | 293 | } |
| 228 | } | 294 | } |
| 229 | if (!binding.surfaceInputOverlay.isInEditMode) { | ||
| 230 | refreshInputOverlay() | ||
| 231 | } | ||
| 232 | } | 295 | } |
| 233 | } | 296 | } |
| 234 | 297 | ||
| @@ -260,10 +323,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 260 | super.onDetach() | 323 | super.onDetach() |
| 261 | } | 324 | } |
| 262 | 325 | ||
| 263 | private fun refreshInputOverlay() { | ||
| 264 | binding.surfaceInputOverlay.refreshControls() | ||
| 265 | } | ||
| 266 | |||
| 267 | private fun resetInputOverlay() { | 326 | private fun resetInputOverlay() { |
| 268 | preferences.edit() | 327 | preferences.edit() |
| 269 | .remove(Settings.PREF_CONTROL_SCALE) | 328 | .remove(Settings.PREF_CONTROL_SCALE) |
| @@ -281,17 +340,15 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 281 | val FRAMETIME = 2 | 340 | val FRAMETIME = 2 |
| 282 | val SPEED = 3 | 341 | val SPEED = 3 |
| 283 | perfStatsUpdater = { | 342 | perfStatsUpdater = { |
| 284 | val perfStats = NativeLibrary.getPerfStats() | 343 | if (emulationViewModel.emulationStarted.value == true) { |
| 285 | if (perfStats[FPS] > 0 && _binding != null) { | 344 | val perfStats = NativeLibrary.getPerfStats() |
| 286 | binding.showFpsText.text = String.format("FPS: %.1f", perfStats[FPS]) | 345 | if (perfStats[FPS] > 0 && _binding != null) { |
| 287 | } | 346 | binding.showFpsText.text = String.format("FPS: %.1f", perfStats[FPS]) |
| 288 | 347 | } | |
| 289 | if (!emulationState.isStopped) { | ||
| 290 | perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 100) | 348 | perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 100) |
| 291 | } | 349 | } |
| 292 | } | 350 | } |
| 293 | perfStatsUpdateHandler.post(perfStatsUpdater!!) | 351 | perfStatsUpdateHandler.post(perfStatsUpdater!!) |
| 294 | binding.showFpsText.text = resources.getString(R.string.emulation_game_loading) | ||
| 295 | binding.showFpsText.visibility = View.VISIBLE | 352 | binding.showFpsText.visibility = View.VISIBLE |
| 296 | } else { | 353 | } else { |
| 297 | if (perfStatsUpdater != null) { | 354 | if (perfStatsUpdater != null) { |
| @@ -349,7 +406,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 349 | 406 | ||
| 350 | isInFoldableLayout = true | 407 | isInFoldableLayout = true |
| 351 | binding.surfaceInputOverlay.layout = InputOverlay.FOLDABLE | 408 | binding.surfaceInputOverlay.layout = InputOverlay.FOLDABLE |
| 352 | refreshInputOverlay() | ||
| 353 | } | 409 | } |
| 354 | } | 410 | } |
| 355 | it.isSeparating | 411 | it.isSeparating |
| @@ -437,7 +493,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 437 | .apply() | 493 | .apply() |
| 438 | } | 494 | } |
| 439 | .setPositiveButton(android.R.string.ok) { _, _ -> | 495 | .setPositiveButton(android.R.string.ok) { _, _ -> |
| 440 | refreshInputOverlay() | 496 | binding.surfaceInputOverlay.refreshControls() |
| 441 | } | 497 | } |
| 442 | .setNegativeButton(android.R.string.cancel, null) | 498 | .setNegativeButton(android.R.string.cancel, null) |
| 443 | .setNeutralButton(R.string.emulation_toggle_all) { _, _ -> } | 499 | .setNeutralButton(R.string.emulation_toggle_all) { _, _ -> } |
| @@ -461,7 +517,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 461 | R.id.menu_show_overlay -> { | 517 | R.id.menu_show_overlay -> { |
| 462 | it.isChecked = !it.isChecked | 518 | it.isChecked = !it.isChecked |
| 463 | EmulationMenuSettings.showOverlay = it.isChecked | 519 | EmulationMenuSettings.showOverlay = it.isChecked |
| 464 | refreshInputOverlay() | 520 | binding.surfaceInputOverlay.refreshControls() |
| 465 | true | 521 | true |
| 466 | } | 522 | } |
| 467 | 523 | ||
| @@ -567,14 +623,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 567 | preferences.edit() | 623 | preferences.edit() |
| 568 | .putInt(Settings.PREF_CONTROL_SCALE, scale) | 624 | .putInt(Settings.PREF_CONTROL_SCALE, scale) |
| 569 | .apply() | 625 | .apply() |
| 570 | refreshInputOverlay() | 626 | binding.surfaceInputOverlay.refreshControls() |
| 571 | } | 627 | } |
| 572 | 628 | ||
| 573 | private fun setControlOpacity(opacity: Int) { | 629 | private fun setControlOpacity(opacity: Int) { |
| 574 | preferences.edit() | 630 | preferences.edit() |
| 575 | .putInt(Settings.PREF_CONTROL_OPACITY, opacity) | 631 | .putInt(Settings.PREF_CONTROL_OPACITY, opacity) |
| 576 | .apply() | 632 | .apply() |
| 577 | refreshInputOverlay() | 633 | binding.surfaceInputOverlay.refreshControls() |
| 578 | } | 634 | } |
| 579 | 635 | ||
| 580 | private fun setInsets() { | 636 | private fun setInsets() { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt new file mode 100644 index 000000000..e35f51bc3 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.model | ||
| 5 | |||
| 6 | import androidx.lifecycle.LiveData | ||
| 7 | import androidx.lifecycle.MutableLiveData | ||
| 8 | import androidx.lifecycle.ViewModel | ||
| 9 | |||
| 10 | class EmulationViewModel : ViewModel() { | ||
| 11 | private val _emulationStarted = MutableLiveData(false) | ||
| 12 | val emulationStarted: LiveData<Boolean> get() = _emulationStarted | ||
| 13 | |||
| 14 | private val _isEmulationStopping = MutableLiveData(false) | ||
| 15 | val isEmulationStopping: LiveData<Boolean> get() = _isEmulationStopping | ||
| 16 | |||
| 17 | private val _shaderProgress = MutableLiveData(0) | ||
| 18 | val shaderProgress: LiveData<Int> get() = _shaderProgress | ||
| 19 | |||
| 20 | private val _totalShaders = MutableLiveData(0) | ||
| 21 | val totalShaders: LiveData<Int> get() = _totalShaders | ||
| 22 | |||
| 23 | private val _shaderMessage = MutableLiveData("") | ||
| 24 | val shaderMessage: LiveData<String> get() = _shaderMessage | ||
| 25 | |||
| 26 | fun setEmulationStarted(started: Boolean) { | ||
| 27 | _emulationStarted.postValue(started) | ||
| 28 | } | ||
| 29 | |||
| 30 | fun setIsEmulationStopping(value: Boolean) { | ||
| 31 | _isEmulationStopping.value = value | ||
| 32 | } | ||
| 33 | |||
| 34 | fun setShaderProgress(progress: Int) { | ||
| 35 | _shaderProgress.value = progress | ||
| 36 | } | ||
| 37 | |||
| 38 | fun setTotalShaders(max: Int) { | ||
| 39 | _totalShaders.value = max | ||
| 40 | } | ||
| 41 | |||
| 42 | fun setShaderMessage(msg: String) { | ||
| 43 | _shaderMessage.value = msg | ||
| 44 | } | ||
| 45 | |||
| 46 | fun updateProgress(msg: String, progress: Int, max: Int) { | ||
| 47 | setShaderMessage(msg) | ||
| 48 | setShaderProgress(progress) | ||
| 49 | setTotalShaders(max) | ||
| 50 | } | ||
| 51 | |||
| 52 | fun clear() { | ||
| 53 | _emulationStarted.value = false | ||
| 54 | _isEmulationStopping.value = false | ||
| 55 | _shaderProgress.value = 0 | ||
| 56 | _totalShaders.value = 0 | ||
| 57 | _shaderMessage.value = "" | ||
| 58 | } | ||
| 59 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt new file mode 100644 index 000000000..c0fe596d7 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.utils | ||
| 5 | |||
| 6 | import android.graphics.Bitmap | ||
| 7 | import android.graphics.BitmapFactory | ||
| 8 | import android.widget.ImageView | ||
| 9 | import androidx.core.graphics.drawable.toDrawable | ||
| 10 | import coil.ImageLoader | ||
| 11 | import coil.decode.DataSource | ||
| 12 | import coil.fetch.DrawableResult | ||
| 13 | import coil.fetch.FetchResult | ||
| 14 | import coil.fetch.Fetcher | ||
| 15 | import coil.key.Keyer | ||
| 16 | import coil.memory.MemoryCache | ||
| 17 | import coil.request.ImageRequest | ||
| 18 | import coil.request.Options | ||
| 19 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 20 | import org.yuzu.yuzu_emu.R | ||
| 21 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 22 | import org.yuzu.yuzu_emu.model.Game | ||
| 23 | |||
| 24 | class GameIconFetcher( | ||
| 25 | private val game: Game, | ||
| 26 | private val options: Options | ||
| 27 | ) : Fetcher { | ||
| 28 | override suspend fun fetch(): FetchResult { | ||
| 29 | return DrawableResult( | ||
| 30 | drawable = decodeGameIcon(game.path)!!.toDrawable(options.context.resources), | ||
| 31 | isSampled = false, | ||
| 32 | dataSource = DataSource.DISK | ||
| 33 | ) | ||
| 34 | } | ||
| 35 | |||
| 36 | private fun decodeGameIcon(uri: String): Bitmap? { | ||
| 37 | val data = NativeLibrary.getIcon(uri) | ||
| 38 | return BitmapFactory.decodeByteArray( | ||
| 39 | data, | ||
| 40 | 0, | ||
| 41 | data.size, | ||
| 42 | BitmapFactory.Options() | ||
| 43 | ) | ||
| 44 | } | ||
| 45 | |||
| 46 | class Factory : Fetcher.Factory<Game> { | ||
| 47 | override fun create(data: Game, options: Options, imageLoader: ImageLoader): Fetcher = | ||
| 48 | GameIconFetcher(data, options) | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | class GameIconKeyer : Keyer<Game> { | ||
| 53 | override fun key(data: Game, options: Options): String = data.path | ||
| 54 | } | ||
| 55 | |||
| 56 | object GameIconUtils { | ||
| 57 | private val imageLoader = ImageLoader.Builder(YuzuApplication.appContext) | ||
| 58 | .components { | ||
| 59 | add(GameIconKeyer()) | ||
| 60 | add(GameIconFetcher.Factory()) | ||
| 61 | } | ||
| 62 | .memoryCache { | ||
| 63 | MemoryCache.Builder(YuzuApplication.appContext) | ||
| 64 | .maxSizePercent(0.25) | ||
| 65 | .build() | ||
| 66 | } | ||
| 67 | .build() | ||
| 68 | |||
| 69 | fun loadGameIcon(game: Game, imageView: ImageView) { | ||
| 70 | val request = ImageRequest.Builder(YuzuApplication.appContext) | ||
| 71 | .data(game) | ||
| 72 | .target(imageView) | ||
| 73 | .error(R.drawable.default_icon) | ||
| 74 | .build() | ||
| 75 | imageLoader.enqueue(request) | ||
| 76 | } | ||
| 77 | } | ||
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp index 9cbbf23a3..960abf95a 100644 --- a/src/android/app/src/main/jni/id_cache.cpp +++ b/src/android/app/src/main/jni/id_cache.cpp | |||
| @@ -15,6 +15,8 @@ static jclass s_disk_cache_progress_class; | |||
| 15 | static jclass s_load_callback_stage_class; | 15 | static jclass s_load_callback_stage_class; |
| 16 | static jmethodID s_exit_emulation_activity; | 16 | static jmethodID s_exit_emulation_activity; |
| 17 | static jmethodID s_disk_cache_load_progress; | 17 | static jmethodID s_disk_cache_load_progress; |
| 18 | static jmethodID s_on_emulation_started; | ||
| 19 | static jmethodID s_on_emulation_stopped; | ||
| 18 | 20 | ||
| 19 | static constexpr jint JNI_VERSION = JNI_VERSION_1_6; | 21 | static constexpr jint JNI_VERSION = JNI_VERSION_1_6; |
| 20 | 22 | ||
| @@ -59,6 +61,14 @@ jmethodID GetDiskCacheLoadProgress() { | |||
| 59 | return s_disk_cache_load_progress; | 61 | return s_disk_cache_load_progress; |
| 60 | } | 62 | } |
| 61 | 63 | ||
| 64 | jmethodID GetOnEmulationStarted() { | ||
| 65 | return s_on_emulation_started; | ||
| 66 | } | ||
| 67 | |||
| 68 | jmethodID GetOnEmulationStopped() { | ||
| 69 | return s_on_emulation_stopped; | ||
| 70 | } | ||
| 71 | |||
| 62 | } // namespace IDCache | 72 | } // namespace IDCache |
| 63 | 73 | ||
| 64 | #ifdef __cplusplus | 74 | #ifdef __cplusplus |
| @@ -85,6 +95,10 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { | |||
| 85 | env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); | 95 | env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V"); |
| 86 | s_disk_cache_load_progress = | 96 | s_disk_cache_load_progress = |
| 87 | env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V"); | 97 | env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V"); |
| 98 | s_on_emulation_started = | ||
| 99 | env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V"); | ||
| 100 | s_on_emulation_stopped = | ||
| 101 | env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V"); | ||
| 88 | 102 | ||
| 89 | // Initialize Android Storage | 103 | // Initialize Android Storage |
| 90 | Common::FS::Android::RegisterCallbacks(env, s_native_library_class); | 104 | Common::FS::Android::RegisterCallbacks(env, s_native_library_class); |
diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h index be535fe1e..b76158928 100644 --- a/src/android/app/src/main/jni/id_cache.h +++ b/src/android/app/src/main/jni/id_cache.h | |||
| @@ -15,5 +15,7 @@ jclass GetDiskCacheProgressClass(); | |||
| 15 | jclass GetDiskCacheLoadCallbackStageClass(); | 15 | jclass GetDiskCacheLoadCallbackStageClass(); |
| 16 | jmethodID GetExitEmulationActivity(); | 16 | jmethodID GetExitEmulationActivity(); |
| 17 | jmethodID GetDiskCacheLoadProgress(); | 17 | jmethodID GetDiskCacheLoadProgress(); |
| 18 | jmethodID GetOnEmulationStarted(); | ||
| 19 | jmethodID GetOnEmulationStopped(); | ||
| 18 | 20 | ||
| 19 | } // namespace IDCache | 21 | } // namespace IDCache |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index b2adfdeda..0f2a6d9e4 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -203,12 +203,10 @@ public: | |||
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | bool IsRunning() const { | 205 | bool IsRunning() const { |
| 206 | std::scoped_lock lock(m_mutex); | ||
| 207 | return m_is_running; | 206 | return m_is_running; |
| 208 | } | 207 | } |
| 209 | 208 | ||
| 210 | bool IsPaused() const { | 209 | bool IsPaused() const { |
| 211 | std::scoped_lock lock(m_mutex); | ||
| 212 | return m_is_running && m_is_paused; | 210 | return m_is_running && m_is_paused; |
| 213 | } | 211 | } |
| 214 | 212 | ||
| @@ -335,6 +333,8 @@ public: | |||
| 335 | 333 | ||
| 336 | // Tear down the render window. | 334 | // Tear down the render window. |
| 337 | m_window.reset(); | 335 | m_window.reset(); |
| 336 | |||
| 337 | OnEmulationStopped(m_load_result); | ||
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | void PauseEmulation() { | 340 | void PauseEmulation() { |
| @@ -376,6 +376,8 @@ public: | |||
| 376 | m_system.InitializeDebugger(); | 376 | m_system.InitializeDebugger(); |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | OnEmulationStarted(); | ||
| 380 | |||
| 379 | while (true) { | 381 | while (true) { |
| 380 | { | 382 | { |
| 381 | [[maybe_unused]] std::unique_lock lock(m_mutex); | 383 | [[maybe_unused]] std::unique_lock lock(m_mutex); |
| @@ -511,6 +513,18 @@ private: | |||
| 511 | static_cast<jint>(progress), static_cast<jint>(max)); | 513 | static_cast<jint>(progress), static_cast<jint>(max)); |
| 512 | } | 514 | } |
| 513 | 515 | ||
| 516 | static void OnEmulationStarted() { | ||
| 517 | JNIEnv* env = IDCache::GetEnvForThread(); | ||
| 518 | env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), | ||
| 519 | IDCache::GetOnEmulationStarted()); | ||
| 520 | } | ||
| 521 | |||
| 522 | static void OnEmulationStopped(Core::SystemResultStatus result) { | ||
| 523 | JNIEnv* env = IDCache::GetEnvForThread(); | ||
| 524 | env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), | ||
| 525 | IDCache::GetOnEmulationStopped(), static_cast<jint>(result)); | ||
| 526 | } | ||
| 527 | |||
| 514 | private: | 528 | private: |
| 515 | static EmulationSession s_instance; | 529 | static EmulationSession s_instance; |
| 516 | 530 | ||
| @@ -528,8 +542,8 @@ private: | |||
| 528 | Core::PerfStatsResults m_perf_stats{}; | 542 | Core::PerfStatsResults m_perf_stats{}; |
| 529 | std::shared_ptr<FileSys::VfsFilesystem> m_vfs; | 543 | std::shared_ptr<FileSys::VfsFilesystem> m_vfs; |
| 530 | Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized}; | 544 | Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized}; |
| 531 | bool m_is_running{}; | 545 | std::atomic<bool> m_is_running = false; |
| 532 | bool m_is_paused{}; | 546 | std::atomic<bool> m_is_paused = false; |
| 533 | SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; | 547 | SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; |
| 534 | std::unique_ptr<Service::Account::ProfileManager> m_profile_manager; | 548 | std::unique_ptr<Service::Account::ProfileManager> m_profile_manager; |
| 535 | std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; | 549 | std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; |
diff --git a/src/android/app/src/main/res/layout/fragment_emulation.xml b/src/android/app/src/main/res/layout/fragment_emulation.xml index e54a10e8f..da97d85c1 100644 --- a/src/android/app/src/main/res/layout/fragment_emulation.xml +++ b/src/android/app/src/main/res/layout/fragment_emulation.xml | |||
| @@ -26,6 +26,81 @@ | |||
| 26 | android:focusable="false" | 26 | android:focusable="false" |
| 27 | android:focusableInTouchMode="false" /> | 27 | android:focusableInTouchMode="false" /> |
| 28 | 28 | ||
| 29 | <com.google.android.material.card.MaterialCardView | ||
| 30 | android:id="@+id/loading_indicator" | ||
| 31 | style="?attr/materialCardViewOutlinedStyle" | ||
| 32 | android:layout_width="wrap_content" | ||
| 33 | android:layout_height="wrap_content" | ||
| 34 | android:layout_gravity="center" | ||
| 35 | android:focusable="false"> | ||
| 36 | |||
| 37 | <androidx.constraintlayout.widget.ConstraintLayout | ||
| 38 | android:id="@+id/loading_layout" | ||
| 39 | android:layout_width="wrap_content" | ||
| 40 | android:layout_height="wrap_content" | ||
| 41 | android:gravity="center_horizontal"> | ||
| 42 | |||
| 43 | <ImageView | ||
| 44 | android:id="@+id/loading_image" | ||
| 45 | android:layout_width="wrap_content" | ||
| 46 | android:layout_height="0dp" | ||
| 47 | android:adjustViewBounds="true" | ||
| 48 | app:layout_constraintBottom_toBottomOf="@+id/linearLayout" | ||
| 49 | app:layout_constraintStart_toStartOf="parent" | ||
| 50 | app:layout_constraintTop_toTopOf="@+id/linearLayout" | ||
| 51 | tools:src="@drawable/default_icon" /> | ||
| 52 | |||
| 53 | <LinearLayout | ||
| 54 | android:id="@+id/linearLayout" | ||
| 55 | android:layout_width="wrap_content" | ||
| 56 | android:layout_height="wrap_content" | ||
| 57 | android:orientation="vertical" | ||
| 58 | android:paddingHorizontal="24dp" | ||
| 59 | android:paddingVertical="36dp" | ||
| 60 | app:layout_constraintBottom_toBottomOf="parent" | ||
| 61 | app:layout_constraintEnd_toEndOf="parent" | ||
| 62 | app:layout_constraintStart_toEndOf="@id/loading_image" | ||
| 63 | app:layout_constraintTop_toTopOf="parent"> | ||
| 64 | |||
| 65 | <com.google.android.material.textview.MaterialTextView | ||
| 66 | android:id="@+id/loading_title" | ||
| 67 | style="@style/TextAppearance.Material3.TitleMedium" | ||
| 68 | android:layout_width="match_parent" | ||
| 69 | android:layout_height="wrap_content" | ||
| 70 | android:ellipsize="marquee" | ||
| 71 | android:marqueeRepeatLimit="marquee_forever" | ||
| 72 | android:requiresFadingEdge="horizontal" | ||
| 73 | android:singleLine="true" | ||
| 74 | android:textAlignment="viewStart" | ||
| 75 | tools:text="@string/games" /> | ||
| 76 | |||
| 77 | <com.google.android.material.textview.MaterialTextView | ||
| 78 | android:id="@+id/loading_text" | ||
| 79 | style="@style/TextAppearance.Material3.TitleSmall" | ||
| 80 | android:layout_width="match_parent" | ||
| 81 | android:layout_height="wrap_content" | ||
| 82 | android:layout_marginTop="4dp" | ||
| 83 | android:ellipsize="marquee" | ||
| 84 | android:marqueeRepeatLimit="marquee_forever" | ||
| 85 | android:requiresFadingEdge="horizontal" | ||
| 86 | android:singleLine="true" | ||
| 87 | android:text="@string/loading" | ||
| 88 | android:textAlignment="viewStart" /> | ||
| 89 | |||
| 90 | <com.google.android.material.progressindicator.LinearProgressIndicator | ||
| 91 | android:id="@+id/loading_progress_indicator" | ||
| 92 | android:layout_width="192dp" | ||
| 93 | android:layout_height="wrap_content" | ||
| 94 | android:layout_marginTop="12dp" | ||
| 95 | android:indeterminate="true" | ||
| 96 | app:trackCornerRadius="8dp" /> | ||
| 97 | |||
| 98 | </LinearLayout> | ||
| 99 | |||
| 100 | </androidx.constraintlayout.widget.ConstraintLayout> | ||
| 101 | |||
| 102 | </com.google.android.material.card.MaterialCardView> | ||
| 103 | |||
| 29 | </FrameLayout> | 104 | </FrameLayout> |
| 30 | 105 | ||
| 31 | <FrameLayout | 106 | <FrameLayout |
| @@ -41,11 +116,12 @@ | |||
| 41 | android:layout_height="match_parent" | 116 | android:layout_height="match_parent" |
| 42 | android:layout_gravity="center" | 117 | android:layout_gravity="center" |
| 43 | android:focusable="true" | 118 | android:focusable="true" |
| 44 | android:focusableInTouchMode="true" /> | 119 | android:focusableInTouchMode="true" |
| 120 | android:visibility="invisible" /> | ||
| 45 | 121 | ||
| 46 | <Button | 122 | <Button |
| 47 | style="@style/Widget.Material3.Button.ElevatedButton" | ||
| 48 | android:id="@+id/done_control_config" | 123 | android:id="@+id/done_control_config" |
| 124 | style="@style/Widget.Material3.Button.ElevatedButton" | ||
| 49 | android:layout_width="wrap_content" | 125 | android:layout_width="wrap_content" |
| 50 | android:layout_height="wrap_content" | 126 | android:layout_height="wrap_content" |
| 51 | android:layout_gravity="center" | 127 | android:layout_gravity="center" |
| @@ -81,6 +157,7 @@ | |||
| 81 | android:layout_height="match_parent" | 157 | android:layout_height="match_parent" |
| 82 | android:layout_gravity="start|bottom" | 158 | android:layout_gravity="start|bottom" |
| 83 | app:headerLayout="@layout/header_in_game" | 159 | app:headerLayout="@layout/header_in_game" |
| 84 | app:menu="@menu/menu_in_game" /> | 160 | app:menu="@menu/menu_in_game" |
| 161 | tools:visibility="gone" /> | ||
| 85 | 162 | ||
| 86 | </androidx.drawerlayout.widget.DrawerLayout> | 163 | </androidx.drawerlayout.widget.DrawerLayout> |
diff --git a/src/android/app/src/main/res/values-de/strings.xml b/src/android/app/src/main/res/values-de/strings.xml index 0c1d91264..daaa7ffde 100644 --- a/src/android/app/src/main/res/values-de/strings.xml +++ b/src/android/app/src/main/res/values-de/strings.xml | |||
| @@ -209,7 +209,6 @@ | |||
| 209 | <string name="emulation_pause">Emulation pausieren</string> | 209 | <string name="emulation_pause">Emulation pausieren</string> |
| 210 | <string name="emulation_unpause">Emulation fortsetzen</string> | 210 | <string name="emulation_unpause">Emulation fortsetzen</string> |
| 211 | <string name="emulation_input_overlay">Overlay-Optionen</string> | 211 | <string name="emulation_input_overlay">Overlay-Optionen</string> |
| 212 | <string name="emulation_game_loading">Spiel lädt…</string> | ||
| 213 | 212 | ||
| 214 | <string name="load_settings">Lädt Einstellungen...</string> | 213 | <string name="load_settings">Lädt Einstellungen...</string> |
| 215 | 214 | ||
diff --git a/src/android/app/src/main/res/values-es/strings.xml b/src/android/app/src/main/res/values-es/strings.xml index 357f956d1..e9129cb00 100644 --- a/src/android/app/src/main/res/values-es/strings.xml +++ b/src/android/app/src/main/res/values-es/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Pausar Emulación</string> | 213 | <string name="emulation_pause">Pausar Emulación</string> |
| 214 | <string name="emulation_unpause">Reanudar Emulación</string> | 214 | <string name="emulation_unpause">Reanudar Emulación</string> |
| 215 | <string name="emulation_input_overlay">Opciones de pantalla </string> | 215 | <string name="emulation_input_overlay">Opciones de pantalla </string> |
| 216 | <string name="emulation_game_loading">Cargando juego...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Cargando configuración...</string> | 217 | <string name="load_settings">Cargando configuración...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-fr/strings.xml b/src/android/app/src/main/res/values-fr/strings.xml index dfca1c830..2d99d618e 100644 --- a/src/android/app/src/main/res/values-fr/strings.xml +++ b/src/android/app/src/main/res/values-fr/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Mettre en pause l\'émulation</string> | 213 | <string name="emulation_pause">Mettre en pause l\'émulation</string> |
| 214 | <string name="emulation_unpause">Reprendre l\'émulation</string> | 214 | <string name="emulation_unpause">Reprendre l\'émulation</string> |
| 215 | <string name="emulation_input_overlay">Options de l\'overlay</string> | 215 | <string name="emulation_input_overlay">Options de l\'overlay</string> |
| 216 | <string name="emulation_game_loading">Chargement du jeu...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Chargement des paramètres…</string> | 217 | <string name="load_settings">Chargement des paramètres…</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-it/strings.xml b/src/android/app/src/main/res/values-it/strings.xml index 089d93ed6..d9c3de385 100644 --- a/src/android/app/src/main/res/values-it/strings.xml +++ b/src/android/app/src/main/res/values-it/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Metti in pausa l\'emulazione</string> | 213 | <string name="emulation_pause">Metti in pausa l\'emulazione</string> |
| 214 | <string name="emulation_unpause">Riprendi Emulazione</string> | 214 | <string name="emulation_unpause">Riprendi Emulazione</string> |
| 215 | <string name="emulation_input_overlay">Impostazioni Overlay</string> | 215 | <string name="emulation_input_overlay">Impostazioni Overlay</string> |
| 216 | <string name="emulation_game_loading">Caricamento del gioco...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Caricamento delle impostazioni...</string> | 217 | <string name="load_settings">Caricamento delle impostazioni...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-ja/strings.xml b/src/android/app/src/main/res/values-ja/strings.xml index 39b590bee..7a226cd5c 100644 --- a/src/android/app/src/main/res/values-ja/strings.xml +++ b/src/android/app/src/main/res/values-ja/strings.xml | |||
| @@ -211,7 +211,6 @@ | |||
| 211 | <string name="emulation_pause">エミュレーションを一時停止</string> | 211 | <string name="emulation_pause">エミュレーションを一時停止</string> |
| 212 | <string name="emulation_unpause">エミュレーションを再開</string> | 212 | <string name="emulation_unpause">エミュレーションを再開</string> |
| 213 | <string name="emulation_input_overlay">オーバーレイオプション</string> | 213 | <string name="emulation_input_overlay">オーバーレイオプション</string> |
| 214 | <string name="emulation_game_loading">ロード中…</string> | ||
| 215 | 214 | ||
| 216 | <string name="load_settings">設定をロード中…</string> | 215 | <string name="load_settings">設定をロード中…</string> |
| 217 | 216 | ||
diff --git a/src/android/app/src/main/res/values-ko/strings.xml b/src/android/app/src/main/res/values-ko/strings.xml index cbcb2873f..427b6e5a0 100644 --- a/src/android/app/src/main/res/values-ko/strings.xml +++ b/src/android/app/src/main/res/values-ko/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">에뮬레이션 일시 중지</string> | 213 | <string name="emulation_pause">에뮬레이션 일시 중지</string> |
| 214 | <string name="emulation_unpause">에뮬레이션 일시 중지 해제</string> | 214 | <string name="emulation_unpause">에뮬레이션 일시 중지 해제</string> |
| 215 | <string name="emulation_input_overlay">오버레이 옵션</string> | 215 | <string name="emulation_input_overlay">오버레이 옵션</string> |
| 216 | <string name="emulation_game_loading">게임 불러오기 중...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">설정 불러오기 중...</string> | 217 | <string name="load_settings">설정 불러오기 중...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-nb/strings.xml b/src/android/app/src/main/res/values-nb/strings.xml index e48a4be38..ce8d7a9e4 100644 --- a/src/android/app/src/main/res/values-nb/strings.xml +++ b/src/android/app/src/main/res/values-nb/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Pause Emulering</string> | 213 | <string name="emulation_pause">Pause Emulering</string> |
| 214 | <string name="emulation_unpause">Opphev pausing av emulering</string> | 214 | <string name="emulation_unpause">Opphev pausing av emulering</string> |
| 215 | <string name="emulation_input_overlay">Alternativer for overlegg</string> | 215 | <string name="emulation_input_overlay">Alternativer for overlegg</string> |
| 216 | <string name="emulation_game_loading">Spillet lastes inn...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Laster inn innstillinger...</string> | 217 | <string name="load_settings">Laster inn innstillinger...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-pl/strings.xml b/src/android/app/src/main/res/values-pl/strings.xml index bc9c0f7f4..c2c24b48f 100644 --- a/src/android/app/src/main/res/values-pl/strings.xml +++ b/src/android/app/src/main/res/values-pl/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Wstrzymaj emulację</string> | 213 | <string name="emulation_pause">Wstrzymaj emulację</string> |
| 214 | <string name="emulation_unpause">Wznów emulację</string> | 214 | <string name="emulation_unpause">Wznów emulację</string> |
| 215 | <string name="emulation_input_overlay">Opcje nakładki</string> | 215 | <string name="emulation_input_overlay">Opcje nakładki</string> |
| 216 | <string name="emulation_game_loading">Wczytywanie gry...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Wczytywanie ustawień...</string> | 217 | <string name="load_settings">Wczytywanie ustawień...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-pt-rBR/strings.xml b/src/android/app/src/main/res/values-pt-rBR/strings.xml index 75fe0edbf..04f276108 100644 --- a/src/android/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/android/app/src/main/res/values-pt-rBR/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Pausa emulação</string> | 213 | <string name="emulation_pause">Pausa emulação</string> |
| 214 | <string name="emulation_unpause">Retomar emulação</string> | 214 | <string name="emulation_unpause">Retomar emulação</string> |
| 215 | <string name="emulation_input_overlay">Opções de sobreposição </string> | 215 | <string name="emulation_input_overlay">Opções de sobreposição </string> |
| 216 | <string name="emulation_game_loading">Jogo a carregar...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Configurações a carregar...</string> | 217 | <string name="load_settings">Configurações a carregar...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-pt-rPT/strings.xml b/src/android/app/src/main/res/values-pt-rPT/strings.xml index 96b040c66..66a3a1a2e 100644 --- a/src/android/app/src/main/res/values-pt-rPT/strings.xml +++ b/src/android/app/src/main/res/values-pt-rPT/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Pausa emulação</string> | 213 | <string name="emulation_pause">Pausa emulação</string> |
| 214 | <string name="emulation_unpause">Retomar emulação</string> | 214 | <string name="emulation_unpause">Retomar emulação</string> |
| 215 | <string name="emulation_input_overlay">Opções de sobreposição </string> | 215 | <string name="emulation_input_overlay">Opções de sobreposição </string> |
| 216 | <string name="emulation_game_loading">Jogo a carregar...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Configurações a carregar...</string> | 217 | <string name="load_settings">Configurações a carregar...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-ru/strings.xml b/src/android/app/src/main/res/values-ru/strings.xml index 8d954f59e..f770e954f 100644 --- a/src/android/app/src/main/res/values-ru/strings.xml +++ b/src/android/app/src/main/res/values-ru/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Пауза эмуляции</string> | 213 | <string name="emulation_pause">Пауза эмуляции</string> |
| 214 | <string name="emulation_unpause">Возобновление эмуляции</string> | 214 | <string name="emulation_unpause">Возобновление эмуляции</string> |
| 215 | <string name="emulation_input_overlay">Настройки оверлея</string> | 215 | <string name="emulation_input_overlay">Настройки оверлея</string> |
| 216 | <string name="emulation_game_loading">Загрузка игры...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Загрузка настроек...</string> | 217 | <string name="load_settings">Загрузка настроек...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-uk/strings.xml b/src/android/app/src/main/res/values-uk/strings.xml index 6c028535b..ea3ab1b15 100644 --- a/src/android/app/src/main/res/values-uk/strings.xml +++ b/src/android/app/src/main/res/values-uk/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">Пауза емуляції</string> | 213 | <string name="emulation_pause">Пауза емуляції</string> |
| 214 | <string name="emulation_unpause">Відновлення емуляції</string> | 214 | <string name="emulation_unpause">Відновлення емуляції</string> |
| 215 | <string name="emulation_input_overlay">Налаштування оверлея</string> | 215 | <string name="emulation_input_overlay">Налаштування оверлея</string> |
| 216 | <string name="emulation_game_loading">Завантаження гри...</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">Завантаження налаштувань...</string> | 217 | <string name="load_settings">Завантаження налаштувань...</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-zh-rCN/strings.xml b/src/android/app/src/main/res/values-zh-rCN/strings.xml index e4ad2ed07..b45a5a528 100644 --- a/src/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/src/android/app/src/main/res/values-zh-rCN/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">暂停模拟</string> | 213 | <string name="emulation_pause">暂停模拟</string> |
| 214 | <string name="emulation_unpause">继续模拟</string> | 214 | <string name="emulation_unpause">继续模拟</string> |
| 215 | <string name="emulation_input_overlay">虚拟按键选项</string> | 215 | <string name="emulation_input_overlay">虚拟按键选项</string> |
| 216 | <string name="emulation_game_loading">载入游戏中…</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">正在载入设定…</string> | 217 | <string name="load_settings">正在载入设定…</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values-zh-rTW/strings.xml b/src/android/app/src/main/res/values-zh-rTW/strings.xml index 0d32f23df..3aab889e4 100644 --- a/src/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/src/android/app/src/main/res/values-zh-rTW/strings.xml | |||
| @@ -213,7 +213,6 @@ | |||
| 213 | <string name="emulation_pause">暫停模擬</string> | 213 | <string name="emulation_pause">暫停模擬</string> |
| 214 | <string name="emulation_unpause">取消暫停模擬</string> | 214 | <string name="emulation_unpause">取消暫停模擬</string> |
| 215 | <string name="emulation_input_overlay">覆疊選項</string> | 215 | <string name="emulation_input_overlay">覆疊選項</string> |
| 216 | <string name="emulation_game_loading">遊戲正在載入…</string> | ||
| 217 | 216 | ||
| 218 | <string name="load_settings">正在載入設定…</string> | 217 | <string name="load_settings">正在載入設定…</string> |
| 219 | 218 | ||
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index d43891cec..b163e6fc1 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -204,6 +204,7 @@ | |||
| 204 | <string name="error_saving">Error saving %1$s.ini: %2$s</string> | 204 | <string name="error_saving">Error saving %1$s.ini: %2$s</string> |
| 205 | <string name="unimplemented_menu">Unimplemented Menu</string> | 205 | <string name="unimplemented_menu">Unimplemented Menu</string> |
| 206 | <string name="loading">Loading…</string> | 206 | <string name="loading">Loading…</string> |
| 207 | <string name="shutting_down">Shutting down…</string> | ||
| 207 | <string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string> | 208 | <string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string> |
| 208 | <string name="reset_to_default">Reset to default</string> | 209 | <string name="reset_to_default">Reset to default</string> |
| 209 | <string name="reset_all_settings">Reset all settings?</string> | 210 | <string name="reset_all_settings">Reset all settings?</string> |
| @@ -262,7 +263,6 @@ | |||
| 262 | <string name="emulation_pause">Pause emulation</string> | 263 | <string name="emulation_pause">Pause emulation</string> |
| 263 | <string name="emulation_unpause">Unpause emulation</string> | 264 | <string name="emulation_unpause">Unpause emulation</string> |
| 264 | <string name="emulation_input_overlay">Overlay options</string> | 265 | <string name="emulation_input_overlay">Overlay options</string> |
| 265 | <string name="emulation_game_loading">Game loading…</string> | ||
| 266 | 266 | ||
| 267 | <string name="load_settings">Loading settings…</string> | 267 | <string name="load_settings">Loading settings…</string> |
| 268 | 268 | ||