summaryrefslogtreecommitdiffstats
path: root/src/android/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/app')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt19
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt109
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt109
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt35
-rw-r--r--src/android/app/src/main/res/layout-w600dp/page_setup.xml69
-rw-r--r--src/android/app/src/main/res/layout/page_setup.xml30
-rw-r--r--src/android/app/src/main/res/values/strings.xml1
8 files changed, 265 insertions, 121 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
index 481ddd5a5..0e3cec9ac 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
@@ -5,13 +5,17 @@ package org.yuzu.yuzu_emu.adapters
import android.text.Html
import android.view.LayoutInflater
+import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.button.MaterialButton
import org.yuzu.yuzu_emu.databinding.PageSetupBinding
+import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage
+import org.yuzu.yuzu_emu.model.StepState
+import org.yuzu.yuzu_emu.utils.ViewUtils
class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) :
RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() {
@@ -26,7 +30,7 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
holder.bind(pages[position])
inner class SetupPageViewHolder(val binding: PageSetupBinding) :
- RecyclerView.ViewHolder(binding.root) {
+ RecyclerView.ViewHolder(binding.root), SetupCallback {
lateinit var page: SetupPage
init {
@@ -35,6 +39,12 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
fun bind(page: SetupPage) {
this.page = page
+
+ if (page.stepCompleted.invoke() == StepState.COMPLETE) {
+ binding.buttonAction.visibility = View.INVISIBLE
+ binding.textConfirmation.visibility = View.VISIBLE
+ }
+
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
activity.resources,
@@ -62,9 +72,14 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
MaterialButton.ICON_GRAVITY_END
}
setOnClickListener {
- page.buttonAction.invoke()
+ page.buttonAction.invoke(this@SetupPageViewHolder)
}
}
}
+
+ override fun onStepCompleted() {
+ ViewUtils.hideView(binding.buttonAction, 200)
+ ViewUtils.showView(binding.textConfirmation, 200)
+ }
}
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
index 6c4ddaf6b..8ca768dcf 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
@@ -32,10 +32,13 @@ import org.yuzu.yuzu_emu.adapters.SetupAdapter
import org.yuzu.yuzu_emu.databinding.FragmentSetupBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.HomeViewModel
+import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage
+import org.yuzu.yuzu_emu.model.StepState
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.GameHelper
+import org.yuzu.yuzu_emu.utils.ViewUtils
class SetupFragment : Fragment() {
private var _binding: FragmentSetupBinding? = null
@@ -112,14 +115,22 @@ class SetupFragment : Fragment() {
0,
false,
R.string.give_permission,
- { permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) },
+ {
+ notificationCallback = it
+ permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
+ },
true,
R.string.notification_warning,
R.string.notification_warning_description,
0,
{
- NotificationManagerCompat.from(requireContext())
+ if (NotificationManagerCompat.from(requireContext())
.areNotificationsEnabled()
+ ) {
+ StepState.COMPLETE
+ } else {
+ StepState.INCOMPLETE
+ }
}
)
)
@@ -133,12 +144,22 @@ class SetupFragment : Fragment() {
R.drawable.ic_add,
true,
R.string.select_keys,
- { mainActivity.getProdKey.launch(arrayOf("*/*")) },
+ {
+ keyCallback = it
+ getProdKey.launch(arrayOf("*/*"))
+ },
true,
R.string.install_prod_keys_warning,
R.string.install_prod_keys_warning_description,
R.string.install_prod_keys_warning_help,
- { File(DirectoryInitialization.userDirectory + "/keys/prod.keys").exists() }
+ {
+ val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys")
+ if (file.exists()) {
+ StepState.COMPLETE
+ } else {
+ StepState.INCOMPLETE
+ }
+ }
)
)
add(
@@ -150,9 +171,8 @@ class SetupFragment : Fragment() {
true,
R.string.add_games,
{
- mainActivity.getGamesDirectory.launch(
- Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
- )
+ gamesDirCallback = it
+ getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
},
true,
R.string.add_games_warning,
@@ -163,7 +183,11 @@ class SetupFragment : Fragment() {
PreferenceManager.getDefaultSharedPreferences(
YuzuApplication.appContext
)
- preferences.getString(GameHelper.KEY_GAME_PATH, "")!!.isNotEmpty()
+ if (preferences.getString(GameHelper.KEY_GAME_PATH, "")!!.isNotEmpty()) {
+ StepState.COMPLETE
+ } else {
+ StepState.INCOMPLETE
+ }
}
)
)
@@ -194,15 +218,15 @@ class SetupFragment : Fragment() {
super.onPageSelected(position)
if (position == 1 && previousPosition == 0) {
- showView(binding.buttonNext)
- showView(binding.buttonBack)
+ ViewUtils.showView(binding.buttonNext)
+ ViewUtils.showView(binding.buttonBack)
} else if (position == 0 && previousPosition == 1) {
- hideView(binding.buttonBack)
- hideView(binding.buttonNext)
+ ViewUtils.hideView(binding.buttonBack)
+ ViewUtils.hideView(binding.buttonNext)
} else if (position == pages.size - 1 && previousPosition == pages.size - 2) {
- hideView(binding.buttonNext)
+ ViewUtils.hideView(binding.buttonNext)
} else if (position == pages.size - 2 && previousPosition == pages.size - 1) {
- showView(binding.buttonNext)
+ ViewUtils.showView(binding.buttonNext)
}
previousPosition = position
@@ -215,7 +239,8 @@ class SetupFragment : Fragment() {
// Checks if the user has completed the task on the current page
if (currentPage.hasWarning) {
- if (currentPage.taskCompleted.invoke()) {
+ val stepState = currentPage.stepCompleted.invoke()
+ if (stepState != StepState.INCOMPLETE) {
pageForward()
return@setOnClickListener
}
@@ -264,9 +289,15 @@ class SetupFragment : Fragment() {
_binding = null
}
+ private lateinit var notificationCallback: SetupCallback
+
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private val permissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
+ if (it) {
+ notificationCallback.onStepCompleted()
+ }
+
if (!it &&
!shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)
) {
@@ -277,6 +308,27 @@ class SetupFragment : Fragment() {
}
}
+ private lateinit var keyCallback: SetupCallback
+
+ val getProdKey =
+ registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
+ if (result != null) {
+ if (mainActivity.processKey(result)) {
+ keyCallback.onStepCompleted()
+ }
+ }
+ }
+
+ private lateinit var gamesDirCallback: SetupCallback
+
+ val getGamesDirectory =
+ registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
+ if (result != null) {
+ mainActivity.processGamesDir(result)
+ gamesDirCallback.onStepCompleted()
+ }
+ }
+
private fun finishSetup() {
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit()
.putBoolean(Settings.PREF_FIRST_APP_LAUNCH, false)
@@ -284,33 +336,6 @@ class SetupFragment : Fragment() {
mainActivity.finishSetup(binding.root.findNavController())
}
- private fun showView(view: View) {
- view.apply {
- alpha = 0f
- visibility = View.VISIBLE
- isClickable = true
- }.animate().apply {
- duration = 300
- alpha(1f)
- }.start()
- }
-
- private fun hideView(view: View) {
- if (view.visibility == View.INVISIBLE) {
- return
- }
-
- view.apply {
- alpha = 1f
- isClickable = false
- }.animate().apply {
- duration = 300
- alpha(0f)
- }.withEndAction {
- view.visibility = View.INVISIBLE
- }
- }
-
fun pageForward() {
binding.viewPager2.currentItem = binding.viewPager2.currentItem + 1
}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt
index a0c878e1c..09a128ae6 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SetupPage.kt
@@ -10,10 +10,20 @@ data class SetupPage(
val buttonIconId: Int,
val leftAlignedIcon: Boolean,
val buttonTextId: Int,
- val buttonAction: () -> Unit,
+ val buttonAction: (callback: SetupCallback) -> Unit,
val hasWarning: Boolean,
val warningTitleId: Int = 0,
val warningDescriptionId: Int = 0,
val warningHelpLinkId: Int = 0,
- val taskCompleted: () -> Boolean = { true }
+ val stepCompleted: () -> StepState = { StepState.UNDEFINED }
)
+
+interface SetupCallback {
+ fun onStepCompleted()
+}
+
+enum class StepState {
+ COMPLETE,
+ INCOMPLETE,
+ UNDEFINED
+}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index f7d7aed1e..f77d06262 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -266,73 +266,80 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
val getGamesDirectory =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
- if (result == null) {
- return@registerForActivityResult
+ if (result != null) {
+ processGamesDir(result)
}
+ }
- contentResolver.takePersistableUriPermission(
- result,
- Intent.FLAG_GRANT_READ_URI_PERMISSION
- )
+ fun processGamesDir(result: Uri) {
+ contentResolver.takePersistableUriPermission(
+ result,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
- // When a new directory is picked, we currently will reset the existing games
- // database. This effectively means that only one game directory is supported.
- PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()
- .putString(GameHelper.KEY_GAME_PATH, result.toString())
- .apply()
+ // When a new directory is picked, we currently will reset the existing games
+ // database. This effectively means that only one game directory is supported.
+ PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()
+ .putString(GameHelper.KEY_GAME_PATH, result.toString())
+ .apply()
- Toast.makeText(
- applicationContext,
- R.string.games_dir_selected,
- Toast.LENGTH_LONG
- ).show()
+ Toast.makeText(
+ applicationContext,
+ R.string.games_dir_selected,
+ Toast.LENGTH_LONG
+ ).show()
- gamesViewModel.reloadGames(true)
- }
+ gamesViewModel.reloadGames(true)
+ }
val getProdKey =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
- if (result == null) {
- return@registerForActivityResult
+ if (result != null) {
+ processKey(result)
}
+ }
- if (FileUtil.getExtension(result) != "keys") {
- MessageDialogFragment.newInstance(
- R.string.reading_keys_failure,
- R.string.install_prod_keys_failure_extension_description
- ).show(supportFragmentManager, MessageDialogFragment.TAG)
- return@registerForActivityResult
- }
+ fun processKey(result: Uri): Boolean {
+ if (FileUtil.getExtension(result) != "keys") {
+ MessageDialogFragment.newInstance(
+ R.string.reading_keys_failure,
+ R.string.install_prod_keys_failure_extension_description
+ ).show(supportFragmentManager, MessageDialogFragment.TAG)
+ return false
+ }
- contentResolver.takePersistableUriPermission(
+ contentResolver.takePersistableUriPermission(
+ result,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ )
+
+ val dstPath = DirectoryInitialization.userDirectory + "/keys/"
+ if (FileUtil.copyUriToInternalStorage(
+ applicationContext,
result,
- Intent.FLAG_GRANT_READ_URI_PERMISSION
+ dstPath,
+ "prod.keys"
)
-
- val dstPath = DirectoryInitialization.userDirectory + "/keys/"
- if (FileUtil.copyUriToInternalStorage(
+ ) {
+ if (NativeLibrary.reloadKeys()) {
+ Toast.makeText(
applicationContext,
- result,
- dstPath,
- "prod.keys"
- )
- ) {
- if (NativeLibrary.reloadKeys()) {
- Toast.makeText(
- applicationContext,
- R.string.install_keys_success,
- Toast.LENGTH_SHORT
- ).show()
- gamesViewModel.reloadGames(true)
- } else {
- MessageDialogFragment.newInstance(
- R.string.invalid_keys_error,
- R.string.install_keys_failure_description,
- R.string.dumping_keys_quickstart_link
- ).show(supportFragmentManager, MessageDialogFragment.TAG)
- }
+ R.string.install_keys_success,
+ Toast.LENGTH_SHORT
+ ).show()
+ gamesViewModel.reloadGames(true)
+ return true
+ } else {
+ MessageDialogFragment.newInstance(
+ R.string.invalid_keys_error,
+ R.string.install_keys_failure_description,
+ R.string.dumping_keys_quickstart_link
+ ).show(supportFragmentManager, MessageDialogFragment.TAG)
+ return false
}
}
+ return false
+ }
val getFirmware =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt
new file mode 100644
index 000000000..f9a3e4126
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ViewUtils.kt
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.yuzu.yuzu_emu.utils
+
+import android.view.View
+
+object ViewUtils {
+ fun showView(view: View, length: Long = 300) {
+ view.apply {
+ alpha = 0f
+ visibility = View.VISIBLE
+ isClickable = true
+ }.animate().apply {
+ duration = length
+ alpha(1f)
+ }.start()
+ }
+
+ fun hideView(view: View, length: Long = 300) {
+ if (view.visibility == View.INVISIBLE) {
+ return
+ }
+
+ view.apply {
+ alpha = 1f
+ isClickable = false
+ }.animate().apply {
+ duration = length
+ alpha(0f)
+ }.withEndAction {
+ view.visibility = View.INVISIBLE
+ }.start()
+ }
+}
diff --git a/src/android/app/src/main/res/layout-w600dp/page_setup.xml b/src/android/app/src/main/res/layout-w600dp/page_setup.xml
index e1c26b2f8..9e0ab8ecb 100644
--- a/src/android/app/src/main/res/layout-w600dp/page_setup.xml
+++ b/src/android/app/src/main/res/layout-w600dp/page_setup.xml
@@ -21,45 +21,76 @@
</LinearLayout>
- <LinearLayout
+ <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="center">
+ android:layout_weight="1">
<com.google.android.material.textview.MaterialTextView
- style="@style/TextAppearance.Material3.DisplaySmall"
android:id="@+id/text_title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAlignment="center"
+ style="@style/TextAppearance.Material3.DisplaySmall"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:gravity="center"
android:textColor="?attr/colorOnSurface"
android:textStyle="bold"
+ app:layout_constraintBottom_toTopOf="@+id/text_description"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintVertical_weight="2"
tools:text="@string/welcome" />
<com.google.android.material.textview.MaterialTextView
- style="@style/TextAppearance.Material3.TitleLarge"
android:id="@+id/text_description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:paddingHorizontal="32dp"
- android:textAlignment="center"
- android:textSize="26sp"
- app:lineHeight="40sp"
+ style="@style/TextAppearance.Material3.TitleLarge"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:gravity="center"
+ android:textSize="20sp"
+ android:paddingHorizontal="16dp"
+ app:layout_constraintBottom_toTopOf="@+id/button_action"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_title"
+ app:layout_constraintVertical_weight="2"
+ app:lineHeight="30sp"
tools:text="@string/welcome_description" />
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/text_confirmation"
+ style="@style/TextAppearance.Material3.TitleLarge"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:paddingHorizontal="16dp"
+ android:paddingBottom="20dp"
+ android:gravity="center"
+ android:textSize="30sp"
+ android:visibility="invisible"
+ android:text="@string/step_complete"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_description"
+ app:layout_constraintVertical_weight="1"
+ app:lineHeight="30sp" />
+
<com.google.android.material.button.MaterialButton
android:id="@+id/button_action"
android:layout_width="wrap_content"
android:layout_height="56dp"
- android:layout_marginTop="32dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="48dp"
android:textSize="20sp"
- app:iconSize="24sp"
app:iconGravity="end"
+ app:iconSize="24sp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_description"
tools:text="Get started" />
- </LinearLayout>
+ </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
diff --git a/src/android/app/src/main/res/layout/page_setup.xml b/src/android/app/src/main/res/layout/page_setup.xml
index 1436ef308..535abcf02 100644
--- a/src/android/app/src/main/res/layout/page_setup.xml
+++ b/src/android/app/src/main/res/layout/page_setup.xml
@@ -21,11 +21,12 @@
app:layout_constraintVertical_chainStyle="spread"
app:layout_constraintWidth_max="220dp"
app:layout_constraintWidth_min="110dp"
- app:layout_constraintVertical_weight="3" />
+ app:layout_constraintVertical_weight="3"
+ tools:src="@drawable/ic_notification" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_title"
- style="@style/TextAppearance.Material3.DisplayMedium"
+ style="@style/TextAppearance.Material3.DisplaySmall"
android:layout_width="0dp"
android:layout_height="0dp"
android:textAlignment="center"
@@ -44,23 +45,42 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:textAlignment="center"
- android:textSize="26sp"
+ android:textSize="20sp"
android:paddingHorizontal="16dp"
app:layout_constraintBottom_toTopOf="@+id/button_action"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_title"
app:layout_constraintVertical_weight="2"
- app:lineHeight="40sp"
+ app:lineHeight="30sp"
tools:text="@string/welcome_description" />
+ <com.google.android.material.textview.MaterialTextView
+ android:id="@+id/text_confirmation"
+ style="@style/TextAppearance.Material3.TitleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:paddingHorizontal="16dp"
+ android:paddingTop="24dp"
+ android:textAlignment="center"
+ android:textSize="30sp"
+ android:visibility="invisible"
+ android:text="@string/step_complete"
+ android:textStyle="bold"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/text_description"
+ app:layout_constraintVertical_weight="1"
+ app:lineHeight="30sp" />
+
<com.google.android.material.button.MaterialButton
android:id="@+id/button_action"
android:layout_width="wrap_content"
android:layout_height="56dp"
- android:textSize="20sp"
android:layout_marginTop="16dp"
android:layout_marginBottom="48dp"
+ android:textSize="20sp"
app:iconGravity="end"
app:iconSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 02e25504d..540ea5ef4 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -29,6 +29,7 @@
<string name="back">Back</string>
<string name="add_games">Add Games</string>
<string name="add_games_description">Select your games folder</string>
+ <string name="step_complete">Complete!</string>
<!-- Home strings -->
<string name="home_games">Games</string>