diff options
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.kt | 307 |
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() - } - } - } - } - } } |