android: Show complete indicator during setup
This commit is contained in:
		| @@ -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) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|     } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -266,74 +266,81 @@ 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 | ||||
|             ) | ||||
|  | ||||
|             // 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() | ||||
|  | ||||
|             gamesViewModel.reloadGames(true) | ||||
|         } | ||||
|  | ||||
|     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() | ||||
|  | ||||
|         Toast.makeText( | ||||
|             applicationContext, | ||||
|             R.string.games_dir_selected, | ||||
|             Toast.LENGTH_LONG | ||||
|         ).show() | ||||
|  | ||||
|         gamesViewModel.reloadGames(true) | ||||
|     } | ||||
|  | ||||
|     val getProdKey = | ||||
|         registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> | ||||
|             if (result == null) { | ||||
|                 return@registerForActivityResult | ||||
|             } | ||||
|  | ||||
|             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 | ||||
|             } | ||||
|  | ||||
|             contentResolver.takePersistableUriPermission( | ||||
|                 result, | ||||
|                 Intent.FLAG_GRANT_READ_URI_PERMISSION | ||||
|             ) | ||||
|  | ||||
|             val dstPath = DirectoryInitialization.userDirectory + "/keys/" | ||||
|             if (FileUtil.copyUriToInternalStorage( | ||||
|                     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) | ||||
|                 } | ||||
|             if (result != null) { | ||||
|                 processKey(result) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     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( | ||||
|             result, | ||||
|             Intent.FLAG_GRANT_READ_URI_PERMISSION | ||||
|         ) | ||||
|  | ||||
|         val dstPath = DirectoryInitialization.userDirectory + "/keys/" | ||||
|         if (FileUtil.copyUriToInternalStorage( | ||||
|                 applicationContext, | ||||
|                 result, | ||||
|                 dstPath, | ||||
|                 "prod.keys" | ||||
|             ) | ||||
|         ) { | ||||
|             if (NativeLibrary.reloadKeys()) { | ||||
|                 Toast.makeText( | ||||
|                     applicationContext, | ||||
|                     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 -> | ||||
|             if (result == null) { | ||||
|   | ||||
| @@ -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() | ||||
|     } | ||||
| } | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Charles Lombardo
					Charles Lombardo