Allow user to generate new recovery code
diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeInputFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeInputFragment.kt
index abd2d8f..15c1d5a 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeInputFragment.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/ui/recoverycode/RecoveryCodeInputFragment.kt
@@ -1,8 +1,11 @@
 package com.stevesoltys.seedvault.ui.recoverycode
 
+import android.app.Activity.RESULT_OK
+import android.content.Intent
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
+import android.view.View.GONE
 import android.view.View.OnFocusChangeListener
 import android.view.View.VISIBLE
 import android.view.ViewGroup
@@ -12,9 +15,11 @@
 import android.widget.TextView
 import android.widget.Toast
 import android.widget.Toast.LENGTH_LONG
+import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
 import androidx.appcompat.app.AlertDialog
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.fragment.app.Fragment
+import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.textfield.TextInputLayout
 import com.stevesoltys.seedvault.R
 import com.stevesoltys.seedvault.isDebugBuild
@@ -32,6 +37,7 @@
 
     private lateinit var introText: TextView
     private lateinit var doneButton: Button
+    private lateinit var newCodeButton: Button
     private lateinit var backView: TextView
     private lateinit var wordLayout1: TextInputLayout
     private lateinit var wordLayout2: TextInputLayout
@@ -61,6 +67,7 @@
 
         introText = v.findViewById(R.id.introText)
         doneButton = v.findViewById(R.id.doneButton)
+        newCodeButton = v.findViewById(R.id.newCodeButton)
         backView = v.findViewById(R.id.backView)
         wordLayout1 = v.findViewById(R.id.wordLayout1)
         wordLayout2 = v.findViewById(R.id.wordLayout2)
@@ -103,6 +110,8 @@
             editText.setAdapter(adapter)
         }
         doneButton.setOnClickListener { done() }
+        newCodeButton.visibility = if (forVerifyingNewCode) GONE else VISIBLE
+        newCodeButton.setOnClickListener { generateNewCode() }
 
         viewModel.existingCodeChecked.observeEvent(viewLifecycleOwner,
             LiveEventHandler { verified -> onExistingCodeChecked(verified) }
@@ -172,10 +181,38 @@
                 setPositiveButton(R.string.recovery_code_verification_try_again) { dialog, _ ->
                     dialog.dismiss()
                 }
+                setNegativeButton(R.string.recovery_code_verification_generate_new) { dialog, _ ->
+                    dialog.dismiss()
+                }
             }
         }.show()
     }
 
+    private val regenRequest = registerForActivityResult(StartActivityForResult()) {
+        if (it.resultCode == RESULT_OK) {
+            parentFragmentManager.popBackStack()
+            Snackbar.make(requireView(), R.string.recovery_code_recreated, Snackbar.LENGTH_LONG)
+                .show()
+        }
+    }
+
+    private fun generateNewCode() {
+        AlertDialog.Builder(requireContext())
+            .setIcon(R.drawable.ic_warning)
+            .setTitle(R.string.recovery_code_verification_new_dialog_title)
+            .setMessage(R.string.recovery_code_verification_new_dialog_message)
+            .setPositiveButton(R.string.recovery_code_verification_generate_new) { dialog, _ ->
+                dialog.dismiss()
+                // TODO try to delete backups
+                val i = Intent(requireContext(), RecoveryCodeActivity::class.java)
+                regenRequest.launch(i)
+            }
+            .setNegativeButton(android.R.string.cancel) { dialog, _ ->
+                dialog.dismiss()
+            }
+            .show()
+    }
+
     @Suppress("MagicNumber")
     private fun getWordLayout(i: Int) = when (i + 1) {
         1 -> wordLayout1
diff --git a/app/src/main/res/layout/fragment_recovery_code_input.xml b/app/src/main/res/layout/fragment_recovery_code_input.xml
index 09e421e..911415e 100644
--- a/app/src/main/res/layout/fragment_recovery_code_input.xml
+++ b/app/src/main/res/layout/fragment_recovery_code_input.xml
@@ -67,7 +67,7 @@
             android:layout_marginBottom="8dp"
             android:text="@string/recovery_code_done_button"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/newCodeButton"
             app:layout_constraintStart_toStartOf="parent" />
 
         <TextView
@@ -86,6 +86,20 @@
             app:layout_constraintVertical_bias="1.0"
             tools:visibility="visible" />
 
+        <Button
+            android:id="@+id/newCodeButton"
+            style="@style/Widget.AppCompat.Button.Borderless"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:layout_marginBottom="8dp"
+            android:text="@string/recovery_code_verification_generate_new"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/doneButton"
+            tools:visibility="visible" />
+
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 </ScrollView>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f3ac414..7b6c773 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -76,6 +76,10 @@
     <string name="recovery_code_verification_error_title">Incorrect Recovery Code</string>
     <string name="recovery_code_verification_error_message">You have entered an invalid recovery code. Please try again!\n\nIf you have lost your code, tap on Generate New Code below.</string>
     <string name="recovery_code_verification_try_again">Try Again</string>
+    <string name="recovery_code_verification_generate_new">Generate New Code</string>
+    <string name="recovery_code_verification_new_dialog_title">Wait one second…</string>
+    <string name="recovery_code_verification_new_dialog_message">Generating a new code will make your existing backups inaccessible. We\'ll try to delete them if possible.\n\nAre you sure you want to do this?</string>
+    <string name="recovery_code_recreated">New recovery code has been created successfully</string>
 
     <!-- Notification -->
     <string name="notification_channel_title">Backup notification</string>