[android] Add quick settings menu to emulation fragment (#3342)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3342 Reviewed-by: DraVee <dravee@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Co-authored-by: Nekle <224100951+ne-kle@users.noreply.github.com> Co-committed-by: Nekle <224100951+ne-kle@users.noreply.github.com>
This commit is contained in:
parent
f74c590a8e
commit
29fad5a89e
|
|
@ -0,0 +1,208 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.dialogs
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RadioGroup
|
||||
import android.widget.TextView
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.YuzuApplication
|
||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||
|
||||
class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||
// Kinda a crappy workaround to get a title from setting keys
|
||||
// Idk how to do this witthout hardcoding every single one
|
||||
private fun getSettingTitle(settingKey: String): String {
|
||||
return settingKey.replace("_", " ").split(" ")
|
||||
.joinToString(" ") { it.replaceFirstChar { c -> c.uppercase() } }
|
||||
|
||||
}
|
||||
|
||||
private fun saveSettings() {
|
||||
if (emulationFragment.shouldUseCustom) {
|
||||
NativeConfig.savePerGameConfig()
|
||||
} else {
|
||||
NativeConfig.saveGlobalConfig()
|
||||
}
|
||||
}
|
||||
|
||||
fun addPerGameConfigStatusIndicator(container: ViewGroup) {
|
||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||
val statusView = inflater.inflate(R.layout.item_quick_settings_status, container, false)
|
||||
|
||||
val statusIcon = statusView.findViewById<android.widget.ImageView>(R.id.status_icon)
|
||||
val statusText = statusView.findViewById<TextView>(R.id.status_text)
|
||||
|
||||
statusIcon.setImageResource(R.drawable.ic_settings_outline)
|
||||
statusText.text = emulationFragment.getString(R.string.using_per_game_config)
|
||||
statusText.setTextColor(
|
||||
MaterialColors.getColor(
|
||||
statusText,
|
||||
com.google.android.material.R.attr.colorPrimary
|
||||
)
|
||||
)
|
||||
|
||||
container.addView(statusView)
|
||||
}
|
||||
|
||||
// settings
|
||||
|
||||
fun addIntSetting(
|
||||
container: ViewGroup,
|
||||
setting: IntSetting,
|
||||
namesArrayId: Int,
|
||||
valuesArrayId: Int
|
||||
) {
|
||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
||||
val headerView = itemView.findViewById<ViewGroup>(R.id.setting_header)
|
||||
val titleView = itemView.findViewById<TextView>(R.id.setting_title)
|
||||
val valueView = itemView.findViewById<TextView>(R.id.setting_value)
|
||||
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
|
||||
val radioGroup = itemView.findViewById<RadioGroup>(R.id.radio_group)
|
||||
|
||||
titleView.text = getSettingTitle(setting.key)
|
||||
|
||||
val names = emulationFragment.resources.getStringArray(namesArrayId)
|
||||
val values = emulationFragment.resources.getIntArray(valuesArrayId)
|
||||
val currentIndex = values.indexOf(setting.getInt())
|
||||
|
||||
valueView.text = if (currentIndex >= 0) names[currentIndex] else "Null"
|
||||
headerView.visibility = View.VISIBLE
|
||||
|
||||
var isExpanded = false
|
||||
names.forEachIndexed { index, name ->
|
||||
val radioButton = com.google.android.material.radiobutton.MaterialRadioButton(emulationFragment.requireContext())
|
||||
radioButton.text = name
|
||||
radioButton.id = View.generateViewId()
|
||||
radioButton.isChecked = index == currentIndex
|
||||
radioButton.setPadding(16, 8, 16, 8)
|
||||
|
||||
radioButton.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
setting.setInt(values[index])
|
||||
saveSettings()
|
||||
valueView.text = name
|
||||
}
|
||||
}
|
||||
radioGroup.addView(radioButton)
|
||||
}
|
||||
|
||||
headerView.setOnClickListener {
|
||||
isExpanded = !isExpanded
|
||||
if (isExpanded) {
|
||||
radioGroup.visibility = View.VISIBLE
|
||||
expandIcon.animate().rotation(180f).setDuration(200).start()
|
||||
} else {
|
||||
radioGroup.visibility = View.GONE
|
||||
expandIcon.animate().rotation(0f).setDuration(200).start()
|
||||
}
|
||||
}
|
||||
|
||||
container.addView(itemView)
|
||||
}
|
||||
|
||||
fun addBooleanSetting(
|
||||
container: ViewGroup,
|
||||
setting: BooleanSetting
|
||||
) {
|
||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
||||
|
||||
val switchContainer = itemView.findViewById<ViewGroup>(R.id.switch_container)
|
||||
val titleView = itemView.findViewById<TextView>(R.id.switch_title)
|
||||
val switchView = itemView.findViewById<com.google.android.material.materialswitch.MaterialSwitch>(R.id.setting_switch)
|
||||
|
||||
titleView.text = getSettingTitle(setting.key)
|
||||
switchContainer.visibility = View.VISIBLE
|
||||
switchView.isChecked = setting.getBoolean()
|
||||
|
||||
switchView.setOnCheckedChangeListener { _, isChecked ->
|
||||
setting.setBoolean(isChecked)
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
switchContainer.setOnClickListener {
|
||||
switchView.toggle()
|
||||
}
|
||||
container.addView(itemView)
|
||||
}
|
||||
|
||||
fun addSliderSetting(
|
||||
container: ViewGroup,
|
||||
setting: AbstractSetting,
|
||||
minValue: Int = 0,
|
||||
maxValue: Int = 100,
|
||||
units: String = ""
|
||||
) {
|
||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
||||
|
||||
val sliderContainer = itemView.findViewById<ViewGroup>(R.id.slider_container)
|
||||
val titleView = itemView.findViewById<TextView>(R.id.slider_title)
|
||||
val valueDisplay = itemView.findViewById<TextView>(R.id.slider_value_display)
|
||||
val slider = itemView.findViewById<com.google.android.material.slider.Slider>(R.id.setting_slider)
|
||||
|
||||
|
||||
titleView.text = getSettingTitle(setting.key)
|
||||
sliderContainer.visibility = View.VISIBLE
|
||||
|
||||
slider.valueFrom = minValue.toFloat()
|
||||
slider.valueTo = maxValue.toFloat()
|
||||
slider.stepSize = 1f
|
||||
val currentValue = when (setting) {
|
||||
is AbstractShortSetting -> setting.getShort(needsGlobal = false).toInt()
|
||||
is AbstractIntSetting -> setting.getInt(needsGlobal = false)
|
||||
else -> 0
|
||||
}
|
||||
slider.value = currentValue.toFloat().coerceIn(minValue.toFloat(), maxValue.toFloat())
|
||||
|
||||
val displayValue = "${slider.value.toInt()}$units"
|
||||
valueDisplay.text = displayValue
|
||||
|
||||
slider.addOnChangeListener { _, value, chanhed ->
|
||||
if (chanhed) {
|
||||
val intValue = value.toInt()
|
||||
when (setting) {
|
||||
is AbstractShortSetting -> setting.setShort(intValue.toShort())
|
||||
is AbstractIntSetting -> setting.setInt(intValue)
|
||||
}
|
||||
saveSettings()
|
||||
valueDisplay.text = "$intValue$units"
|
||||
}
|
||||
}
|
||||
|
||||
slider.setOnTouchListener { _, event ->
|
||||
val drawer = emulationFragment.view?.findViewById<DrawerLayout>(R.id.drawer_layout)
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
drawer?.requestDisallowInterceptTouchEvent(true)
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
drawer?.requestDisallowInterceptTouchEvent(false)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
container.addView(itemView)
|
||||
}
|
||||
|
||||
fun addDivider(container: ViewGroup) {
|
||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||
val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false)
|
||||
container.addView(dividerView)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
|
|
@ -68,12 +68,14 @@ import org.yuzu.yuzu_emu.R
|
|||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
|
||||
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
|
||||
import org.yuzu.yuzu_emu.dialogs.QuickSettings
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationOrientation
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings.EmulationVerticalAlignment
|
||||
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
||||
import org.yuzu.yuzu_emu.model.DriverViewModel
|
||||
import org.yuzu.yuzu_emu.model.EmulationViewModel
|
||||
|
|
@ -96,6 +98,7 @@ import java.io.ByteArrayOutputStream
|
|||
import java.io.File
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.or
|
||||
|
||||
class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
private lateinit var emulationState: EmulationState
|
||||
|
|
@ -136,6 +139,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
private var wasInputOverlayAutoHidden = false
|
||||
private var overlayTouchActive = false
|
||||
|
||||
var shouldUseCustom = false
|
||||
private var isQuickSettingsMenuOpen = false
|
||||
private val quickSettings = QuickSettings(this)
|
||||
|
||||
private val loadAmiiboLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
|
||||
isAmiiboPickerOpen = false
|
||||
|
|
@ -283,7 +290,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
|
||||
// Normal game launch from arguments
|
||||
else -> {
|
||||
val shouldUseCustom = game?.let { it == args.game && args.custom } ?: false
|
||||
shouldUseCustom = game?.let { it == args.game && args.custom } ?: false
|
||||
|
||||
if (shouldUseCustom) {
|
||||
SettingsFile.loadCustomConfig(game!!)
|
||||
|
|
@ -659,6 +666,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
binding.inGameMenu.requestFocus()
|
||||
emulationViewModel.setDrawerOpen(true)
|
||||
updateQuickOverlayMenuEntry(BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean())
|
||||
if (drawerView == binding.inGameMenu) {
|
||||
binding.drawerLayout.closeDrawer(binding.quickSettingsSheet)
|
||||
} else if (drawerView == binding.quickSettingsSheet) {
|
||||
binding.drawerLayout.closeDrawer(binding.inGameMenu)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
|
|
@ -726,16 +738,23 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
Settings.MenuTag.SECTION_ROOT
|
||||
)
|
||||
binding.inGameMenu.requestFocus()
|
||||
binding.drawerLayout.closeDrawer(binding.quickSettingsSheet)
|
||||
binding.root.findNavController().navigate(action)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_quick_settings -> {
|
||||
openQuickSettingsMenu()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_settings_per_game -> {
|
||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||
args.game,
|
||||
Settings.MenuTag.SECTION_ROOT
|
||||
)
|
||||
binding.inGameMenu.requestFocus()
|
||||
binding.drawerLayout.closeDrawer(binding.quickSettingsSheet)
|
||||
binding.root.findNavController().navigate(action)
|
||||
true
|
||||
}
|
||||
|
|
@ -801,6 +820,36 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
addQuickSettings()
|
||||
|
||||
binding.drawerLayout.addDrawerListener(object : DrawerListener {
|
||||
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
|
||||
// no op
|
||||
}
|
||||
|
||||
override fun onDrawerOpened(drawerView: View) {
|
||||
if (drawerView == binding.quickSettingsSheet) {
|
||||
isQuickSettingsMenuOpen = true
|
||||
if (shouldUseCustom) {
|
||||
SettingsFile.loadCustomConfig(args.game!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
if (drawerView == binding.quickSettingsSheet) {
|
||||
isQuickSettingsMenuOpen = false
|
||||
if (shouldUseCustom) {
|
||||
NativeConfig.unloadPerGameConfig()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDrawerStateChanged(newState: Int) {
|
||||
// No op
|
||||
}
|
||||
})
|
||||
|
||||
setInsets()
|
||||
|
||||
requireActivity().onBackPressedDispatcher.addCallback(
|
||||
|
|
@ -979,6 +1028,73 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
private fun addQuickSettings() {
|
||||
binding.quickSettingsSheet.apply {
|
||||
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
|
||||
|
||||
container.removeAllViews()
|
||||
|
||||
if (shouldUseCustom) {
|
||||
quickSettings.addPerGameConfigStatusIndicator(container)
|
||||
}
|
||||
|
||||
quickSettings.addBooleanSetting(
|
||||
container,
|
||||
BooleanSetting.RENDERER_USE_SPEED_LIMIT,
|
||||
)
|
||||
|
||||
quickSettings.addSliderSetting(
|
||||
container,
|
||||
ShortSetting.RENDERER_SPEED_LIMIT,
|
||||
minValue = 0,
|
||||
maxValue = 400,
|
||||
units = "%",
|
||||
)
|
||||
|
||||
quickSettings.addBooleanSetting(
|
||||
container,
|
||||
BooleanSetting.USE_DOCKED_MODE,
|
||||
)
|
||||
|
||||
quickSettings.addDivider(container)
|
||||
|
||||
quickSettings.addIntSetting(
|
||||
container,
|
||||
IntSetting.RENDERER_ACCURACY,
|
||||
R.array.rendererAccuracyNames,
|
||||
R.array.rendererAccuracyValues
|
||||
)
|
||||
|
||||
|
||||
quickSettings.addIntSetting(
|
||||
container,
|
||||
IntSetting.RENDERER_SCALING_FILTER,
|
||||
R.array.rendererScalingFilterNames,
|
||||
R.array.rendererScalingFilterValues
|
||||
)
|
||||
|
||||
quickSettings.addSliderSetting(
|
||||
container,
|
||||
IntSetting.FSR_SHARPENING_SLIDER,
|
||||
minValue = 0,
|
||||
maxValue = 100,
|
||||
units = "%"
|
||||
)
|
||||
|
||||
quickSettings.addIntSetting(
|
||||
container,
|
||||
IntSetting.RENDERER_ANTI_ALIASING,
|
||||
R.array.rendererAntiAliasingNames,
|
||||
R.array.rendererAntiAliasingValues
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun openQuickSettingsMenu() {
|
||||
binding.drawerLayout.closeDrawer(binding.inGameMenu)
|
||||
binding.drawerLayout.openDrawer(binding.quickSettingsSheet)
|
||||
}
|
||||
|
||||
private fun updateQuickOverlayMenuEntry(isVisible: Boolean) {
|
||||
val b = _binding ?: return
|
||||
val item = b.inGameMenu.menu.findItem(R.id.menu_quick_overlay) ?: return
|
||||
|
|
@ -1151,6 +1267,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
// we need to reinitialize the auto-hide timer
|
||||
initializeOverlayAutoHide()
|
||||
|
||||
addQuickSettings()
|
||||
}
|
||||
|
||||
private fun resetInputOverlay() {
|
||||
|
|
@ -1809,6 +1926,26 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
|
||||
windowInsets
|
||||
}
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(binding.quickSettingsSheet) { v, insets ->
|
||||
val systemBarsInsets: Insets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
if (v.layoutDirection == View.LAYOUT_DIRECTION_LTR) {
|
||||
v.setPadding(
|
||||
systemBarsInsets.left,
|
||||
systemBarsInsets.top,
|
||||
0,
|
||||
systemBarsInsets.bottom
|
||||
)
|
||||
} else {
|
||||
v.setPadding(
|
||||
0,
|
||||
systemBarsInsets.top,
|
||||
systemBarsInsets.right,
|
||||
systemBarsInsets.bottom
|
||||
)
|
||||
}
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
private class EmulationState(
|
||||
|
|
|
|||
|
|
@ -170,6 +170,19 @@
|
|||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/quick_settings_sheet"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:focusedByDefault="true"
|
||||
android:background="?attr/colorSurface"
|
||||
tools:visibility="gone">
|
||||
|
||||
<include layout="@layout/layout_quick_settings" />
|
||||
|
||||
</com.google.android.material.navigation.NavigationView>
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/in_game_menu"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<View xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/setting_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/setting_title"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/setting_value"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/expand_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/ic_dropdown_arrow"
|
||||
android:contentDescription=""
|
||||
app:tint="?attr/colorPrimary" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/radio_group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/slider_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/slider_title"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/slider_value_display"
|
||||
style="@style/TextAppearance.Material3.BodySmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/setting_slider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="100"
|
||||
android:stepSize="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/switch_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/switch_title"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/setting_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:strokeWidth="1dp"
|
||||
app:strokeColor="?attr/colorPrimary">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/status_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_settings_outline"
|
||||
android:contentDescription="" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/status_text"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="12dp"
|
||||
android:textColor="?attr/colorPrimary" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/quick_settings_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:elevation="0dp"
|
||||
app:title="@string/quick_settings"
|
||||
app:titleTextAppearance="@style/TextAppearance.Material3.TitleLarge"
|
||||
android:fitsSystemWindows="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/quick_settings_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="16dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
|
@ -18,6 +18,11 @@
|
|||
android:icon="@drawable/ic_settings"
|
||||
android:title="@string/preferences_settings" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_quick_settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:title="@string/quick_settings" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_settings_per_game"
|
||||
android:icon="@drawable/ic_settings_outline"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
<string name="value_too_high">Value must be at most %1$d</string>
|
||||
<string name="invalid_value">Invalid value</string>
|
||||
|
||||
<string name="using_per_game_config">Using Per-Game Config</string>
|
||||
|
||||
<!-- Input Overlay -->
|
||||
<string name="show_input_overlay">Show Input Overlay</string>
|
||||
|
|
@ -709,6 +710,7 @@
|
|||
<string name="preferences_system_description">Docked mode, region, language</string>
|
||||
<string name="preferences_graphics">Graphics</string>
|
||||
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
|
||||
<string name="quick_settings">Quick Settings</string>
|
||||
<string name="preferences_audio">Audio</string>
|
||||
<string name="preferences_audio_description">Output engine, volume</string>
|
||||
<string name="preferences_controls">Controls</string>
|
||||
|
|
|
|||
Loading…
Reference in New Issue