android: Add warnings to setup screens

This commit is contained in:
Charles Lombardo 2023-04-28 18:06:01 -04:00 committed by bunnei
parent 71667e4d6d
commit 72247a2324
4 changed files with 149 additions and 13 deletions

View file

@ -14,7 +14,6 @@ import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.navigation.findNavController import androidx.navigation.findNavController
@ -38,9 +37,12 @@ class SetupFragment : Fragment() {
private lateinit var mainActivity: MainActivity private lateinit var mainActivity: MainActivity
private lateinit var hasBeenWarned: BooleanArray
companion object { companion object {
const val KEY_NEXT_VISIBILITY = "NextButtonVisibility" const val KEY_NEXT_VISIBILITY = "NextButtonVisibility"
const val KEY_BACK_VISIBILITY = "BackButtonVisibility" const val KEY_BACK_VISIBILITY = "BackButtonVisibility"
const val KEY_HAS_BEEN_WARNED = "HasBeenWarned"
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -84,36 +86,51 @@ class SetupFragment : Fragment() {
R.string.welcome_description, R.string.welcome_description,
0, 0,
true, true,
R.string.get_started R.string.get_started,
) { pageForward() }, { pageForward() },
false
),
SetupPage( SetupPage(
R.drawable.ic_key, R.drawable.ic_key,
R.string.keys, R.string.keys,
R.string.keys_description, R.string.keys_description,
R.drawable.ic_add, R.drawable.ic_add,
true, true,
R.string.select_keys R.string.select_keys,
) { mainActivity.getProdKey.launch(arrayOf("*/*")) }, { mainActivity.getProdKey.launch(arrayOf("*/*")) },
true,
R.string.install_prod_keys_warning,
R.string.install_prod_keys_warning_description,
R.string.install_prod_keys_warning_help
),
SetupPage( SetupPage(
R.drawable.ic_controller, R.drawable.ic_controller,
R.string.games, R.string.games,
R.string.games_description, R.string.games_description,
R.drawable.ic_add, R.drawable.ic_add,
true, true,
R.string.add_games R.string.add_games,
) { mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) }, { mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) },
true,
R.string.add_games_warning,
R.string.add_games_warning_description,
0
),
SetupPage( SetupPage(
R.drawable.ic_check, R.drawable.ic_check,
R.string.done, R.string.done,
R.string.done_description, R.string.done_description,
R.drawable.ic_arrow_forward, R.drawable.ic_arrow_forward,
false, false,
R.string.text_continue R.string.text_continue,
) { finishSetup() } { finishSetup() },
false
)
) )
binding.viewPager2.apply { binding.viewPager2.apply {
adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages) adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages)
offscreenPageLimit = 2 offscreenPageLimit = 2
isUserInputEnabled = false
} }
binding.viewPager2.registerOnPageChangeCallback(object : OnPageChangeCallback() { binding.viewPager2.registerOnPageChangeCallback(object : OnPageChangeCallback() {
@ -138,12 +155,26 @@ class SetupFragment : Fragment() {
} }
}) })
binding.buttonNext.setOnClickListener { pageForward() } binding.buttonNext.setOnClickListener {
val index = binding.viewPager2.currentItem
val currentPage = pages[index]
if (currentPage.hasWarning && !hasBeenWarned[index]) {
SetupWarningDialogFragment.newInstance(
currentPage.warningTitleId,
currentPage.warningDescriptionId,
currentPage.warningHelpLinkId,
index
).show(childFragmentManager, SetupWarningDialogFragment.TAG)
} else {
pageForward()
}
}
binding.buttonBack.setOnClickListener { pageBackward() } binding.buttonBack.setOnClickListener { pageBackward() }
if (savedInstanceState != null) { if (savedInstanceState != null) {
val nextIsVisible = savedInstanceState.getBoolean(KEY_NEXT_VISIBILITY) val nextIsVisible = savedInstanceState.getBoolean(KEY_NEXT_VISIBILITY)
val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY) val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY)
hasBeenWarned = savedInstanceState.getBooleanArray(KEY_HAS_BEEN_WARNED)!!
if (nextIsVisible) { if (nextIsVisible) {
binding.buttonNext.visibility = View.VISIBLE binding.buttonNext.visibility = View.VISIBLE
@ -151,6 +182,8 @@ class SetupFragment : Fragment() {
if (backIsVisible) { if (backIsVisible) {
binding.buttonBack.visibility = View.VISIBLE binding.buttonBack.visibility = View.VISIBLE
} }
} else {
hasBeenWarned = BooleanArray(pages.size)
} }
setInsets() setInsets()
@ -160,6 +193,7 @@ class SetupFragment : Fragment() {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putBoolean(KEY_NEXT_VISIBILITY, binding.buttonNext.isVisible) outState.putBoolean(KEY_NEXT_VISIBILITY, binding.buttonNext.isVisible)
outState.putBoolean(KEY_BACK_VISIBILITY, binding.buttonBack.isVisible) outState.putBoolean(KEY_BACK_VISIBILITY, binding.buttonBack.isVisible)
outState.putBooleanArray(KEY_HAS_BEEN_WARNED, hasBeenWarned)
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -201,14 +235,18 @@ class SetupFragment : Fragment() {
} }
} }
private fun pageForward() { fun pageForward() {
binding.viewPager2.currentItem = binding.viewPager2.currentItem + 1 binding.viewPager2.currentItem = binding.viewPager2.currentItem + 1
} }
private fun pageBackward() { fun pageBackward() {
binding.viewPager2.currentItem = binding.viewPager2.currentItem - 1 binding.viewPager2.currentItem = binding.viewPager2.currentItem - 1
} }
fun setPageWarned(page: Int) {
hasBeenWarned[page] = true
}
private fun setInsets() = private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat -> ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())

View file

@ -0,0 +1,86 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.R
class SetupWarningDialogFragment : DialogFragment() {
private var titleId: Int = 0
private var descriptionId: Int = 0
private var helpLinkId: Int = 0
private var page: Int = 0
private lateinit var setupFragment: SetupFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
titleId = requireArguments().getInt(TITLE)
descriptionId = requireArguments().getInt(DESCRIPTION)
helpLinkId = requireArguments().getInt(HELP_LINK)
page = requireArguments().getInt(PAGE)
setupFragment = requireParentFragment() as SetupFragment
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
.setPositiveButton(R.string.warning_skip) { _: DialogInterface?, _: Int ->
setupFragment.pageForward()
setupFragment.setPageWarned(page)
}
.setNegativeButton(R.string.warning_cancel, null)
if (titleId != 0) {
builder.setTitle(titleId)
} else {
builder.setTitle("")
}
if (descriptionId != 0) {
builder.setMessage(descriptionId)
}
if (helpLinkId != 0) {
builder.setNeutralButton(R.string.warning_help) { _: DialogInterface?, _: Int ->
val helpLink = resources.getString(R.string.install_prod_keys_warning_help)
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(helpLink))
startActivity(intent)
}
}
return builder.show()
}
companion object {
const val TAG = "SetupWarningDialogFragment"
private const val TITLE = "Title"
private const val DESCRIPTION = "Description"
private const val HELP_LINK = "HelpLink"
private const val PAGE = "Page"
fun newInstance(
titleId: Int,
descriptionId: Int,
helpLinkId: Int,
page: Int
): SetupWarningDialogFragment {
val dialog = SetupWarningDialogFragment()
val bundle = Bundle()
bundle.apply {
putInt(TITLE, titleId)
putInt(DESCRIPTION, descriptionId)
putInt(HELP_LINK, helpLinkId)
putInt(PAGE, page)
}
dialog.arguments = bundle
return dialog
}
}
}

View file

@ -10,5 +10,9 @@ data class SetupPage(
val buttonIconId: Int, val buttonIconId: Int,
val leftAlignedIcon: Boolean, val leftAlignedIcon: Boolean,
val buttonTextId: Int, val buttonTextId: Int,
val buttonAction: () -> Unit val buttonAction: () -> Unit,
val hasWarning: Boolean,
val warningTitleId: Int = 0,
val warningDescriptionId: Int = 0,
val warningHelpLinkId: Int = 0
) )

View file

@ -29,10 +29,18 @@
<string name="home_settings">Settings</string> <string name="home_settings">Settings</string>
<string name="add_games">Add Games</string> <string name="add_games">Add Games</string>
<string name="add_games_description">Select your games folder</string> <string name="add_games_description">Select your games folder</string>
<string name="add_games_warning">Skip selecting games folder?</string>
<string name="add_games_warning_description">Games won\'t be displayed in the Games list if a folder isn\'t selected.</string>
<string name="home_search_games">Search Games</string> <string name="home_search_games">Search Games</string>
<string name="games_dir_selected">Games directory selected</string> <string name="games_dir_selected">Games directory selected</string>
<string name="install_prod_keys">Install Prod.keys</string> <string name="install_prod_keys">Install Prod.keys</string>
<string name="install_prod_keys_description">Required to decrypt retail games</string> <string name="install_prod_keys_description">Required to decrypt retail games</string>
<string name="install_prod_keys_warning">Skip adding keys?</string>
<string name="install_prod_keys_warning_description">Valid keys are required to emulate retail games. Only homebrew apps will function if you continue.</string>
<string name="install_prod_keys_warning_help">https://yuzu-emu.org/help/quickstart/#guide-introduction</string>
<string name="warning_help">Help</string>
<string name="warning_skip">Skip</string>
<string name="warning_cancel">Cancel</string>
<string name="install_amiibo_keys">Install Amiibo Keys</string> <string name="install_amiibo_keys">Install Amiibo Keys</string>
<string name="install_amiibo_keys_description">Required to use Amiibo in game</string> <string name="install_amiibo_keys_description">Required to use Amiibo in game</string>
<string name="invalid_keys_file">Invalid keys file selected</string> <string name="invalid_keys_file">Invalid keys file selected</string>