Hush lite wallet for Android
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

216 lines
8.7 KiB

package cash.z.ecc.android.ui.setup
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import cash.z.ecc.android.R
import cash.z.ecc.android.ZcashWalletApp
import cash.z.ecc.android.databinding.FragmentLandingBinding
import cash.z.ecc.android.ext.locale
import cash.z.ecc.android.ext.showSharedLibraryCriticalError
import cash.z.ecc.android.ext.toAppString
import cash.z.ecc.android.feedback.Report
import cash.z.ecc.android.feedback.Report.Funnel.Restore
import cash.z.ecc.android.feedback.Report.Tap.*
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.ZcashNetwork
import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITHOUT_BACKUP
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITH_BACKUP
import cash.z.ecc.android.util.twig
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
class LandingFragment : BaseFragment<FragmentLandingBinding>() {
override val screen = Report.Screen.LANDING
private val walletSetup: WalletSetupViewModel by activityViewModels()
private var skipCount: Int = 0
override fun inflate(inflater: LayoutInflater): FragmentLandingBinding =
FragmentLandingBinding.inflate(inflater)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.buttonPositive.setOnClickListener {
when (binding.buttonPositive.text.toString().toLowerCase(locale())) {
R.string.landing_button_primary.toAppString(true) -> onNewWallet().also {
tapped(
LANDING_NEW
)
}
R.string.landing_button_primary_create_success.toAppString(true) -> onBackupWallet().also {
tapped(
LANDING_BACKUP
)
}
}
}
binding.buttonNegative.setOnLongClickListener {
tapped(DEVELOPER_WALLET_PROMPT)
if (binding.buttonNegative.text.toString().toLowerCase(locale()) == "restore") {
MaterialAlertDialogBuilder(requireContext())
.setMessage("Would you like to import the dev wallet?\n\nIf so, please only send 1000 zatoshis at a time and return some later so that the account remains funded.")
.setTitle("Import Dev Wallet?")
.setCancelable(true)
.setPositiveButton("Import") { dialog, _ ->
tapped(DEVELOPER_WALLET_IMPORT)
dialog.dismiss()
onUseDevWallet()
}
.setNegativeButton("Cancel") { dialog, _ ->
tapped(DEVELOPER_WALLET_CANCEL)
dialog.dismiss()
}
.show()
true
} else {
false
}
}
binding.buttonNegative.setOnClickListener {
when (binding.buttonNegative.text.toString().toLowerCase(locale())) {
R.string.landing_button_secondary.toAppString(true) -> onRestoreWallet().also {
mainActivity?.reportFunnel(Restore.Initiated)
tapped(LANDING_RESTORE)
}
else -> onSkip(++skipCount)
}
}
}
override fun onAttach(context: Context) {
super.onAttach(context)
walletSetup.checkSeed().onEach {
when (it) {
SEED_WITHOUT_BACKUP, SEED_WITH_BACKUP -> {
mainActivity?.safeNavigate(R.id.nav_backup)
}
else -> {}
}
}.launchIn(lifecycleScope)
}
override fun onResume() {
super.onResume()
view?.postDelayed(
{
mainActivity?.hideKeyboard()
},
25L
)
}
private fun onSkip(count: Int) {
when (count) {
1 -> {
tapped(LANDING_BACKUP_SKIPPED_1)
binding.textMessage.setText(R.string.landing_backup_skipped_message_1)
binding.buttonNegative.setText(R.string.landing_button_backup_skipped_1)
}
2 -> {
tapped(LANDING_BACKUP_SKIPPED_2)
binding.textMessage.setText(R.string.landing_backup_skipped_message_2)
binding.buttonNegative.setText(R.string.landing_button_backup_skipped_2)
}
else -> {
tapped(LANDING_BACKUP_SKIPPED_3)
onEnterWallet()
}
}
}
private fun onRestoreWallet() {
mainActivity?.safeNavigate(R.id.action_nav_landing_to_nav_restore)
}
// AKA import wallet
private fun onUseDevWallet() {
val seedPhrase: String
val birthday: BlockHeight
// new testnet dev wallet
when (ZcashWalletApp.instance.defaultNetwork) {
ZcashNetwork.Mainnet -> {
seedPhrase =
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
birthday = BlockHeight.new(ZcashNetwork.Mainnet, 991645) // 663174
}
ZcashNetwork.Testnet -> {
seedPhrase =
"quantum whisper lion route fury lunar pelican image job client hundred sauce chimney barely life cliff spirit admit weekend message recipe trumpet impact kitten"
birthday = BlockHeight.new(ZcashNetwork.Testnet, 1330190)
}
else -> throw RuntimeException("No developer wallet exists for network ${ZcashWalletApp.instance.defaultNetwork}")
}
mainActivity?.apply {
lifecycleScope.launch {
try {
walletSetup.importWallet(seedPhrase, birthday)
mainActivity?.startSync()
binding.buttonPositive.isEnabled = true
binding.textMessage.setText(R.string.landing_import_success_message)
binding.buttonNegative.setText(R.string.landing_button_secondary_import_success)
binding.buttonPositive.setText(R.string.landing_import_success_primary_button)
playSound("sound_receive_small.mp3")
vibrateSuccess()
} catch (e: UnsatisfiedLinkError) {
mainActivity?.showSharedLibraryCriticalError(e)
}
}
}
}
private fun onNewWallet() {
lifecycleScope.launch {
binding.buttonPositive.setText(R.string.landing_button_progress_create)
binding.buttonPositive.isEnabled = false
try {
walletSetup.newWallet()
mainActivity?.startSync()
binding.buttonPositive.isEnabled = true
binding.textMessage.setText(R.string.landing_create_success_message)
binding.buttonNegative.setText(R.string.landing_button_secondary_create_success)
binding.buttonPositive.setText(R.string.landing_button_primary_create_success)
mainActivity?.playSound("sound_receive_small.mp3")
mainActivity?.vibrateSuccess()
} catch (e: UnsatisfiedLinkError) {
// For developer sanity:
// show a nice dialog, rather than a toast, when the rust didn't get compile
// which can happen often when working from a local SDK build
mainActivity?.showSharedLibraryCriticalError(e)
} catch (t: Throwable) {
twig("Failed to create wallet due to: $t")
mainActivity?.feedback?.report(t)
binding.buttonPositive.isEnabled = true
binding.buttonPositive.setText(R.string.landing_button_primary)
Toast.makeText(
context,
"Failed to create wallet. See logs for details. Try restarting the app.\n\nMessage: \n${t.message}",
Toast.LENGTH_LONG
).show()
}
}
}
private fun onBackupWallet() {
skipCount = 0
mainActivity?.safeNavigate(R.id.action_nav_landing_to_nav_backup)
}
private fun onEnterWallet() {
skipCount = 0
mainActivity?.navController?.popBackStack()
}
}