diff --git a/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/ConfirmRecoveryPhraseActivity.kt b/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/ConfirmRecoveryPhraseActivity.kt index 4b5b817a69..f737b2faf0 100644 --- a/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/ConfirmRecoveryPhraseActivity.kt +++ b/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/ConfirmRecoveryPhraseActivity.kt @@ -4,6 +4,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.support.v7.widget.GridLayoutManager +import android.view.View import android.widget.TextView import com.jakewharton.rxbinding2.view.clicks import io.reactivex.android.schedulers.AndroidSchedulers @@ -15,9 +16,11 @@ import pm.gnosis.heimdall.R import pm.gnosis.heimdall.helpers.ToolbarHelper import pm.gnosis.heimdall.reporting.ScreenId import pm.gnosis.heimdall.ui.base.ViewModelActivity +import pm.gnosis.heimdall.utils.setCompoundDrawableResource import pm.gnosis.svalinn.common.utils.getColorCompat import pm.gnosis.svalinn.common.utils.snackbar import pm.gnosis.svalinn.common.utils.subscribeForResult +import pm.gnosis.utils.nullOnThrow import pm.gnosis.utils.words import timber.log.Timber import javax.inject.Inject @@ -33,11 +36,17 @@ abstract class ConfirmRecoveryPhraseActivity @Inject lateinit var adapter: ConfirmRecoveryPhraseAdapter + private var scrollRunnable: Runnable? = null + + override fun layout() = R.layout.layout_confirm_recovery_phrase + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel.setup(intent.getStringExtra(EXTRA_RECOVERY_PHRASE)) + layout_confirm_recovery_phrase_submit.setCompoundDrawableResource(right = R.drawable.ic_arrow_forward_24dp) + layout_confirm_recovery_phrase_recycler_view.apply { setHasFixedSize(true) layoutManager = GridLayoutManager(context, 3, GridLayoutManager.VERTICAL, false) @@ -67,7 +76,7 @@ abstract class ConfirmRecoveryPhraseActivity layout_confirm_recovery_phrase_word_4.text = recoveryPhraseWords[randomPositions[3]] layout_confirm_recovery_phrase_word_4.isClickable = true - adapter.setWords(recoveryPhraseWords, randomPositions) + scrollToWord(adapter.setWords(recoveryPhraseWords, randomPositions)) } override fun onStart() { @@ -96,6 +105,11 @@ abstract class ConfirmRecoveryPhraseActivity disposables += toolbarHelper.setupShadow(layout_confirm_recovery_phrase_toolbar_shadow, layout_confirm_recovery_phrase_scroll_view) } + override fun onPause() { + scrollRunnable?.let { layout_confirm_recovery_phrase_scroll_view.removeCallbacks(it) } + super.onPause() + } + private fun onIncorrectPositions(incorrectPositions: Set) { if (incorrectPositions.isEmpty()) { isRecoveryPhraseConfirmed() @@ -110,7 +124,7 @@ abstract class ConfirmRecoveryPhraseActivity private fun subscribeWordSelection(wordView: TextView) = wordView.clicks().subscribeBy( onNext = { - adapter.pushWord(wordView.text.toString()) + scrollToWord(adapter.pushWord(wordView.text.toString())) setWord(isEnabled = false, wordView = wordView) }, onError = Timber::e @@ -119,16 +133,28 @@ abstract class ConfirmRecoveryPhraseActivity override fun onBackPressed() { if (adapter.getSelectedCount() == 0) super.onBackPressed() else { - val poppedWord = adapter.popWord() + val (poppedWord, nextActiveIndex) = adapter.popWord() when (poppedWord) { layout_confirm_recovery_phrase_word_1.text -> setWord(isEnabled = true, wordView = layout_confirm_recovery_phrase_word_1) layout_confirm_recovery_phrase_word_2.text -> setWord(isEnabled = true, wordView = layout_confirm_recovery_phrase_word_2) layout_confirm_recovery_phrase_word_3.text -> setWord(isEnabled = true, wordView = layout_confirm_recovery_phrase_word_3) layout_confirm_recovery_phrase_word_4.text -> setWord(isEnabled = true, wordView = layout_confirm_recovery_phrase_word_4) } + scrollToWord(nextActiveIndex) } } + private fun scrollToWord(wordPosition: Int) { + scrollRunnable?.let { layout_confirm_recovery_phrase_scroll_view.removeCallbacks(it) } + scrollRunnable = Runnable { + layout_confirm_recovery_phrase_recycler_view.layoutManager.findViewByPosition(wordPosition)?.let { + // Android sometimes doesn't like this if this is done at the wrong point in time + nullOnThrow { layout_confirm_recovery_phrase_scroll_view.requestChildFocus(it, it) } + } + } + layout_confirm_recovery_phrase_scroll_view.postDelayed(scrollRunnable, SCROLL_DELAY_MS) + } + private fun setWord(isEnabled: Boolean, wordView: TextView) { wordView.isClickable = isEnabled wordView.setTextColor(getColorCompat(if (isEnabled) R.color.word_recovery_phrase_picker else R.color.word_recovery_phrase_picker_disabled)) @@ -144,9 +170,8 @@ abstract class ConfirmRecoveryPhraseActivity randomWordsDisposable?.dispose() } - override fun layout() = R.layout.layout_confirm_recovery_phrase - companion object { + private const val SCROLL_DELAY_MS = 400L const val EXTRA_RECOVERY_PHRASE = "extra.string.recovery_phrase" fun createIntent(context: Context, recoveryPhrase: String) = Intent(context, ConfirmRecoveryPhraseActivity::class.java).apply { diff --git a/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/ConfirmRecoveryPhraseAdapter.kt b/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/ConfirmRecoveryPhraseAdapter.kt index 6b6bab5d2f..88da08f5f3 100644 --- a/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/ConfirmRecoveryPhraseAdapter.kt +++ b/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/ConfirmRecoveryPhraseAdapter.kt @@ -42,17 +42,27 @@ class ConfirmRecoveryPhraseAdapter @Inject constructor() : RecyclerView.Adapter< override fun getItemCount() = words.size - fun setWords(words: List, inputPositions: List) { + /** + * Returns the index of the word that is active or -1 if no word is active + */ + fun setWords(words: List, inputPositions: List): Int { this.words.clear() this.words.addAll(words.mapIndexed { index, word -> if (inputPositions.contains(index)) Word(word = "", isSelectable = true, isActive = false, isError = false) else Word(word = word, isSelectable = false, isActive = false, isError = false) }) - this.words.firstOrNull { it.isSelectable }?.let { it.isActive = true } + val currentActiveWord = this.words.indexOfFirst { it.isSelectable } + if (currentActiveWord != -1) { + this.words[currentActiveWord].isActive = true + } notifyDataSetChanged() + return currentActiveWord } - fun pushWord(word: String) { + /** + * Returns the index of the word that is active or -1 if no word is active + */ + fun pushWord(word: String): Int { // Set the current active word to inactive val currentActiveWordIndex = words.indexOfFirst { it.isActive } if (currentActiveWordIndex != -1) { @@ -68,9 +78,13 @@ class ConfirmRecoveryPhraseAdapter @Inject constructor() : RecyclerView.Adapter< words[nextActiveWordIndex].isActive = true notifyItemChanged(nextActiveWordIndex) } + return nextActiveWordIndex } - fun popWord(): String { + /** + * Returns the word that was popped and the next active position or -1 if no position is active + */ + fun popWord(): Pair { var poppedWord = "" // Remove the current active status @@ -91,7 +105,7 @@ class ConfirmRecoveryPhraseAdapter @Inject constructor() : RecyclerView.Adapter< notifyItemChanged(wordToPopIndex) } - return poppedWord + return poppedWord to wordToPopIndex } fun observeSelectedCount(): Observable = selectedWordCountSubject.startWith(getSelectedCount()) diff --git a/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/RecoveryPhraseIntroActivity.kt b/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/RecoveryPhraseIntroActivity.kt index 530d41bb76..0f3f8ee7e9 100644 --- a/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/RecoveryPhraseIntroActivity.kt +++ b/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/RecoveryPhraseIntroActivity.kt @@ -18,6 +18,7 @@ import pm.gnosis.heimdall.helpers.ToolbarHelper import pm.gnosis.heimdall.reporting.ScreenId import pm.gnosis.heimdall.ui.base.BaseActivity import pm.gnosis.heimdall.utils.scaleBitmapToWidth +import pm.gnosis.heimdall.utils.setCompoundDrawableResource import timber.log.Timber import javax.inject.Inject @@ -32,6 +33,7 @@ abstract class RecoveryPhraseIntroActivity : BaseActivity() { super.onCreate(savedInstanceState) inject() setContentView(R.layout.layout_recovery_phrase_intro) + layout_recovery_phrase_intro_next.setCompoundDrawableResource(right = R.drawable.ic_arrow_forward_24dp) } override fun onStart() { diff --git a/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/SetupRecoveryPhraseActivity.kt b/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/SetupRecoveryPhraseActivity.kt index 29fb45ea9c..fadf907a02 100644 --- a/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/SetupRecoveryPhraseActivity.kt +++ b/app/src/main/java/pm/gnosis/heimdall/ui/recoveryphrase/SetupRecoveryPhraseActivity.kt @@ -16,12 +16,13 @@ import pm.gnosis.heimdall.R import pm.gnosis.heimdall.helpers.ToolbarHelper import pm.gnosis.heimdall.reporting.ScreenId import pm.gnosis.heimdall.ui.base.ViewModelActivity +import pm.gnosis.heimdall.utils.setCompoundDrawableResource import timber.log.Timber import javax.inject.Inject abstract class SetupRecoveryPhraseActivity : ViewModelActivity() { override fun screenId(): ScreenId = ScreenId.CONFIRM_RECOVERY_PHRASE - + @Inject lateinit var toolbarHelper: ToolbarHelper @@ -34,6 +35,8 @@ abstract class SetupRecoveryPhraseActivity : V super.onCreate(savedInstanceState) setContentView(R.layout.layout_setup_recovery_phrase) + layout_setup_recovery_phrase_next.setCompoundDrawableResource(right = R.drawable.ic_arrow_forward_24dp) + layout_setup_recovery_phrase_recycler_view.apply { setHasFixedSize(true) layoutManager = GridLayoutManager(context, 3, GridLayoutManager.VERTICAL, false) diff --git a/app/src/main/java/pm/gnosis/heimdall/ui/safe/main/NoSafesFragment.kt b/app/src/main/java/pm/gnosis/heimdall/ui/safe/main/NoSafesFragment.kt index c298a049b8..6df416346e 100644 --- a/app/src/main/java/pm/gnosis/heimdall/ui/safe/main/NoSafesFragment.kt +++ b/app/src/main/java/pm/gnosis/heimdall/ui/safe/main/NoSafesFragment.kt @@ -18,6 +18,7 @@ import pm.gnosis.heimdall.reporting.ScreenId import pm.gnosis.heimdall.ui.base.BaseFragment import pm.gnosis.heimdall.ui.safe.create.CreateSafeIntroActivity import pm.gnosis.heimdall.ui.safe.recover.safe.CheckSafeActivity +import pm.gnosis.heimdall.ui.safe.recover.safe.RecoverSafeIntroActivity import timber.log.Timber import javax.inject.Inject @@ -37,7 +38,7 @@ class NoSafesFragment : BaseFragment() { .subscribeBy(onNext = { startActivity(CreateSafeIntroActivity.createIntent(context!!)) }, onError = Timber::e) disposables += layout_no_safes_recover_safe.clicks() - .subscribeBy(onNext = { startActivity(CheckSafeActivity.createIntent(context!!)) }, onError = Timber::e) + .subscribeBy(onNext = { startActivity(RecoverSafeIntroActivity.createIntent(context!!)) }, onError = Timber::e) } override fun inject(component: ApplicationComponent) { diff --git a/app/src/main/java/pm/gnosis/heimdall/ui/safe/main/SafeMainActivity.kt b/app/src/main/java/pm/gnosis/heimdall/ui/safe/main/SafeMainActivity.kt index d2552ba026..120ab24f1c 100644 --- a/app/src/main/java/pm/gnosis/heimdall/ui/safe/main/SafeMainActivity.kt +++ b/app/src/main/java/pm/gnosis/heimdall/ui/safe/main/SafeMainActivity.kt @@ -42,6 +42,7 @@ import pm.gnosis.heimdall.ui.safe.recover.extension.ReplaceExtensionPairingActiv import pm.gnosis.heimdall.ui.safe.recover.recoveryphrase.ScanExtensionAddressActivity import pm.gnosis.heimdall.ui.safe.recover.recoveryphrase.SetupNewRecoveryPhraseIntroActivity import pm.gnosis.heimdall.ui.safe.recover.safe.CheckSafeActivity +import pm.gnosis.heimdall.ui.safe.recover.safe.RecoverSafeIntroActivity import pm.gnosis.heimdall.ui.safe.recover.safe.submit.RecoveringSafeFragment import pm.gnosis.heimdall.ui.settings.general.GeneralSettingsActivity import pm.gnosis.heimdall.ui.tokens.manage.ManageTokensActivity @@ -182,7 +183,7 @@ class SafeMainActivity : ViewModelActivity() { } layout_safe_main_recover_safe.setOnClickListener { - startActivity(CheckSafeActivity.createIntent(this)) + startActivity(RecoverSafeIntroActivity.createIntent(this)) closeDrawer() } diff --git a/app/src/main/java/pm/gnosis/heimdall/ui/safe/recover/safe/RecoverSafeIntroActivity.kt b/app/src/main/java/pm/gnosis/heimdall/ui/safe/recover/safe/RecoverSafeIntroActivity.kt index f488c79dde..7668a1e1e2 100644 --- a/app/src/main/java/pm/gnosis/heimdall/ui/safe/recover/safe/RecoverSafeIntroActivity.kt +++ b/app/src/main/java/pm/gnosis/heimdall/ui/safe/recover/safe/RecoverSafeIntroActivity.kt @@ -14,6 +14,7 @@ import pm.gnosis.heimdall.di.modules.ViewModule import pm.gnosis.heimdall.helpers.ToolbarHelper import pm.gnosis.heimdall.reporting.ScreenId import pm.gnosis.heimdall.ui.base.BaseActivity +import pm.gnosis.heimdall.utils.setCompoundDrawableResource import timber.log.Timber import javax.inject.Inject @@ -28,6 +29,8 @@ class RecoverSafeIntroActivity: BaseActivity() { super.onCreate(savedInstanceState) inject() setContentView(R.layout.layout_recover_safe_intro) + + layout_recover_safe_intro_next.setCompoundDrawableResource(right = R.drawable.ic_arrow_forward_24dp) } override fun onStart() { diff --git a/app/src/main/res/layout/layout_confirm_recovery_phrase.xml b/app/src/main/res/layout/layout_confirm_recovery_phrase.xml index 32a5e07206..4fa8fcadfa 100644 --- a/app/src/main/res/layout/layout_confirm_recovery_phrase.xml +++ b/app/src/main/res/layout/layout_confirm_recovery_phrase.xml @@ -2,6 +2,7 @@ @@ -53,8 +54,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" - android:paddingStart="16dp" android:paddingEnd="16dp" + android:paddingStart="16dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -173,16 +174,16 @@ android:layout_width="wrap_content" android:layout_height="0dp" android:background="@drawable/selectable_background" - android:drawableEnd="@drawable/ic_arrow_forward_24dp" android:drawablePadding="12dp" android:gravity="center" - android:paddingStart="12dp" android:paddingEnd="12dp" + android:paddingStart="12dp" android:text="@string/submit" android:textColor="@color/white" app:layout_constraintBottom_toBottomOf="@+id/layout_confirm_recovery_phrase_bottom_bar_container" app:layout_constraintEnd_toEndOf="@+id/layout_confirm_recovery_phrase_bottom_bar_container" - app:layout_constraintTop_toTopOf="@+id/layout_confirm_recovery_phrase_bottom_bar_container" /> + app:layout_constraintTop_toTopOf="@+id/layout_confirm_recovery_phrase_bottom_bar_container" + tools:drawableEnd="@drawable/ic_arrow_forward_24dp" /> @@ -37,11 +38,11 @@ android:id="@+id/layout_recovery_phrase_intro_description" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="40dp" android:layout_marginBottom="20dp" + android:layout_marginTop="40dp" android:lineSpacingExtra="7sp" - android:paddingStart="56dp" android:paddingEnd="56dp" + android:paddingStart="56dp" android:text="@string/layout_recovery_phrase_intro_description" android:textColor="@color/battleship_grey" android:textSize="15sp" @@ -110,17 +111,17 @@ android:layout_width="wrap_content" android:layout_height="0dp" android:background="@drawable/selectable_background" - android:drawableEnd="@drawable/ic_arrow_forward_24dp" android:drawablePadding="16dp" android:gravity="center" - android:paddingStart="16dp" android:paddingEnd="16dp" + android:paddingStart="16dp" android:text="@string/get_my_recovery_phrase" android:textColor="@color/white" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="@+id/layout_recovery_phrase_intro_bottom_bar" app:layout_constraintEnd_toEndOf="@+id/layout_recovery_phrase_intro_bottom_bar" - app:layout_constraintTop_toTopOf="@+id/layout_recovery_phrase_intro_bottom_bar" /> + app:layout_constraintTop_toTopOf="@+id/layout_recovery_phrase_intro_bottom_bar" + tools:drawableEnd="@drawable/ic_arrow_forward_24dp" /> @@ -54,10 +55,10 @@ android:id="@+id/layout_setup_recovery_phrase_recycler_view" android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginBottom="20dp" + android:layout_marginEnd="24dp" android:layout_marginStart="24dp" android:layout_marginTop="40dp" - android:layout_marginEnd="24dp" - android:layout_marginBottom="20dp" app:layout_constraintBottom_toTopOf="@+id/layout_setup_recovery_phrase_waves" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -126,16 +127,16 @@ android:layout_width="wrap_content" android:layout_height="0dp" android:background="@drawable/selectable_background" - android:drawableEnd="@drawable/ic_arrow_forward_24dp" android:drawablePadding="12dp" android:gravity="center" - android:paddingStart="12dp" android:paddingEnd="12dp" + android:paddingStart="12dp" android:text="@string/i_have_a_copy" android:textColor="@color/white" app:layout_constraintBottom_toBottomOf="@+id/layout_setup_recovery_phrase_container" app:layout_constraintEnd_toEndOf="@+id/layout_setup_recovery_phrase_container" - app:layout_constraintTop_toTopOf="@+id/layout_setup_recovery_phrase_container" /> + app:layout_constraintTop_toTopOf="@+id/layout_setup_recovery_phrase_container" + tools:drawableEnd="@drawable/ic_arrow_forward_24dp" /> diff --git a/app/src/main/res/layout/layout_setup_recovery_phrase_item_first.xml b/app/src/main/res/layout/layout_setup_recovery_phrase_item_first.xml index ef75a0559e..a40e0836c8 100644 --- a/app/src/main/res/layout/layout_setup_recovery_phrase_item_first.xml +++ b/app/src/main/res/layout/layout_setup_recovery_phrase_item_first.xml @@ -1,6 +1,7 @@ diff --git a/app/src/main/res/layout/layout_setup_recovery_phrase_item_last.xml b/app/src/main/res/layout/layout_setup_recovery_phrase_item_last.xml index 1087f921fe..aac4ee149c 100644 --- a/app/src/main/res/layout/layout_setup_recovery_phrase_item_last.xml +++ b/app/src/main/res/layout/layout_setup_recovery_phrase_item_last.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" + xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@drawable/ic_outlined_word_last" android:gravity="center" android:letterSpacing="0.04" @@ -11,4 +12,9 @@ android:textColor="@color/word_recovery_phrase" android:textSize="16sp" android:textStyle="bold" + app:autoSizeTextType="uniform" + app:autoSizeMinTextSize="12sp" + app:autoSizeMaxTextSize="16sp" + app:autoSizeStepGranularity="2sp" + android:maxLines="1" tools:text="Word" /> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 339551b7e3..6c29cd0bc0 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -82,7 +82,6 @@ 16sp sans-serif normal - 12sp @color/dark_slate_blue