Rework OSC action bar appearance

FABs are now placed on top of a sheet hanging from the top. Actions are now properly enumerated and don't rely on the icon resource ID anymore.
This commit is contained in:
lynxnb 2023-03-28 13:21:26 +02:00 committed by Billy Laws
parent fe4ccd1ee0
commit 49de8a8f38
7 changed files with 95 additions and 42 deletions

View File

@ -10,6 +10,7 @@ import android.os.Bundle
import android.os.Vibrator import android.os.Vibrator
import android.os.VibratorManager import android.os.VibratorManager
import android.view.* import android.view.*
import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isGone import androidx.core.view.isGone
@ -27,6 +28,23 @@ import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class OnScreenEditActivity : AppCompatActivity() { class OnScreenEditActivity : AppCompatActivity() {
private enum class Action(@DrawableRes private val icon : Int, @DrawableRes private val activeIcon : Int = 0) {
Restore(R.drawable.ic_restore),
Toggle(R.drawable.ic_toggle_on),
Move(R.drawable.ic_move),
Resize(R.drawable.ic_resize),
Grid(R.drawable.ic_grid_off, R.drawable.ic_grid_on),
Palette(R.drawable.ic_palette),
ZoomOut(R.drawable.ic_zoom_out),
ZoomIn(R.drawable.ic_zoom_in),
OpacityMinus(R.drawable.ic_opacity_minus),
OpacityPlus(R.drawable.ic_opacity_plus),
Close(R.drawable.ic_close),
;
fun getIcon(active : Boolean) = if (activeIcon != 0 && active) activeIcon else icon
}
private val binding by lazy { OnScreenEditActivityBinding.inflate(layoutInflater) } private val binding by lazy { OnScreenEditActivityBinding.inflate(layoutInflater) }
private var fullEditVisible = true private var fullEditVisible = true
@ -41,13 +59,13 @@ class OnScreenEditActivity : AppCompatActivity() {
} else { } else {
fullEditVisible = !fullEditVisible fullEditVisible = !fullEditVisible
toggleFabVisibility(fullEditVisible) toggleFabVisibility(fullEditVisible)
fabMapping[R.drawable.ic_close]!!.animate().rotation(if (fullEditVisible) 0f else 45f) fabMapping[Action.Close]!!.animate().rotation(if (fullEditVisible) 0f else 45f)
} }
} }
private fun toggleFabVisibility(visible : Boolean) { private fun toggleFabVisibility(visible : Boolean) {
fabMapping.forEach { (id, fab) -> fabMapping.forEach { (action, fab) ->
if (id != R.drawable.ic_close) { if (action != Action.Close) {
if (visible) fab.show() if (visible) fab.show()
else fab.hide() else fab.hide()
} }
@ -109,34 +127,42 @@ class OnScreenEditActivity : AppCompatActivity() {
} }
} }
private val enableGridAction = { private val toggleGridAction : () -> Unit = {
appSettings.onScreenControlSnapToGrid = true val snapToGrid = !appSettings.onScreenControlSnapToGrid
binding.onScreenControllerView.setSnapToGrid(true) appSettings.onScreenControlSnapToGrid = snapToGrid
binding.alignmentGrid.isGone = false
binding.onScreenControllerView.setSnapToGrid(snapToGrid)
binding.alignmentGrid.isGone = !snapToGrid
fabMapping[Action.Grid]!!.setImageResource(Action.Grid.getIcon(!snapToGrid))
} }
private val disableGridAction = { private val resetAction : () -> Unit = {
appSettings.onScreenControlSnapToGrid = false MaterialAlertDialogBuilder(this)
binding.onScreenControllerView.setSnapToGrid(false) .setTitle(R.string.osc_reset)
binding.alignmentGrid.isGone = true .setMessage(R.string.osc_reset_confirm)
.setPositiveButton(R.string.confirm) { _, _ -> binding.onScreenControllerView.resetControls() }
.setNegativeButton(R.string.cancel, null)
.setOnDismissListener { fullScreen() }
.show()
} }
private val actions : List<Pair<Int, () -> Unit>> = listOf( private data class ActionEntry(val action : Action, val callback : () -> Unit)
Pair(R.drawable.ic_palette, paletteAction),
Pair(R.drawable.ic_restore) { binding.onScreenControllerView.resetControls() }, private val actions : List<ActionEntry> = listOf(
Pair(R.drawable.ic_toggle, toggleAction), ActionEntry(Action.Restore, resetAction),
Pair(R.drawable.ic_move, moveAction), ActionEntry(Action.Toggle, toggleAction),
Pair(R.drawable.ic_resize, resizeAction), ActionEntry(Action.Move, moveAction),
Pair(R.drawable.ic_grid_on, enableGridAction), ActionEntry(Action.Resize, resizeAction),
Pair(R.drawable.ic_grid_off, disableGridAction), ActionEntry(Action.Grid, toggleGridAction),
Pair(R.drawable.ic_zoom_out) { binding.onScreenControllerView.decreaseScale() }, ActionEntry(Action.Palette, paletteAction),
Pair(R.drawable.ic_zoom_in) { binding.onScreenControllerView.increaseScale() }, ActionEntry(Action.ZoomOut) { binding.onScreenControllerView.decreaseScale() },
Pair(R.drawable.ic_opacity_minus) { binding.onScreenControllerView.decreaseOpacity() }, ActionEntry(Action.ZoomIn) { binding.onScreenControllerView.increaseScale() },
Pair(R.drawable.ic_opacity_plus) { binding.onScreenControllerView.increaseOpacity() }, ActionEntry(Action.OpacityMinus) { binding.onScreenControllerView.decreaseOpacity() },
Pair(R.drawable.ic_close, closeAction) ActionEntry(Action.OpacityPlus) { binding.onScreenControllerView.increaseOpacity() },
ActionEntry(Action.Close, closeAction),
) )
private val fabMapping = mutableMapOf<Int, FloatingActionButton>() private val fabMapping = mutableMapOf<Action, FloatingActionButton>()
override fun onCreate(savedInstanceState : Bundle?) { override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -168,13 +194,15 @@ class OnScreenEditActivity : AppCompatActivity() {
binding.alignmentGrid.isGone = !snapToGrid binding.alignmentGrid.isGone = !snapToGrid
binding.alignmentGrid.gridSize = OnScreenEditInfo.GridSize binding.alignmentGrid.gridSize = OnScreenEditInfo.GridSize
actions.forEach { pair -> actions.forEach { (action, callback) ->
binding.fabParent.addView(LayoutInflater.from(this).inflate(R.layout.on_screen_edit_mini_fab, binding.fabParent, false).apply { binding.fabParent.addView(LayoutInflater.from(this).inflate(R.layout.on_screen_edit_mini_fab, binding.fabParent, false).apply {
(this as FloatingActionButton).setImageDrawable(ContextCompat.getDrawable(context, pair.first)) (this as FloatingActionButton).setImageDrawable(ContextCompat.getDrawable(context, action.getIcon(false)))
setOnClickListener { pair.second.invoke() } setOnClickListener { callback.invoke() }
fabMapping[pair.first] = this fabMapping[action] = this
}) })
} }
fabMapping[Action.Grid]!!.setImageDrawable(ContextCompat.getDrawable(this, Action.Grid.getIcon(!snapToGrid)))
} }
override fun onResume() { override fun onResume() {

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M7,10A2,2 0 0,1 9,12A2,2 0 0,1 7,14A2,2 0 0,1 5,12A2,2 0 0,1 7,10M17,7A5,5 0 0,1 22,12A5,5 0 0,1 17,17H7A5,5 0 0,1 2,12A5,5 0 0,1 7,7H17M7,9A3,3 0 0,0 4,12A3,3 0 0,0 7,15H17A3,3 0 0,0 20,12A3,3 0 0,0 17,9H7Z" />
</vector>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M7,10A2,2 0 0,1 9,12A2,2 0 0,1 7,14A2,2 0 0,1 5,12A2,2 0 0,1 7,10M17,7A5,5 0 0,1 22,12A5,5 0 0,1 17,17H7A5,5 0 0,1 2,12A5,5 0 0,1 7,7H17M7,9A3,3 0 0,0 4,12A3,3 0 0,0 7,15H17A3,3 0 0,0 20,12A3,3 0 0,0 17,9H7Z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M17,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h10c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5zM17,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3z" />
</vector>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?attr/colorSurface" />
<corners
android:bottomLeftRadius="28dp"
android:bottomRightRadius="28dp" />
</shape>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@android:color/black"> android:background="@android:color/black">
@ -18,7 +19,12 @@
android:id="@+id/fab_parent" android:id="@+id/fab_parent"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="end" android:layout_gravity="top|center_horizontal"
android:layout_margin="16dp" android:background="@drawable/top_sheet_bg"
android:orientation="horizontal" /> android:backgroundTint="?attr/colorPrimaryContainer"
android:clipToPadding="false"
android:orientation="horizontal"
android:padding="10dp"
tools:layout_height="72dp"
tools:layout_width="512dp" />
</FrameLayout> </FrameLayout>

View File

@ -160,6 +160,8 @@
<string name="osc_edit">Edit On-Screen Controls layout</string> <string name="osc_edit">Edit On-Screen Controls layout</string>
<string name="osc_text_color">Text color</string> <string name="osc_text_color">Text color</string>
<string name="osc_background_color">Background color</string> <string name="osc_background_color">Background color</string>
<string name="osc_reset">Reset On-Screen Controls</string>
<string name="osc_reset_confirm">Are you sure you want to reset the On-Screen Controls?</string>
<string name="setup_guide">Setup Guide</string> <string name="setup_guide">Setup Guide</string>
<string name="setup_guide_description">Sequentially map every stick and button</string> <string name="setup_guide_description">Sequentially map every stick and button</string>
<string name="joystick">Joystick</string> <string name="joystick">Joystick</string>