android: Use modal navigation drawer as in game menu
This commit is contained in:
parent
1f3b41366c
commit
273e81bb94
|
@ -8,15 +8,10 @@ import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.activity.OnBackPressedCallback
|
|
||||||
import androidx.annotation.IntDef
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.fragment.app.FragmentManager
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.slider.Slider.OnChangeListener
|
import com.google.android.material.slider.Slider.OnChangeListener
|
||||||
|
@ -25,8 +20,9 @@ import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
|
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
||||||
import org.yuzu.yuzu_emu.fragments.MenuFragment
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
|
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
|
||||||
|
import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable
|
||||||
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
@ -37,11 +33,11 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
//private Intent foregroundService;
|
//private Intent foregroundService;
|
||||||
|
|
||||||
var isActivityRecreated = false
|
var isActivityRecreated = false
|
||||||
private var selectedTitle: String? = null
|
|
||||||
private var path: String? = null
|
|
||||||
private var menuVisible = false
|
private var menuVisible = false
|
||||||
private var emulationFragment: EmulationFragment? = null
|
private var emulationFragment: EmulationFragment? = null
|
||||||
|
|
||||||
|
private lateinit var game: Game
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
// TODO(bunnei): Disable notifications until we support app suspension.
|
// TODO(bunnei): Disable notifications until we support app suspension.
|
||||||
//stopService(foregroundService);
|
//stopService(foregroundService);
|
||||||
|
@ -54,9 +50,7 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
// Get params we were passed
|
// Get params we were passed
|
||||||
val gameToEmulate = intent
|
game = intent.parcelable(EXTRA_SELECTED_GAME)!!
|
||||||
path = gameToEmulate.getStringExtra(EXTRA_SELECTED_GAME)
|
|
||||||
selectedTitle = gameToEmulate.getStringExtra(EXTRA_SELECTED_TITLE)
|
|
||||||
isActivityRecreated = false
|
isActivityRecreated = false
|
||||||
} else {
|
} else {
|
||||||
isActivityRecreated = true
|
isActivityRecreated = true
|
||||||
|
@ -73,34 +67,26 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
emulationFragment =
|
emulationFragment =
|
||||||
supportFragmentManager.findFragmentById(R.id.frame_emulation_fragment) as EmulationFragment?
|
supportFragmentManager.findFragmentById(R.id.frame_emulation_fragment) as EmulationFragment?
|
||||||
if (emulationFragment == null) {
|
if (emulationFragment == null) {
|
||||||
emulationFragment = EmulationFragment.newInstance(path)
|
emulationFragment = EmulationFragment.newInstance(game)
|
||||||
supportFragmentManager.beginTransaction()
|
supportFragmentManager.beginTransaction()
|
||||||
.add(R.id.frame_emulation_fragment, emulationFragment!!)
|
.add(R.id.frame_emulation_fragment, emulationFragment!!)
|
||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
title = selectedTitle
|
title = game.title
|
||||||
|
|
||||||
// Start a foreground service to prevent the app from getting killed in the background
|
// Start a foreground service to prevent the app from getting killed in the background
|
||||||
// TODO(bunnei): Disable notifications until we support app suspension.
|
// TODO(bunnei): Disable notifications until we support app suspension.
|
||||||
//foregroundService = new Intent(EmulationActivity.this, ForegroundService.class);
|
//foregroundService = new Intent(EmulationActivity.this, ForegroundService.class);
|
||||||
//startForegroundService(foregroundService);
|
//startForegroundService(foregroundService);
|
||||||
|
|
||||||
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
|
||||||
override fun handleOnBackPressed() {
|
|
||||||
toggleMenu()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
outState.putString(EXTRA_SELECTED_GAME, path)
|
outState.putParcelable(EXTRA_SELECTED_GAME, game)
|
||||||
outState.putString(EXTRA_SELECTED_TITLE, selectedTitle)
|
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreState(savedInstanceState: Bundle) {
|
private fun restoreState(savedInstanceState: Bundle) {
|
||||||
path = savedInstanceState.getString(EXTRA_SELECTED_GAME)
|
game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!!
|
||||||
selectedTitle = savedInstanceState.getString(EXTRA_SELECTED_TITLE)
|
|
||||||
|
|
||||||
// If an alert prompt was in progress when state was restored, retry displaying it
|
// If an alert prompt was in progress when state was restored, retry displaying it
|
||||||
NativeLibrary.retryDisplayAlertPrompt()
|
NativeLibrary.retryDisplayAlertPrompt()
|
||||||
|
@ -110,6 +96,8 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
window.attributes.layoutInDisplayCutoutMode =
|
window.attributes.layoutInDisplayCutoutMode =
|
||||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||||
|
|
||||||
|
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)
|
||||||
|
|
||||||
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
|
// It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar.
|
||||||
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||||
|
@ -119,15 +107,6 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
View.SYSTEM_UI_FLAG_IMMERSIVE
|
View.SYSTEM_UI_FLAG_IMMERSIVE
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleMenuAction(action: Int) {
|
|
||||||
when (action) {
|
|
||||||
MENU_ACTION_EXIT -> {
|
|
||||||
emulationFragment!!.stopEmulation()
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun editControlsPlacement() {
|
private fun editControlsPlacement() {
|
||||||
if (emulationFragment!!.isConfiguringControls) {
|
if (emulationFragment!!.isConfiguringControls) {
|
||||||
emulationFragment!!.stopConfiguringControls()
|
emulationFragment!!.stopConfiguringControls()
|
||||||
|
@ -176,94 +155,14 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
|
||||||
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
||||||
var anyMenuClosed = false
|
|
||||||
var submenu = supportFragmentManager.findFragmentById(R.id.frame_submenu)
|
|
||||||
if (submenu != null && areCoordinatesOutside(submenu.view, event.x, event.y)) {
|
|
||||||
closeSubmenu()
|
|
||||||
submenu = null
|
|
||||||
anyMenuClosed = true
|
|
||||||
}
|
|
||||||
if (submenu == null) {
|
|
||||||
val menu = supportFragmentManager.findFragmentById(R.id.frame_menu)
|
|
||||||
if (menu != null && areCoordinatesOutside(menu.view, event.x, event.y)) {
|
|
||||||
closeMenu()
|
|
||||||
anyMenuClosed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (anyMenuClosed) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.dispatchTouchEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
|
||||||
@IntDef(
|
|
||||||
MENU_ACTION_EDIT_CONTROLS_PLACEMENT,
|
|
||||||
MENU_ACTION_TOGGLE_CONTROLS,
|
|
||||||
MENU_ACTION_ADJUST_SCALE,
|
|
||||||
MENU_ACTION_EXIT,
|
|
||||||
MENU_ACTION_SHOW_FPS,
|
|
||||||
MENU_ACTION_RESET_OVERLAY,
|
|
||||||
MENU_ACTION_SHOW_OVERLAY,
|
|
||||||
MENU_ACTION_OPEN_SETTINGS
|
|
||||||
)
|
|
||||||
annotation class MenuAction
|
|
||||||
|
|
||||||
private fun closeSubmenu(): Boolean {
|
|
||||||
return supportFragmentManager.popBackStackImmediate(
|
|
||||||
BACKSTACK_NAME_SUBMENU,
|
|
||||||
FragmentManager.POP_BACK_STACK_INCLUSIVE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun closeMenu(): Boolean {
|
|
||||||
menuVisible = false
|
|
||||||
return supportFragmentManager.popBackStackImmediate(
|
|
||||||
BACKSTACK_NAME_MENU,
|
|
||||||
FragmentManager.POP_BACK_STACK_INCLUSIVE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleMenu() {
|
|
||||||
if (!closeMenu()) {
|
|
||||||
val fragment: Fragment = MenuFragment.newInstance()
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.setCustomAnimations(
|
|
||||||
R.animator.menu_slide_in_from_start,
|
|
||||||
R.animator.menu_slide_out_to_start,
|
|
||||||
R.animator.menu_slide_in_from_start,
|
|
||||||
R.animator.menu_slide_out_to_start
|
|
||||||
)
|
|
||||||
.add(R.id.frame_menu, fragment)
|
|
||||||
.addToBackStack(BACKSTACK_NAME_MENU)
|
|
||||||
.commit()
|
|
||||||
menuVisible = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val BACKSTACK_NAME_MENU = "menu"
|
|
||||||
private const val BACKSTACK_NAME_SUBMENU = "submenu"
|
|
||||||
const val EXTRA_SELECTED_GAME = "SelectedGame"
|
const val EXTRA_SELECTED_GAME = "SelectedGame"
|
||||||
const val EXTRA_SELECTED_TITLE = "SelectedTitle"
|
|
||||||
const val MENU_ACTION_EDIT_CONTROLS_PLACEMENT = 0
|
|
||||||
const val MENU_ACTION_TOGGLE_CONTROLS = 1
|
|
||||||
const val MENU_ACTION_ADJUST_SCALE = 2
|
|
||||||
const val MENU_ACTION_EXIT = 3
|
|
||||||
const val MENU_ACTION_SHOW_FPS = 4
|
|
||||||
const val MENU_ACTION_RESET_OVERLAY = 6
|
|
||||||
const val MENU_ACTION_SHOW_OVERLAY = 7
|
|
||||||
const val MENU_ACTION_OPEN_SETTINGS = 8
|
|
||||||
private const val EMULATION_RUNNING_NOTIFICATION = 0x1000
|
private const val EMULATION_RUNNING_NOTIFICATION = 0x1000
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun launch(activity: FragmentActivity, path: String?, title: String?) {
|
fun launch(activity: FragmentActivity, game: Game) {
|
||||||
val launcher = Intent(activity, EmulationActivity::class.java)
|
val launcher = Intent(activity, EmulationActivity::class.java)
|
||||||
launcher.putExtra(EXTRA_SELECTED_GAME, path)
|
launcher.putExtra(EXTRA_SELECTED_GAME, game)
|
||||||
launcher.putExtra(EXTRA_SELECTED_TITLE, title)
|
|
||||||
activity.startActivity(launcher)
|
activity.startActivity(launcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
|
@ -23,8 +22,8 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity.Companion.launch
|
|
||||||
import org.yuzu.yuzu_emu.databinding.CardGameBinding
|
import org.yuzu.yuzu_emu.databinding.CardGameBinding
|
||||||
|
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.model.GameDatabase
|
import org.yuzu.yuzu_emu.model.GameDatabase
|
||||||
import org.yuzu.yuzu_emu.utils.Log
|
import org.yuzu.yuzu_emu.utils.Log
|
||||||
|
@ -181,7 +180,7 @@ class GameAdapter(private val activity: AppCompatActivity) : RecyclerView.Adapte
|
||||||
*/
|
*/
|
||||||
override fun onClick(view: View) {
|
override fun onClick(view: View) {
|
||||||
val holder = view.tag as GameViewHolder
|
val holder = view.tag as GameViewHolder
|
||||||
launch((view.context as FragmentActivity), holder.game.path, holder.game.title)
|
EmulationActivity.launch((view.context as AppCompatActivity), holder.game)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isValidGame(path: String): Boolean {
|
private fun isValidGame(path: String): Boolean {
|
||||||
|
|
|
@ -10,7 +10,14 @@ import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.view.*
|
import android.view.*
|
||||||
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import androidx.core.graphics.Insets
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
@ -20,10 +27,15 @@ import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
|
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
||||||
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver
|
import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver
|
||||||
|
import org.yuzu.yuzu_emu.utils.InsetsHelper
|
||||||
import org.yuzu.yuzu_emu.utils.Log
|
import org.yuzu.yuzu_emu.utils.Log
|
||||||
|
import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable
|
||||||
|
|
||||||
class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.FrameCallback {
|
class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.FrameCallback {
|
||||||
private lateinit var preferences: SharedPreferences
|
private lateinit var preferences: SharedPreferences
|
||||||
|
@ -35,6 +47,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||||
private var _binding: FragmentEmulationBinding? = null
|
private var _binding: FragmentEmulationBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
private lateinit var game: Game
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
if (context is EmulationActivity) {
|
if (context is EmulationActivity) {
|
||||||
|
@ -54,8 +68,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||||
retainInstance = true
|
retainInstance = true
|
||||||
preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||||
val gamePath = requireArguments().getString(KEY_GAMEPATH)
|
game = requireArguments().parcelable(EmulationActivity.EXTRA_SELECTED_GAME)!!
|
||||||
emulationState = EmulationState(gamePath)
|
emulationState = EmulationState(game.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,6 +92,57 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||||
// Setup overlay.
|
// Setup overlay.
|
||||||
resetInputOverlay()
|
resetInputOverlay()
|
||||||
updateShowFpsOverlay()
|
updateShowFpsOverlay()
|
||||||
|
|
||||||
|
binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =
|
||||||
|
game.title
|
||||||
|
binding.inGameMenu.setNavigationItemSelectedListener {
|
||||||
|
when (it.itemId) {
|
||||||
|
R.id.menu_pause_emulation -> {
|
||||||
|
if (emulationState.isPaused) {
|
||||||
|
emulationState.run(false)
|
||||||
|
it.title = resources.getString(R.string.emulation_pause)
|
||||||
|
it.icon = ResourcesCompat.getDrawable(
|
||||||
|
resources,
|
||||||
|
R.drawable.ic_pause,
|
||||||
|
requireContext().theme
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
emulationState.pause()
|
||||||
|
it.title = resources.getString(R.string.emulation_unpause)
|
||||||
|
it.icon = ResourcesCompat.getDrawable(
|
||||||
|
resources,
|
||||||
|
R.drawable.ic_play,
|
||||||
|
requireContext().theme
|
||||||
|
)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.menu_settings -> {
|
||||||
|
SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "")
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.menu_overlay_controls -> {
|
||||||
|
showOverlayOptions()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.menu_exit -> {
|
||||||
|
requireActivity().finish()
|
||||||
|
emulationState.stop()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInsets()
|
||||||
|
|
||||||
|
requireActivity().onBackPressedDispatcher.addCallback(
|
||||||
|
requireActivity(),
|
||||||
|
object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
if (binding.drawerLayout.isOpen) binding.drawerLayout.close() else binding.drawerLayout.open()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -202,8 +267,30 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||||
NativeLibrary.DoFrame()
|
NativeLibrary.DoFrame()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopEmulation() {
|
private fun showOverlayOptions() {
|
||||||
emulationState.stop()
|
val anchor = binding.inGameMenu.findViewById<View>(R.id.menu_overlay_controls)
|
||||||
|
val popup = PopupMenu(requireContext(), anchor)
|
||||||
|
|
||||||
|
popup.menuInflater.inflate(R.menu.menu_overlay_options, popup.menu)
|
||||||
|
|
||||||
|
popup.setOnMenuItemClickListener {
|
||||||
|
when (it.itemId) {
|
||||||
|
R.id.menu_edit_overlay -> {
|
||||||
|
binding.drawerLayout.close()
|
||||||
|
binding.surfaceInputOverlay.requestFocus()
|
||||||
|
startConfiguringControls()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.menu_reset_overlay -> {
|
||||||
|
binding.drawerLayout.close()
|
||||||
|
resetInputOverlay()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startConfiguringControls() {
|
fun startConfiguringControls() {
|
||||||
|
@ -219,6 +306,27 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||||
val isConfiguringControls: Boolean
|
val isConfiguringControls: Boolean
|
||||||
get() = binding.surfaceInputOverlay.isInEditMode
|
get() = binding.surfaceInputOverlay.isInEditMode
|
||||||
|
|
||||||
|
private fun setInsets() {
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(binding.inGameMenu) { v: View, windowInsets: WindowInsetsCompat ->
|
||||||
|
val cutInsets: Insets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
||||||
|
var left = 0
|
||||||
|
var right = 0
|
||||||
|
if (ViewCompat.getLayoutDirection(v) == ViewCompat.LAYOUT_DIRECTION_LTR) {
|
||||||
|
left = cutInsets.left
|
||||||
|
} else {
|
||||||
|
right = cutInsets.right
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't use padding if the navigation bar isn't in the way
|
||||||
|
if (InsetsHelper.getBottomPaddingRequired(requireActivity()) > 0) {
|
||||||
|
v.setPadding(left, cutInsets.top, right, 0)
|
||||||
|
} else {
|
||||||
|
v.setPadding(left, cutInsets.top, right, 0)
|
||||||
|
}
|
||||||
|
windowInsets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class EmulationState(private val mGamePath: String?) {
|
private class EmulationState(private val mGamePath: String?) {
|
||||||
private var state: State
|
private var state: State
|
||||||
private var surface: Surface? = null
|
private var surface: Surface? = null
|
||||||
|
@ -340,12 +448,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY_GAMEPATH = "gamepath"
|
|
||||||
private val perfStatsUpdateHandler = Handler()
|
private val perfStatsUpdateHandler = Handler()
|
||||||
|
|
||||||
fun newInstance(gamePath: String?): EmulationFragment {
|
fun newInstance(game: Game): EmulationFragment {
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
args.putString(KEY_GAMEPATH, gamePath)
|
args.putParcelable(EmulationActivity.EXTRA_SELECTED_GAME, game)
|
||||||
val fragment = EmulationFragment()
|
val fragment = EmulationFragment()
|
||||||
fragment.arguments = args
|
fragment.arguments = args
|
||||||
return fragment
|
return fragment
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
package org.yuzu.yuzu_emu.fragments;
|
|
||||||
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.SparseIntArray;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.graphics.Insets;
|
|
||||||
import androidx.core.view.ViewCompat;
|
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
public final class MenuFragment extends Fragment implements View.OnClickListener
|
|
||||||
{
|
|
||||||
private static final String KEY_TITLE = "title";
|
|
||||||
private static final String KEY_WII = "wii";
|
|
||||||
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
|
|
||||||
|
|
||||||
private int mCutInset = 0;
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MenuFragment newInstance()
|
|
||||||
{
|
|
||||||
MenuFragment fragment = new MenuFragment();
|
|
||||||
|
|
||||||
Bundle arguments = new Bundle();
|
|
||||||
fragment.setArguments(arguments);
|
|
||||||
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is primarily intended to account for any navigation bar at the bottom of the screen
|
|
||||||
private int getBottomPaddingRequired()
|
|
||||||
{
|
|
||||||
Rect visibleFrame = new Rect();
|
|
||||||
requireActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleFrame);
|
|
||||||
return visibleFrame.bottom - visibleFrame.top - getResources().getDisplayMetrics().heightPixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false);
|
|
||||||
|
|
||||||
LinearLayout options = rootView.findViewById(R.id.layout_options);
|
|
||||||
|
|
||||||
// mPauseEmulation = options.findViewById(R.id.menu_pause_emulation);
|
|
||||||
// mUnpauseEmulation = options.findViewById(R.id.menu_unpause_emulation);
|
|
||||||
//
|
|
||||||
// updatePauseUnpauseVisibility();
|
|
||||||
//
|
|
||||||
// if (!requireActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN))
|
|
||||||
// {
|
|
||||||
// options.findViewById(R.id.menu_overlay_controls).setVisibility(View.GONE);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (!getArguments().getBoolean(KEY_WII, true))
|
|
||||||
// {
|
|
||||||
// options.findViewById(R.id.menu_refresh_wiimotes).setVisibility(View.GONE);
|
|
||||||
// }
|
|
||||||
|
|
||||||
int bottomPaddingRequired = getBottomPaddingRequired();
|
|
||||||
|
|
||||||
// Provide a safe zone between the navigation bar and Exit Emulation to avoid accidental touches
|
|
||||||
float density = getResources().getDisplayMetrics().density;
|
|
||||||
if (bottomPaddingRequired >= 32 * density)
|
|
||||||
{
|
|
||||||
bottomPaddingRequired += 32 * density;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bottomPaddingRequired > rootView.getPaddingBottom())
|
|
||||||
{
|
|
||||||
rootView.setPadding(rootView.getPaddingLeft(), rootView.getPaddingTop(),
|
|
||||||
rootView.getPaddingRight(), bottomPaddingRequired);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++)
|
|
||||||
{
|
|
||||||
Button button = (Button) options.getChildAt(childIndex);
|
|
||||||
|
|
||||||
button.setOnClickListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
rootView.findViewById(R.id.menu_exit).setOnClickListener(this);
|
|
||||||
|
|
||||||
// mTitleText = rootView.findViewById(R.id.text_game_title);
|
|
||||||
// String title = getArguments().getString(KEY_TITLE, null);
|
|
||||||
// if (title != null)
|
|
||||||
// {
|
|
||||||
// mTitleText.setText(title);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR)
|
|
||||||
{
|
|
||||||
// rootView.post(() -> NativeLibrary.SetObscuredPixelsLeft(rootView.getWidth()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return rootView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View button)
|
|
||||||
{
|
|
||||||
int action = buttonsActionsMap.get(button.getId());
|
|
||||||
EmulationActivity activity = (EmulationActivity) requireActivity();
|
|
||||||
activity.handleMenuAction(action);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,9 @@
|
||||||
package org.yuzu.yuzu_emu.utils
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Rect
|
||||||
import android.view.ViewGroup.MarginLayoutParams
|
import android.view.ViewGroup.MarginLayoutParams
|
||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
@ -27,4 +29,10 @@ object InsetsHelper {
|
||||||
resources.getInteger(resourceId)
|
resources.getInteger(resourceId)
|
||||||
} else 0
|
} else 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getBottomPaddingRequired(activity: Activity): Int {
|
||||||
|
val visibleFrame = Rect()
|
||||||
|
activity.window.decorView.getWindowVisibleDisplayFrame(visibleFrame)
|
||||||
|
return visibleFrame.bottom - visibleFrame.top - activity.resources.displayMetrics.heightPixels
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Parcelable
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
object SerializableHelper {
|
||||||
|
inline fun <reified T : Serializable> Bundle.serializable(key: String): T? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
||||||
|
getSerializable(key, T::class.java)
|
||||||
|
else
|
||||||
|
getSerializable(key) as? T
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Serializable> Intent.serializable(key: String): T? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
||||||
|
getSerializableExtra(key, T::class.java)
|
||||||
|
else
|
||||||
|
getSerializableExtra(key) as? T
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Parcelable> Bundle.parcelable(key: String): T? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
||||||
|
getParcelable(key, T::class.java)
|
||||||
|
else
|
||||||
|
getParcelable(key) as? T
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
||||||
|
getParcelableExtra(key, T::class.java)
|
||||||
|
else
|
||||||
|
getParcelableExtra(key) as? T
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M21,6L3,6c-1.1,0 -2,0.9 -2,2v8c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,8c0,-1.1 -0.9,-2 -2,-2zM11,13L8,13v3L6,16v-3L3,13v-2h3L6,8h2v3h3v2zM15.5,15c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM19.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S18.67,9 19.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:autoMirrored="true"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="?attr/colorControlNormal"
|
||||||
|
android:pathData="M8,5v14l11,-7z" />
|
||||||
|
</vector>
|
|
@ -1,32 +1,13 @@
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_height="match_parent"
|
android:id="@+id/frame_content"
|
||||||
android:keepScreenOn="true"
|
android:layout_width="match_parent"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
android:layout_height="match_parent"
|
||||||
android:id="@+id/frame_content">
|
android:keepScreenOn="true">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/frame_emulation_fragment"
|
android:id="@+id/frame_emulation_fragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:baselineAligned="false">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/frame_menu"
|
|
||||||
android:layout_width="@dimen/menu_width"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:layout="@layout/fragment_ingame_menu"/>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/frame_submenu"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
@ -1,47 +1,63 @@
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/drawer_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:keepScreenOn="true"
|
android:keepScreenOn="true"
|
||||||
tools:context="org.yuzu.yuzu_emu.fragments.EmulationFragment">
|
tools:context="org.yuzu.yuzu_emu.fragments.EmulationFragment"
|
||||||
|
tools:openDrawer="start">
|
||||||
|
|
||||||
<!-- This is what everything is rendered to during emulation -->
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
<Button
|
|
||||||
android:id="@+id/done_control_config"
|
|
||||||
style="@style/Widget.Material3.Button.Icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:padding="@dimen/spacing_small"
|
|
||||||
android:text="@string/emulation_done"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<!-- This is the onscreen input overlay -->
|
|
||||||
<SurfaceView
|
|
||||||
android:id="@+id/surface_emulation"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:focusable="false"
|
|
||||||
android:focusableInTouchMode="false" />
|
|
||||||
|
|
||||||
<org.yuzu.yuzu_emu.overlay.InputOverlay
|
<!-- This is the onscreen input overlay -->
|
||||||
android:id="@+id/surface_input_overlay"
|
<SurfaceView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/surface_emulation"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:focusable="true"
|
android:layout_height="match_parent"
|
||||||
android:focusableInTouchMode="true" />
|
android:focusable="false"
|
||||||
|
android:focusableInTouchMode="false" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/show_fps_text"
|
android:id="@+id/show_fps_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="18dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:clickable="false"
|
||||||
|
android:linksClickable="false"
|
||||||
|
android:longClickable="false"
|
||||||
|
android:shadowColor="@android:color/black"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<org.yuzu.yuzu_emu.overlay.InputOverlay
|
||||||
|
android:id="@+id/surface_input_overlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true" />
|
||||||
|
|
||||||
|
<!-- This is what everything is rendered to during emulation -->
|
||||||
|
<Button
|
||||||
|
style="@style/Widget.Material3.Button.ElevatedButton"
|
||||||
|
android:id="@+id/done_control_config"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/emulation_done"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.navigation.NavigationView
|
||||||
|
android:id="@+id/in_game_menu"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginStart="18dp"
|
android:layout_gravity="start"
|
||||||
android:layout_marginTop="2dp"
|
app:headerLayout="@layout/header_in_game"
|
||||||
android:clickable="false"
|
app:menu="@menu/menu_in_game" />
|
||||||
android:linksClickable="false"
|
|
||||||
android:longClickable="false"
|
|
||||||
android:shadowColor="@android:color/black"
|
|
||||||
android:textColor="@android:color/white"
|
|
||||||
android:textSize="12sp" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
</androidx.drawerlayout.widget.DrawerLayout>
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/colorSurface"
|
|
||||||
android:elevation="3dp"
|
|
||||||
tools:layout_width="250dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_game_title"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="32dp"
|
|
||||||
android:layout_marginVertical="24dp"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:letterSpacing="0"
|
|
||||||
android:maxLines="@integer/game_title_lines"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:textColor="?attr/colorOnSurface"
|
|
||||||
tools:text="The Legend of Zelda: Breath of the Wild" />
|
|
||||||
|
|
||||||
<com.google.android.material.divider.MaterialDivider
|
|
||||||
android:id="@+id/divider"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:scrollbarSize="4dp"
|
|
||||||
android:fadeScrollbars="false">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_options"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical" />
|
|
||||||
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
<com.google.android.material.divider.MaterialDivider
|
|
||||||
android:id="@+id/divider_2"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/menu_exit"
|
|
||||||
style="@style/InGameMenuOption"
|
|
||||||
android:layout_marginTop="@dimen/spacing_large"
|
|
||||||
android:text="@string/emulation_exit" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/text_game_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="24dp"
|
||||||
|
android:textAppearance="?attr/textAppearanceHeadlineMedium"
|
||||||
|
android:textColor="?attr/colorOnSurface"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Super Mario Odyssey" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item android:title="">
|
||||||
|
|
||||||
|
<menu>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_pause_emulation"
|
||||||
|
android:icon="@drawable/ic_pause"
|
||||||
|
android:title="@string/emulation_pause" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_settings"
|
||||||
|
android:icon="@drawable/ic_settings"
|
||||||
|
android:title="@string/preferences_settings" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_overlay_controls"
|
||||||
|
android:icon="@drawable/ic_controller"
|
||||||
|
android:title="@string/emulation_input_overlay" />
|
||||||
|
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_exit"
|
||||||
|
android:icon="@drawable/ic_exit"
|
||||||
|
android:title="@string/emulation_exit" />
|
||||||
|
|
||||||
|
</menu>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_edit_overlay"
|
||||||
|
android:title="@string/emulation_touch_overlay_edit" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_reset_overlay"
|
||||||
|
android:title="@string/emulation_touch_overlay_reset" />
|
||||||
|
|
||||||
|
</menu>
|
|
@ -87,6 +87,10 @@
|
||||||
<string name="emulation_toggle_controls">Toggle Controls</string>
|
<string name="emulation_toggle_controls">Toggle Controls</string>
|
||||||
<string name="emulation_control_scale">Adjust Scale</string>
|
<string name="emulation_control_scale">Adjust Scale</string>
|
||||||
<string name="emulation_touch_overlay_reset">Reset Overlay</string>
|
<string name="emulation_touch_overlay_reset">Reset Overlay</string>
|
||||||
|
<string name="emulation_touch_overlay_edit">Edit Overlay</string>
|
||||||
|
<string name="emulation_pause">Pause Emulation</string>
|
||||||
|
<string name="emulation_unpause">Unpause Emulation</string>
|
||||||
|
<string name="emulation_input_overlay">Input Overlay</string>
|
||||||
|
|
||||||
<string name="load_settings">Loading Settings…</string>
|
<string name="load_settings">Loading Settings…</string>
|
||||||
|
|
||||||
|
|
Reference in New Issue