mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
App | Settings | Blur mnemonic (#2391)
This commit is contained in:
parent
28a0397c8b
commit
d219f74bf3
14 changed files with 274 additions and 242 deletions
|
@ -0,0 +1,125 @@
|
|||
package com.anytypeio.anytype.ui.dashboard
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.widget.TextView
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.inSpans
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.TransitionManager
|
||||
import androidx.transition.TransitionSet
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.anytypeio.anytype.R
|
||||
import com.anytypeio.anytype.core_utils.ext.dimen
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.anytypeio.anytype.presentation.keychain.KeychainPhraseViewModel
|
||||
import com.anytypeio.anytype.presentation.keychain.KeychainPhraseViewModelFactory
|
||||
import com.anytypeio.anytype.presentation.keychain.KeychainViewState
|
||||
import com.anytypeio.anytype.ui.profile.RoundedBackgroundColorSpan
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class BaseMnemonicFragment<T : ViewBinding> : BaseBottomSheetFragment<T>() {
|
||||
|
||||
protected val vm: KeychainPhraseViewModel by viewModels { factory }
|
||||
|
||||
private val fakePhrase by lazy {
|
||||
val bg = RoundedBackgroundColorSpan(
|
||||
requireContext().getColor(R.color.palette_light_ice),
|
||||
dimen(R.dimen.shimmer_radius).toFloat(),
|
||||
dimen(R.dimen.shimmer_radius).toFloat(),
|
||||
dimen(R.dimen.shimmer_line_height).toFloat()
|
||||
)
|
||||
buildSpannedString { inSpans(bg) { append(SHIMMER_PHRASE) } }
|
||||
}
|
||||
|
||||
protected abstract val keychain: TextView
|
||||
|
||||
@Inject
|
||||
lateinit var factory: KeychainPhraseViewModelFactory
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
keychain.setOnClickListener { vm.onKeychainClicked() }
|
||||
binding.root.setOnClickListener { vm.onRootClicked() }
|
||||
|
||||
vm.state.observe(viewLifecycleOwner) { render(it) }
|
||||
|
||||
setupFullHeight()
|
||||
}
|
||||
|
||||
private fun render(state: KeychainViewState) {
|
||||
when (state) {
|
||||
is KeychainViewState.Displayed -> {
|
||||
setKeychainPhrase(state.mnemonic)
|
||||
copyMnemonicToClipboard(state.mnemonic)
|
||||
}
|
||||
is KeychainViewState.Blurred -> {
|
||||
setBlurredPhrase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupFullHeight() {
|
||||
binding.apply { root.layoutParams.height = resources.displayMetrics.heightPixels }
|
||||
|
||||
val bottomSheetDialog = dialog as BottomSheetDialog
|
||||
val behavior = bottomSheetDialog.behavior
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
private fun animateBlurChange() {
|
||||
val transitionSet = TransitionSet().apply {
|
||||
addTransition(ChangeBounds())
|
||||
duration = ANIMATION_LENGTH
|
||||
interpolator = DecelerateInterpolator(ANIMATION_FACTOR)
|
||||
ordering = TransitionSet.ORDERING_TOGETHER
|
||||
}
|
||||
TransitionManager.beginDelayedTransition(binding.root as ViewGroup, transitionSet)
|
||||
}
|
||||
|
||||
private fun setBlurredPhrase() {
|
||||
keychain
|
||||
animateBlurChange()
|
||||
keychain.setShadowLayer(0f, 0f, 0f, 0)
|
||||
keychain.setTextColor(requireContext().getColor(R.color.palette_light_ice))
|
||||
keychain.setShadowLayer(dimen(R.dimen.shimmer_radius).toFloat(), 0f, 0f, 0)
|
||||
keychain.text = fakePhrase
|
||||
}
|
||||
|
||||
private fun setKeychainPhrase(mnemonic: String) {
|
||||
animateBlurChange()
|
||||
keychain.setTextColor(requireContext().getColor(R.color.keychain_text_color))
|
||||
keychain.setShadowLayer(0f, 0f, 0f, 0)
|
||||
keychain.text = mnemonic
|
||||
}
|
||||
|
||||
private fun copyMnemonicToClipboard(keychainPhrase: String) {
|
||||
try {
|
||||
val clipboard =
|
||||
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(
|
||||
DashboardMnemonicReminderDialog.MNEMONIC_LABEL,
|
||||
keychainPhrase
|
||||
)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
toast("Recovery phrase copied to clipboard.")
|
||||
} catch (e: Exception) {
|
||||
toast("Could not copy your recovery phrase. Please try again later, or copy it manually.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val SHIMMER_LENGTH = 50
|
||||
private val SHIMMER_PHRASE = "- ".repeat(SHIMMER_LENGTH)
|
||||
private const val ANIMATION_LENGTH = 700L
|
||||
private const val ANIMATION_FACTOR = 2.5f
|
|
@ -1,129 +1,41 @@
|
|||
package com.anytypeio.anytype.ui.dashboard
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.graphics.BlurMaskFilter
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import android.widget.TextView
|
||||
import com.anytypeio.anytype.analytics.base.EventsDictionary
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ui.ViewState
|
||||
import com.anytypeio.anytype.databinding.DialogDashboardKeychainPhraseBinding
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.keychain.KeychainPhraseViewModel
|
||||
import com.anytypeio.anytype.presentation.keychain.KeychainPhraseViewModelFactory
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import javax.inject.Inject
|
||||
|
||||
class DashboardMnemonicReminderDialog : BottomSheetDialogFragment(), Observer<ViewState<String>> {
|
||||
|
||||
private var _binding: DialogDashboardKeychainPhraseBinding? = null
|
||||
private val binding: DialogDashboardKeychainPhraseBinding get() = _binding!!
|
||||
|
||||
private val vm : KeychainPhraseViewModel by viewModels { factory }
|
||||
|
||||
@Inject
|
||||
lateinit var factory: KeychainPhraseViewModelFactory
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
injectDependencies()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
releaseDependencies()
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
_binding = DialogDashboardKeychainPhraseBinding.inflate(inflater, container, false)
|
||||
return _binding?.root
|
||||
}
|
||||
class DashboardMnemonicReminderDialog :
|
||||
BaseMnemonicFragment<DialogDashboardKeychainPhraseBinding>() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
vm.sendShowEvent(EventsDictionary.Type.firstSession)
|
||||
setBlur()
|
||||
binding.keychain.setOnClickListener {
|
||||
if (binding.keychain.layerType == View.LAYER_TYPE_SOFTWARE) {
|
||||
removeBlur()
|
||||
}
|
||||
}
|
||||
binding.btnCopy.setOnClickListener {
|
||||
vm.onCopyClickedFromScreenSettings()
|
||||
copyMnemonicToClipboard()
|
||||
}
|
||||
binding.root.setOnClickListener {
|
||||
setBlur()
|
||||
}
|
||||
|
||||
vm.state.observe(viewLifecycleOwner, this)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
private fun copyMnemonicToClipboard() {
|
||||
try {
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(MNEMONIC_LABEL, binding.keychain.text.toString())
|
||||
clipboard.setPrimaryClip(clip)
|
||||
toast("Recovery phrase copied to clipboard.")
|
||||
} catch (e: Exception) {
|
||||
toast("Could not copy your recovery phrase. Please try again later, or copy it manually.")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChanged(state: ViewState<String>) {
|
||||
when (state) {
|
||||
is ViewState.Success -> {
|
||||
binding.keychain.text = state.data
|
||||
}
|
||||
is ViewState.Error -> {
|
||||
// TODO
|
||||
}
|
||||
is ViewState.Loading -> {
|
||||
// TODO
|
||||
}
|
||||
is ViewState.Init -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setBlur() = with(binding.keychain) {
|
||||
setLayerType(View.LAYER_TYPE_SOFTWARE, null)
|
||||
val radius = textSize / 3
|
||||
val filter = BlurMaskFilter(radius, BlurMaskFilter.Blur.NORMAL)
|
||||
paint.maskFilter = filter
|
||||
}
|
||||
|
||||
private fun removeBlur() = with(binding.keychain) {
|
||||
setLayerType(View.LAYER_TYPE_NONE, null)
|
||||
paint.maskFilter = null
|
||||
isFocusable = true
|
||||
setTextIsSelectable(true)
|
||||
}
|
||||
|
||||
private fun injectDependencies() {
|
||||
override fun injectDependencies() {
|
||||
componentManager().keychainPhraseComponent.get().inject(this)
|
||||
}
|
||||
|
||||
private fun releaseDependencies() {
|
||||
override fun releaseDependencies() {
|
||||
componentManager().keychainPhraseComponent.release()
|
||||
}
|
||||
|
||||
override fun inflateBinding(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?
|
||||
): DialogDashboardKeychainPhraseBinding {
|
||||
return DialogDashboardKeychainPhraseBinding.inflate(
|
||||
inflater, container, false
|
||||
)
|
||||
}
|
||||
|
||||
override val keychain: TextView by lazy { binding.keychain }
|
||||
|
||||
companion object {
|
||||
const val MNEMONIC_LABEL = "Your Anytype mnemonic phrase"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package com.anytypeio.anytype.ui.profile
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
import android.text.style.LineBackgroundSpan
|
||||
import kotlin.math.abs
|
||||
|
||||
class RoundedBackgroundColorSpan(
|
||||
backgroundColor: Int,
|
||||
private val padding: Float,
|
||||
private val radius: Float,
|
||||
private val lineHeight: Float
|
||||
) : LineBackgroundSpan {
|
||||
|
||||
companion object {
|
||||
private const val NO_INIT = -1f
|
||||
}
|
||||
|
||||
private val rect = RectF()
|
||||
private val paint = Paint().apply {
|
||||
color = backgroundColor
|
||||
isAntiAlias = true
|
||||
}
|
||||
|
||||
private var prevWidth = NO_INIT
|
||||
private var prevRight = NO_INIT
|
||||
|
||||
override fun drawBackground(
|
||||
c: Canvas,
|
||||
p: Paint,
|
||||
left: Int,
|
||||
right: Int,
|
||||
top: Int,
|
||||
baseline: Int,
|
||||
bottom: Int,
|
||||
text: CharSequence,
|
||||
start: Int,
|
||||
end: Int,
|
||||
lineNumber: Int
|
||||
) {
|
||||
|
||||
val actualWidth = p.measureText(text, start, end) + 2f * padding
|
||||
val widthDiff = abs(prevWidth - actualWidth)
|
||||
val diffIsShort = widthDiff < 2f * radius
|
||||
|
||||
val width = if (lineNumber == 0) {
|
||||
actualWidth
|
||||
} else if ((actualWidth < prevWidth) && diffIsShort) {
|
||||
prevWidth
|
||||
} else if ((actualWidth > prevWidth) && diffIsShort) {
|
||||
actualWidth + (2f * radius - widthDiff)
|
||||
} else {
|
||||
actualWidth
|
||||
}
|
||||
|
||||
val shiftLeft = 0f - padding
|
||||
val shiftRight = width + shiftLeft
|
||||
|
||||
val shiftGap = abs((bottom.toFloat() - top.toFloat() - lineHeight) /2f)
|
||||
|
||||
rect.set(shiftLeft, top.toFloat() + shiftGap, shiftRight, bottom.toFloat() - shiftGap)
|
||||
|
||||
c.drawRoundRect(rect, radius, radius, paint)
|
||||
|
||||
prevWidth = width
|
||||
prevRight = rect.right
|
||||
}
|
||||
}
|
|
@ -1,97 +1,22 @@
|
|||
package com.anytypeio.anytype.ui.profile
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.graphics.BlurMaskFilter
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import android.widget.TextView
|
||||
import com.anytypeio.anytype.core_utils.ext.arg
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.anytypeio.anytype.core_utils.ui.ViewState
|
||||
import com.anytypeio.anytype.databinding.DialogKeychainPhraseBinding
|
||||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.presentation.keychain.KeychainPhraseViewModel
|
||||
import com.anytypeio.anytype.presentation.keychain.KeychainPhraseViewModelFactory
|
||||
import javax.inject.Inject
|
||||
import com.anytypeio.anytype.ui.dashboard.BaseMnemonicFragment
|
||||
|
||||
class KeychainPhraseDialog : BaseBottomSheetFragment<DialogKeychainPhraseBinding>(), Observer<ViewState<String>> {
|
||||
|
||||
private val vm : KeychainPhraseViewModel by viewModels { factory }
|
||||
|
||||
@Inject
|
||||
lateinit var factory: KeychainPhraseViewModelFactory
|
||||
class KeychainPhraseDialog : BaseMnemonicFragment<DialogKeychainPhraseBinding>() {
|
||||
|
||||
private val screenType get() = arg<String>(ARG_SCREEN_TYPE)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
vm.sendShowEvent(screenType)
|
||||
setBlur()
|
||||
binding.keychain.setOnClickListener {
|
||||
if (binding.keychain.layerType == View.LAYER_TYPE_SOFTWARE) {
|
||||
removeBlur()
|
||||
}
|
||||
}
|
||||
binding.btnCopy.setOnClickListener {
|
||||
vm.onCopyClickedFromLogout()
|
||||
copyMnemonicToClipboard()
|
||||
}
|
||||
binding.root.setOnClickListener {
|
||||
setBlur()
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyMnemonicToClipboard() {
|
||||
try {
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(MNEMONIC_LABEL, binding.keychain.text.toString())
|
||||
clipboard.setPrimaryClip(clip)
|
||||
toast("Recovery phrase copied to clipboard.")
|
||||
} catch (e: Exception) {
|
||||
toast("Could not copy your mnemonic. Please try again later, or copy it manually.")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
vm.state.observe(viewLifecycleOwner, this)
|
||||
}
|
||||
|
||||
override fun onChanged(state: ViewState<String>) {
|
||||
when (state) {
|
||||
is ViewState.Success -> {
|
||||
binding.keychain.text = state.data
|
||||
}
|
||||
is ViewState.Error -> {
|
||||
// TODO
|
||||
}
|
||||
is ViewState.Loading -> {
|
||||
// TODO
|
||||
}
|
||||
ViewState.Init -> {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setBlur() = with(binding.keychain) {
|
||||
setLayerType(View.LAYER_TYPE_SOFTWARE, null)
|
||||
val radius = textSize / 3
|
||||
val filter = BlurMaskFilter(radius, BlurMaskFilter.Blur.NORMAL)
|
||||
paint.maskFilter = filter
|
||||
}
|
||||
|
||||
private fun removeBlur() = with(binding.keychain) {
|
||||
setLayerType(View.LAYER_TYPE_NONE, null)
|
||||
paint.maskFilter = null
|
||||
isFocusable = true
|
||||
setTextIsSelectable(true)
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
|
@ -109,8 +34,9 @@ class KeychainPhraseDialog : BaseBottomSheetFragment<DialogKeychainPhraseBinding
|
|||
inflater, container, false
|
||||
)
|
||||
|
||||
override val keychain: TextView by lazy { binding.keychain }
|
||||
|
||||
companion object {
|
||||
const val MNEMONIC_LABEL = "Your Anytype recovery phrase"
|
||||
const val ARG_SCREEN_TYPE = "arg.keychain.screen.type"
|
||||
}
|
||||
}
|
12
app/src/main/res/drawable/keychain_ripple.xml
Normal file
12
app/src/main/res/drawable/keychain_ripple.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="?colorControlHighlight">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/shape_transparent" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</ripple>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="8dp" />
|
||||
<solid android:color="@color/shape_transparent" />
|
||||
</shape>
|
|
@ -4,20 +4,31 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.anytypeio.anytype.ui.dashboard.DashboardMnemonicReminderDialog">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/drag"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="6dp"
|
||||
android:src="@drawable/ic_drag"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
style="@style/KeychainDialogTitleStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="23dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="23dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="@string/do_not_forget_mnemonic_phrase"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/drag" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
|
@ -40,8 +51,8 @@
|
|||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:clickable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="20dp"
|
||||
|
@ -50,21 +61,7 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/subtitle"
|
||||
|
||||
tools:text="@string/keychain_mock" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnCopy"
|
||||
style="@style/DefaultStrokeButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/auth_default_button_height"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:text="Copy to clipboard"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/keychain" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -4,7 +4,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/drag"
|
||||
|
@ -21,10 +21,10 @@
|
|||
android:id="@+id/title"
|
||||
style="@style/KeychainDialogTitleStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:textAlignment="center"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="54dp"
|
||||
android:text="@string/back_up_your_recovery_phrase"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/drag" />
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
|||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="34dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:clickable="true"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:paddingStart="20dp"
|
||||
|
@ -60,20 +61,4 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/subtitle"
|
||||
tools:text="@string/keychain_mock" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btnCopy"
|
||||
style="@style/DefaultStrokeButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/auth_default_button_height"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:text="Copy to clipboard"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/keychain" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -31,6 +31,8 @@
|
|||
<dimen name="action_toolbar_bar_margin_bottom">16dp</dimen>
|
||||
<dimen name="action_toolbar_bar_margin_top">8dp</dimen>
|
||||
|
||||
<dimen name="shimmer_radius">5dp</dimen>
|
||||
<dimen name="shimmer_line_height">8dp</dimen>
|
||||
<dimen name="scroll_and_move_start_end_padding">8dp</dimen>
|
||||
<dimen name="height_avatar_on_dashboard">80dp</dimen>
|
||||
<dimen name="width_avatar_on_dashboard">80dp</dimen>
|
||||
|
|
|
@ -86,7 +86,7 @@ Do the computation of an expensive paragraph of text on a background thread:
|
|||
<string name="your_page">Your public page</string>
|
||||
<string name="updates">Updates</string>
|
||||
<string name="log_out">Log out</string>
|
||||
<string name="recovery_phrase_text">Your recovery phrase protects your account. You need it to sign in if you don\'t have access to your devices. Keep it in a safe place.</string>
|
||||
<string name="recovery_phrase_text">You’ll need it to sign in. Keep it in a safe place. If you lose it, you can no longer access your account.</string>
|
||||
<string name="back_up_your_recovery_phrase">Back up your recovery \nphrase</string>
|
||||
<string name="i_ve_written_it_down">i\'ve written it down</string>
|
||||
<string name="keychain_mock">witch collapse practice feed shame open despair creek road again ice least lake tree young address brain envelope</string>
|
||||
|
|
|
@ -153,10 +153,10 @@
|
|||
</style>
|
||||
|
||||
<style name="KeychainDialogKeychainStyle">
|
||||
<item name="android:background">@drawable/rectangle_keychain_background</item>
|
||||
<item name="android:background">@drawable/keychain_ripple</item>
|
||||
<item name="android:fontFamily">monospace</item>
|
||||
<item name="android:lineSpacingExtra">2sp</item>
|
||||
<item name="android:textColor">#1BA0EB</item>
|
||||
<item name="android:textColor">@color/keychain_text_color</item>
|
||||
<item name="android:textIsSelectable">true</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
</style>
|
||||
|
|
|
@ -110,6 +110,7 @@
|
|||
<color name="RelationPlaceholderTextColor">#929082</color>
|
||||
<color name="default_status_text_color">#929082</color>
|
||||
<color name="default_grey">#929082</color>
|
||||
<color name="keychain_text_color">#1BA0EB</color>
|
||||
|
||||
<color name="orange_button_background_color">#FFB522</color>
|
||||
<color name="editor_default_hint_text_color">#CBC9BD</color>
|
||||
|
|
|
@ -10,7 +10,6 @@ import com.anytypeio.anytype.analytics.base.EventsDictionary.keychainPhraseScree
|
|||
import com.anytypeio.anytype.analytics.base.EventsPropertiesKey
|
||||
import com.anytypeio.anytype.analytics.base.sendEvent
|
||||
import com.anytypeio.anytype.analytics.props.Props
|
||||
import com.anytypeio.anytype.core_utils.ui.ViewState
|
||||
import com.anytypeio.anytype.core_utils.ui.ViewStateViewModel
|
||||
import com.anytypeio.anytype.domain.auth.interactor.GetMnemonic
|
||||
import timber.log.Timber
|
||||
|
@ -18,10 +17,13 @@ import timber.log.Timber
|
|||
class KeychainPhraseViewModel(
|
||||
private val getMnemonic: GetMnemonic,
|
||||
private val analytics: Analytics
|
||||
) : ViewStateViewModel<ViewState<String>>() {
|
||||
) : ViewStateViewModel<KeychainViewState>() {
|
||||
|
||||
private var mnemonic: String = ""
|
||||
|
||||
init {
|
||||
proceedWithGettingMnemonic()
|
||||
stateData.postValue(KeychainViewState.Blurred)
|
||||
}
|
||||
|
||||
fun sendShowEvent(type: String) {
|
||||
|
@ -34,7 +36,7 @@ class KeychainPhraseViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
fun onCopyClickedFromScreenSettings() {
|
||||
private fun copyClickedFromScreenSettings() {
|
||||
viewModelScope.sendEvent(
|
||||
analytics = analytics,
|
||||
eventName = keychainCopy,
|
||||
|
@ -44,21 +46,23 @@ class KeychainPhraseViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
fun onCopyClickedFromLogout() {
|
||||
viewModelScope.sendEvent(
|
||||
analytics = analytics,
|
||||
eventName = keychainCopy,
|
||||
props = Props(
|
||||
mapOf(EventsPropertiesKey.type to EventsDictionary.Type.beforeLogout)
|
||||
)
|
||||
)
|
||||
fun onKeychainClicked() {
|
||||
stateData.postValue(KeychainViewState.Displayed(mnemonic))
|
||||
copyClickedFromScreenSettings()
|
||||
}
|
||||
|
||||
fun onRootClicked() {
|
||||
stateData.postValue(KeychainViewState.Blurred)
|
||||
}
|
||||
|
||||
private fun proceedWithGettingMnemonic() {
|
||||
getMnemonic.invoke(viewModelScope, Unit) { result ->
|
||||
result.either(
|
||||
fnL = { e -> Timber.e(e, "Error while getting mnemonic") },
|
||||
fnR = { stateData.postValue(ViewState.Success(it)) }
|
||||
fnR = { mnemonic ->
|
||||
this.mnemonic = mnemonic
|
||||
Any()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package com.anytypeio.anytype.presentation.keychain
|
||||
|
||||
sealed class KeychainViewState {
|
||||
data class Displayed(val mnemonic: String) : KeychainViewState()
|
||||
object Blurred : KeychainViewState()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue