summaryrefslogtreecommitdiffstats
path: root/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt307
1 files changed, 63 insertions, 244 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 69a371947..a16ca8529 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -3,42 +3,31 @@
package org.yuzu.yuzu_emu.ui.main
-import android.content.DialogInterface
-import android.content.Intent
import android.os.Bundle
-import android.view.Menu
-import android.view.MenuItem
import android.view.View
-import android.widget.Toast
-import androidx.activity.result.contract.ActivityResultContracts
+import android.view.ViewGroup.MarginLayoutParams
+import android.view.animation.PathInterpolator
+import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
-import androidx.core.view.updatePadding
-import androidx.lifecycle.lifecycleScope
-import androidx.preference.PreferenceManager
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import org.yuzu.yuzu_emu.NativeLibrary
+import androidx.navigation.fragment.NavHostFragment
+import androidx.navigation.ui.setupWithNavController
+import com.google.android.material.color.MaterialColors
+import com.google.android.material.elevation.ElevationOverlayProvider
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
-import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
-import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
-import org.yuzu.yuzu_emu.ui.platform.PlatformGamesFragment
+import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.*
-import java.io.IOException
-
-class MainActivity : AppCompatActivity(), MainView {
- private var platformGamesFragment: PlatformGamesFragment? = null
- private val presenter = MainPresenter(this)
+class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
+ private val homeViewModel: HomeViewModel by viewModels()
+
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
@@ -52,19 +41,36 @@ class MainActivity : AppCompatActivity(), MainView {
WindowCompat.setDecorFitsSystemWindows(window, false)
- setSupportActionBar(binding.toolbarMain)
- presenter.onCreate()
- if (savedInstanceState == null) {
- StartupHandler.handleInit(this)
- platformGamesFragment = PlatformGamesFragment()
- supportFragmentManager.beginTransaction()
- .add(R.id.games_platform_frame, platformGamesFragment!!)
- .commit()
- } else {
- platformGamesFragment = supportFragmentManager.getFragment(
- savedInstanceState,
- PlatformGamesFragment.TAG
- ) as PlatformGamesFragment?
+ ThemeHelper.setNavigationBarColor(
+ this,
+ ElevationOverlayProvider(binding.navigationBar.context).compositeOverlay(
+ MaterialColors.getColor(binding.navigationBar, R.attr.colorSurface),
+ binding.navigationBar.elevation
+ )
+ )
+
+ // Set up a central host fragment that is controlled via bottom navigation with xml navigation
+ val navHostFragment =
+ supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
+ binding.navigationBar.setupWithNavController(navHostFragment.navController)
+
+ binding.statusBarShade.setBackgroundColor(
+ ThemeHelper.getColorWithOpacity(
+ MaterialColors.getColor(
+ binding.root,
+ R.attr.colorSurface
+ ), ThemeHelper.SYSTEM_BAR_ALPHA
+ )
+ )
+
+ // Prevents navigation from being drawn for a short time on recreation if set to hidden
+ if (homeViewModel.navigationVisible.value == false) {
+ binding.navigationBar.visibility = View.INVISIBLE
+ binding.statusBarShade.visibility = View.INVISIBLE
+ }
+
+ homeViewModel.navigationVisible.observe(this) { visible ->
+ showNavigation(visible)
}
// Dismiss previous notifications (should not happen unless a crash occurred)
@@ -73,78 +79,24 @@ class MainActivity : AppCompatActivity(), MainView {
setInsets()
}
- override fun onSaveInstanceState(outState: Bundle) {
- super.onSaveInstanceState(outState)
- supportFragmentManager.putFragment(
- outState,
- PlatformGamesFragment.TAG,
- platformGamesFragment!!
- )
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.menu_game_grid, menu)
- return true
- }
-
- /**
- * MainView
- */
- override fun setVersionString(version: String) {
- binding.toolbarMain.subtitle = version
- }
-
- override fun launchSettingsActivity(menuTag: String) {
- SettingsActivity.launch(this, menuTag, "")
- }
-
- override fun launchFileListActivity(request: Int) {
- when (request) {
- MainPresenter.REQUEST_ADD_DIRECTORY -> getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
- MainPresenter.REQUEST_INSTALL_KEYS -> getProdKey.launch(arrayOf("*/*"))
- MainPresenter.REQUEST_INSTALL_AMIIBO_KEYS -> getAmiiboKey.launch(arrayOf("*/*"))
- MainPresenter.REQUEST_SELECT_GPU_DRIVER -> {
- // Get the driver name for the dialog message.
- var driverName = GpuDriverHelper.customDriverName
- if (driverName == null) {
- driverName = getString(R.string.system_gpu_driver)
- }
-
- MaterialAlertDialogBuilder(this)
- .setTitle(getString(R.string.select_gpu_driver_title))
- .setMessage(driverName)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.select_gpu_driver_default) { _: DialogInterface?, _: Int ->
- GpuDriverHelper.installDefaultDriver(this)
- Toast.makeText(
- this,
- R.string.select_gpu_driver_use_default,
- Toast.LENGTH_SHORT
- ).show()
- }
- .setNeutralButton(R.string.select_gpu_driver_install) { _: DialogInterface?, _: Int ->
- getDriver.launch(arrayOf("application/zip"))
- }
- .show()
+ private fun showNavigation(visible: Boolean) {
+ binding.navigationBar.animate().apply {
+ if (visible) {
+ binding.navigationBar.visibility = View.VISIBLE
+ binding.navigationBar.translationY = binding.navigationBar.height.toFloat() * 2
+ duration = 300
+ translationY(0f)
+ interpolator = PathInterpolator(0.05f, 0.7f, 0.1f, 1f)
+ } else {
+ duration = 300
+ translationY(binding.navigationBar.height.toFloat() * 2)
+ interpolator = PathInterpolator(0.3f, 0f, 0.8f, 0.15f)
}
- }
- }
-
- /**
- * Called by the framework whenever any actionbar/toolbar icon is clicked.
- *
- * @param item The icon that was clicked on.
- * @return True if the event was handled, false to bubble it up to the OS.
- */
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return presenter.handleOptionSelection(item.itemId)
- }
-
- private fun refreshFragment() {
- if (platformGamesFragment != null) {
- NativeLibrary.resetRomMetadata()
- platformGamesFragment!!.refresh()
- }
+ }.withEndAction {
+ if (!visible) {
+ binding.navigationBar.visibility = View.INVISIBLE
+ }
+ }.start()
}
override fun onDestroy() {
@@ -152,145 +104,12 @@ class MainActivity : AppCompatActivity(), MainView {
super.onDestroy()
}
- private fun setInsets() {
- ViewCompat.setOnApplyWindowInsetsListener(binding.gamesPlatformFrame) { view: View, windowInsets: WindowInsetsCompat ->
+ private fun setInsets() =
+ ViewCompat.setOnApplyWindowInsetsListener(binding.statusBarShade) { view: View, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
- view.updatePadding(left = insets.left, right = insets.right)
- InsetsHelper.insetAppBar(insets, binding.appbarMain)
+ val mlpShade = view.layoutParams as MarginLayoutParams
+ mlpShade.height = insets.top
+ binding.statusBarShade.layoutParams = mlpShade
windowInsets
}
- }
-
- private val getGamesDirectory =
- registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
- if (result == null)
- return@registerForActivityResult
-
- val takeFlags =
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
- contentResolver.takePersistableUriPermission(
- result,
- takeFlags
- )
-
- // When a new directory is picked, we currently will reset the existing games
- // database. This effectively means that only one game directory is supported.
- PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()
- .putString(GameHelper.KEY_GAME_PATH, result.toString())
- .apply()
- }
-
- private val getProdKey =
- registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
- if (result == null)
- return@registerForActivityResult
-
- val takeFlags =
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
- contentResolver.takePersistableUriPermission(
- result,
- takeFlags
- )
-
- val dstPath = DirectoryInitialization.userDirectory + "/keys/"
- if (FileUtil.copyUriToInternalStorage(this, result, dstPath, "prod.keys")) {
- if (NativeLibrary.reloadKeys()) {
- Toast.makeText(
- this,
- R.string.install_keys_success,
- Toast.LENGTH_SHORT
- ).show()
- refreshFragment()
- } else {
- Toast.makeText(
- this,
- R.string.install_keys_failure,
- Toast.LENGTH_LONG
- ).show()
- }
- }
- }
-
- private val getAmiiboKey =
- registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
- if (result == null)
- return@registerForActivityResult
-
- val takeFlags =
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
- contentResolver.takePersistableUriPermission(
- result,
- takeFlags
- )
-
- val dstPath = DirectoryInitialization.userDirectory + "/keys/"
- if (FileUtil.copyUriToInternalStorage(this, result, dstPath, "key_retail.bin")) {
- if (NativeLibrary.reloadKeys()) {
- Toast.makeText(
- this,
- R.string.install_keys_success,
- Toast.LENGTH_SHORT
- ).show()
- refreshFragment()
- } else {
- Toast.makeText(
- this,
- R.string.install_amiibo_keys_failure,
- Toast.LENGTH_LONG
- ).show()
- }
- }
- }
-
- private val getDriver =
- registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
- if (result == null)
- return@registerForActivityResult
-
- val takeFlags =
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
- contentResolver.takePersistableUriPermission(
- result,
- takeFlags
- )
-
- val progressBinding = DialogProgressBarBinding.inflate(layoutInflater)
- progressBinding.progressBar.isIndeterminate = true
- val installationDialog = MaterialAlertDialogBuilder(this)
- .setTitle(R.string.installing_driver)
- .setView(progressBinding.root)
- .show()
-
- lifecycleScope.launch {
- withContext(Dispatchers.IO) {
- // Ignore file exceptions when a user selects an invalid zip
- try {
- GpuDriverHelper.installCustomDriver(applicationContext, result)
- } catch (_: IOException) {
- }
-
- withContext(Dispatchers.Main) {
- installationDialog.dismiss()
-
- val driverName = GpuDriverHelper.customDriverName
- if (driverName != null) {
- Toast.makeText(
- applicationContext,
- getString(
- R.string.select_gpu_driver_install_success,
- driverName
- ),
- Toast.LENGTH_SHORT
- ).show()
- } else {
- Toast.makeText(
- applicationContext,
- R.string.select_gpu_driver_error,
- Toast.LENGTH_LONG
- ).show()
- }
- }
- }
- }
- }
}