diff options
27 files changed, 394 insertions, 104 deletions
@@ -1,7 +1,7 @@ | |||
1 | yuzu emulator early access | 1 | yuzu emulator early access |
2 | ============= | 2 | ============= |
3 | 3 | ||
4 | This is the source code for early-access 3848. | 4 | This is the source code for early-access 3849. |
5 | 5 | ||
6 | ## Legal Notice | 6 | ## Legal Notice |
7 | 7 | ||
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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 53f19c4f8..944ae652e 100755 --- 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 100755 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 100755 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 100755 --- 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 | ||