From 5dea15632cb1cf055d4613715faac02ca451f6af Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Fri, 11 Mar 2022 20:38:11 +0530 Subject: [PATCH] Add Controller Setup Guide A setup guide for controllers that goes through every available button/stick sequentially and opens up a corresponding dialog to map them. --- .../controller/ControllerGeneralViewItem.kt | 2 + .../main/java/emu/skyline/input/Controller.kt | 1 + .../emu/skyline/input/ControllerActivity.kt | 48 +++++++++++-------- .../emu/skyline/input/dialog/ButtonDialog.kt | 28 ++++++++--- .../emu/skyline/input/dialog/StickDialog.kt | 19 +++++++- app/src/main/res/layout/button_dialog.xml | 3 +- app/src/main/res/values/strings.xml | 2 + 7 files changed, 74 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/emu/skyline/adapter/controller/ControllerGeneralViewItem.kt b/app/src/main/java/emu/skyline/adapter/controller/ControllerGeneralViewItem.kt index 2bfa1aff..6224f86a 100644 --- a/app/src/main/java/emu/skyline/adapter/controller/ControllerGeneralViewItem.kt +++ b/app/src/main/java/emu/skyline/adapter/controller/ControllerGeneralViewItem.kt @@ -35,6 +35,8 @@ class ControllerGeneralViewItem(private val controllerId : Int, val type : Gener } GeneralType.RumbleDevice -> controller.rumbleDeviceName ?: context.getString(R.string.none) + + GeneralType.SetupGuide -> context.getString(R.string.setup_guide_description) } super.bind(binding, position) diff --git a/app/src/main/java/emu/skyline/input/Controller.kt b/app/src/main/java/emu/skyline/input/Controller.kt index 789d62c1..bb5bbf48 100644 --- a/app/src/main/java/emu/skyline/input/Controller.kt +++ b/app/src/main/java/emu/skyline/input/Controller.kt @@ -31,6 +31,7 @@ enum class ControllerType(val stringRes : Int, val firstController : Boolean, va enum class GeneralType(val stringRes : Int, val compatibleControllers : Array? = null) { PartnerJoyCon(R.string.partner_joycon, arrayOf(ControllerType.JoyConLeft)), RumbleDevice(R.string.rumble_device), + SetupGuide(R.string.setup_guide), } /** diff --git a/app/src/main/java/emu/skyline/input/ControllerActivity.kt b/app/src/main/java/emu/skyline/input/ControllerActivity.kt index 295d397c..a2a449c3 100644 --- a/app/src/main/java/emu/skyline/input/ControllerActivity.kt +++ b/app/src/main/java/emu/skyline/input/ControllerActivity.kt @@ -9,14 +9,15 @@ import android.content.Intent import android.graphics.Canvas import android.os.Bundle import android.view.KeyEvent -import android.view.View import android.view.ViewTreeObserver import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.app.AppCompatDialogFragment import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.marginTop import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import emu.skyline.R @@ -55,6 +56,10 @@ class ControllerActivity : AppCompatActivity() { */ val axisMap = mutableMapOf() + val stickItems = mutableListOf() + + val buttonItems = mutableListOf() + @Inject lateinit var settings : Settings @@ -108,17 +113,14 @@ class ControllerActivity : AppCompatActivity() { } } - wroteTitle = false + if (controller.type.sticks.isNotEmpty()) + items.add(ControllerHeaderItem(getString(R.string.sticks))) for (stick in controller.type.sticks) { - if (!wroteTitle) { - items.add(ControllerHeaderItem(getString(R.string.sticks))) - wroteTitle = true - } - val stickItem = ControllerStickViewItem(id, stick, onControllerStickClick) items.add(stickItem) + stickItems.add(stickItem) buttonMap[stick.button] = stickItem axisMap[stick.xAxis] = stickItem axisMap[stick.yAxis] = stickItem @@ -132,32 +134,26 @@ class ControllerActivity : AppCompatActivity() { val buttonArrays = arrayOf(dpadButtons, faceButtons, shoulderTriggerButtons, shoulderRailButtons) for (buttonArray in buttonArrays) { - wroteTitle = false + val filteredButtons = controller.type.buttons.filter { it in buttonArray.second } - for (button in controller.type.buttons.filter { it in buttonArray.second }) { - if (!wroteTitle) { - items.add(ControllerHeaderItem(getString(buttonArray.first))) - wroteTitle = true - } + if (filteredButtons.isNotEmpty()) + items.add(ControllerHeaderItem(getString(buttonArray.first))) + for (button in filteredButtons) { val buttonItem = ControllerButtonViewItem(id, button, onControllerButtonClick) items.add(buttonItem) + buttonItems.add(buttonItem) buttonMap[button] = buttonItem } } - wroteTitle = false - + items.add(ControllerHeaderItem(getString(R.string.misc_buttons))) // The menu button will always exist for (button in controller.type.buttons.filterNot { item -> buttonArrays.any { item in it.second } }.plus(ButtonId.Menu)) { - if (!wroteTitle) { - items.add(ControllerHeaderItem(getString(R.string.misc_buttons))) - wroteTitle = true - } - val buttonItem = ControllerButtonViewItem(id, button, onControllerButtonClick) items.add(buttonItem) + buttonItems.add(buttonItem) buttonMap[button] = buttonItem } } finally { @@ -309,6 +305,18 @@ class ControllerActivity : AppCompatActivity() { GeneralType.RumbleDevice -> { RumbleDialog(item).show(supportFragmentManager, null) } + + GeneralType.SetupGuide -> { + var dialogFragment : BottomSheetDialogFragment? = null + + for (buttonItem in buttonItems.reversed()) + dialogFragment = ButtonDialog(buttonItem, dialogFragment) + + for (stickItem in stickItems.reversed()) + dialogFragment = StickDialog(stickItem, dialogFragment) + + dialogFragment?.show(supportFragmentManager, null) + } } Unit } diff --git a/app/src/main/java/emu/skyline/input/dialog/ButtonDialog.kt b/app/src/main/java/emu/skyline/input/dialog/ButtonDialog.kt index 346d3fc2..04c2e1c6 100644 --- a/app/src/main/java/emu/skyline/input/dialog/ButtonDialog.kt +++ b/app/src/main/java/emu/skyline/input/dialog/ButtonDialog.kt @@ -11,6 +11,8 @@ import android.os.Handler import android.os.Looper import android.view.* import android.view.animation.LinearInterpolator +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.fragment.app.commit import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment import emu.skyline.R @@ -25,7 +27,7 @@ import kotlin.math.abs * * @param item This is used to hold the [ControllerButtonViewItem] between instances */ -class ButtonDialog @JvmOverloads constructor(private val item : ControllerButtonViewItem? = null) : BottomSheetDialogFragment() { +class ButtonDialog @JvmOverloads constructor(private val item : ControllerButtonViewItem? = null, private val nextDialog : BottomSheetDialogFragment? = null) : BottomSheetDialogFragment() { private var _binding : ButtonDialogBinding? = null private val binding get() = _binding!! @@ -42,8 +44,22 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton override fun onStart() { super.onStart() - val behavior = BottomSheetBehavior.from(requireView().parent as View) - behavior.state = BottomSheetBehavior.STATE_EXPANDED + val parentView = requireView().parent as View + if (parentView.layoutParams is CoordinatorLayout.LayoutParams) { + val behavior = BottomSheetBehavior.from(parentView) + behavior.state = BottomSheetBehavior.STATE_EXPANDED + } + } + + private fun gotoNextOrDismiss() { + if (nextDialog != null) { + parentFragmentManager.commit { + remove(this@ButtonDialog) + add(nextDialog, null) + } + } else { + dismiss() + } } override fun onViewCreated(view : View, savedInstanceState : Bundle?) { @@ -69,7 +85,7 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton item.update() - dismiss() + gotoNextOrDismiss() } // Ensure that layout animations are proper @@ -131,7 +147,7 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton item.update() - dismiss() + gotoNextOrDismiss() } true @@ -209,7 +225,7 @@ class ButtonDialog @JvmOverloads constructor(private val item : ControllerButton item.update() - dismiss() + gotoNextOrDismiss() } axisHandler.postDelayed(axisRunnable!!, 1000) diff --git a/app/src/main/java/emu/skyline/input/dialog/StickDialog.kt b/app/src/main/java/emu/skyline/input/dialog/StickDialog.kt index 96aeb15c..0651cb2f 100644 --- a/app/src/main/java/emu/skyline/input/dialog/StickDialog.kt +++ b/app/src/main/java/emu/skyline/input/dialog/StickDialog.kt @@ -12,6 +12,8 @@ import android.os.Looper import android.util.TypedValue import android.view.* import android.view.animation.LinearInterpolator +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.fragment.app.commit import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment import emu.skyline.R @@ -29,7 +31,7 @@ import kotlin.math.max * * @param item This is used to hold the [ControllerStickViewItem] between instances */ -class StickDialog @JvmOverloads constructor(val item : ControllerStickViewItem? = null) : BottomSheetDialogFragment() { +class StickDialog @JvmOverloads constructor(val item : ControllerStickViewItem? = null, private val nextDialog : BottomSheetDialogFragment? = null) : BottomSheetDialogFragment() { /** * This enumerates all of the stages this dialog can be in */ @@ -82,6 +84,17 @@ class StickDialog @JvmOverloads constructor(val item : ControllerStickViewItem? behavior.state = BottomSheetBehavior.STATE_EXPANDED } + private fun gotoNextOrDismiss() { + if (nextDialog != null) { + parentFragmentManager.commit { + remove(this@StickDialog) + add(nextDialog, null) + } + } else { + dismiss() + } + } + /** * This function converts [dip] (Density Independent Pixels) to normal pixels */ @@ -218,6 +231,8 @@ class StickDialog @JvmOverloads constructor(val item : ControllerStickViewItem? binding.stickNext.text = getString(if (ordinal + 1 == size) R.string.done else R.string.next) updateAnimation() + } else if (ordinal == size) { + gotoNextOrDismiss() } else { dismiss() } @@ -254,7 +269,7 @@ class StickDialog @JvmOverloads constructor(val item : ControllerStickViewItem? item.update() - dismiss() + gotoNextOrDismiss() } // Ensure that layout animations are proper diff --git a/app/src/main/res/layout/button_dialog.xml b/app/src/main/res/layout/button_dialog.xml index f7a387b8..c78e9176 100644 --- a/app/src/main/res/layout/button_dialog.xml +++ b/app/src/main/res/layout/button_dialog.xml @@ -68,7 +68,8 @@ android:max="100" android:progress="25" android:secondaryProgressTintMode="screen" - android:visibility="gone" /> + android:visibility="gone" + tools:visibility="visible" />