Implemented homescreen.
- Added logic for numberpad and send button - Added logic for starting sync and displaying progress
This commit is contained in:
parent
fa4415ae99
commit
f81c6b2dff
|
@ -1,89 +1,255 @@
|
|||
package cash.z.ecc.android.ui.home
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import cash.z.ecc.android.R
|
||||
import cash.z.ecc.android.databinding.FragmentHomeBinding
|
||||
import cash.z.ecc.android.di.annotation.FragmentScope
|
||||
import cash.z.ecc.android.ext.disabledIf
|
||||
import cash.z.ecc.android.ext.goneIf
|
||||
import cash.z.ecc.android.ext.onClickNavTo
|
||||
import cash.z.ecc.android.ui.base.BaseFragment
|
||||
import cash.z.ecc.android.ui.home.HomeFragment.BannerAction.*
|
||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel
|
||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.*
|
||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.NO_SEED
|
||||
import cash.z.wallet.sdk.SdkSynchronizer
|
||||
import cash.z.wallet.sdk.Synchronizer.Status.SYNCING
|
||||
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
|
||||
import cash.z.wallet.sdk.ext.convertZecToZatoshi
|
||||
import cash.z.wallet.sdk.ext.safelyConvertToBigDecimal
|
||||
import cash.z.wallet.sdk.ext.twig
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
||||
|
||||
private lateinit var numberPad: List<TextView>
|
||||
private lateinit var uiModel: HomeViewModel.UiModel
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelProvider.Factory
|
||||
|
||||
private val walletSetup: WalletSetupViewModel by activityViewModels { viewModelFactory }
|
||||
private val viewModel: HomeViewModel by activityViewModels { viewModelFactory }
|
||||
|
||||
private val _typedChars = ConflatedBroadcastChannel<Char>()
|
||||
private val typedChars = _typedChars.asFlow()
|
||||
|
||||
override fun inflate(inflater: LayoutInflater): FragmentHomeBinding =
|
||||
FragmentHomeBinding.inflate(inflater)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
with(binding) {
|
||||
numberPad = arrayListOf(
|
||||
buttonNumberPad0,
|
||||
buttonNumberPad1,
|
||||
buttonNumberPad2,
|
||||
buttonNumberPad3,
|
||||
buttonNumberPad4,
|
||||
buttonNumberPad5,
|
||||
buttonNumberPad6,
|
||||
buttonNumberPad7,
|
||||
buttonNumberPad8,
|
||||
buttonNumberPad9,
|
||||
buttonNumberPadDecimal,
|
||||
buttonNumberPadBack
|
||||
)
|
||||
hitAreaReceive.onClickNavTo(R.id.action_nav_home_to_nav_receive)
|
||||
iconDetail.onClickNavTo(R.id.action_nav_home_to_nav_detail)
|
||||
textDetail.onClickNavTo(R.id.action_nav_home_to_nav_detail)
|
||||
hitAreaScan.onClickNavTo(R.id.action_nav_home_to_nav_send)
|
||||
|
||||
textBannerAction.setOnClickListener {
|
||||
onBannerAction(BannerAction.from((it as? TextView)?.text?.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: trigger this from presenter
|
||||
onNoFunds()
|
||||
}
|
||||
//
|
||||
// LifeCycle
|
||||
//
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
twig("HomeFragment.onAttach")
|
||||
super.onAttach(context)
|
||||
|
||||
// call initSync either now or later (after initializing DBs with newly created seed)
|
||||
walletSetup.checkSeed().onEach {
|
||||
twig("Checking seed")
|
||||
when(it) {
|
||||
NO_SEED -> {
|
||||
twig("Seed not found, therefore, launching seed creation flow")
|
||||
// interact with user to create, backup and verify seed
|
||||
mainActivity?.navController?.navigate(R.id.action_nav_home_to_create_wallet)
|
||||
// leads to a call to initSync(), later (after accounts are created from seed)
|
||||
}
|
||||
else -> {
|
||||
twig("Found seed. Re-opening existing wallet")
|
||||
mainActivity?.initSync()
|
||||
}
|
||||
}
|
||||
}.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
twig("HomeFragment.onViewCreated uiModel: ${::uiModel.isInitialized} saved: ${savedInstanceState != null}")
|
||||
with(binding) {
|
||||
numberPad = arrayListOf(
|
||||
buttonNumberPad0.asKey(),
|
||||
buttonNumberPad1.asKey(),
|
||||
buttonNumberPad2.asKey(),
|
||||
buttonNumberPad3.asKey(),
|
||||
buttonNumberPad4.asKey(),
|
||||
buttonNumberPad5.asKey(),
|
||||
buttonNumberPad6.asKey(),
|
||||
buttonNumberPad7.asKey(),
|
||||
buttonNumberPad8.asKey(),
|
||||
buttonNumberPad9.asKey(),
|
||||
buttonNumberPadDecimal.asKey(),
|
||||
buttonNumberPadBack.asKey()
|
||||
)
|
||||
hitAreaReceive.onClickNavTo(R.id.action_nav_home_to_nav_receive)
|
||||
iconDetail.onClickNavTo(R.id.action_nav_home_to_nav_detail)
|
||||
textDetail.onClickNavTo(R.id.action_nav_home_to_nav_detail)
|
||||
// hitAreaScan.onClickNavTo(R.id.action_nav_home_to_nav_send)
|
||||
|
||||
textBannerAction.setOnClickListener {
|
||||
onBannerAction(BannerAction.from((it as? TextView)?.text?.toString()))
|
||||
}
|
||||
buttonSend.setOnClickListener {
|
||||
onSend()
|
||||
}
|
||||
}
|
||||
if (::uiModel.isInitialized) {
|
||||
twig("uiModel exists!")
|
||||
onModelUpdated(HomeViewModel.UiModel(), uiModel)
|
||||
} else {
|
||||
twig("uiModel does not exist!")
|
||||
mainActivity?.onSyncInit {
|
||||
viewModel.initialize(mainActivity!!.synchronizer, typedChars)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
twig("HomeFragment.onResume resumeScope.isActive: ${resumedScope.isActive} $resumedScope")
|
||||
viewModel.uiModels.scanReduce { old, new ->
|
||||
onModelUpdated(old, new)
|
||||
new
|
||||
}.catch { e ->
|
||||
twig("exception while processing uiModels $e")
|
||||
}.launchIn(resumedScope)
|
||||
|
||||
// TODO: see if there is a better way to trigger a refresh of the uiModel on resume
|
||||
// the latest one should just be in the viewmodel and we should just "resubscribe"
|
||||
// but for some reason, this doesn't always happen, which kind of defeats the purpose
|
||||
// of having a cold stream in the view model
|
||||
resumedScope.launch {
|
||||
(mainActivity!!.synchronizer as SdkSynchronizer).refreshBalance()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
twig("HomeFragment.onSaveInstanceState")
|
||||
if (::uiModel.isInitialized) {
|
||||
outState.putParcelable("uiModel", uiModel)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewStateRestored(savedInstanceState: Bundle?) {
|
||||
super.onViewStateRestored(savedInstanceState)
|
||||
savedInstanceState?.let { inState ->
|
||||
twig("HomeFragment.onViewStateRestored")
|
||||
onModelUpdated(HomeViewModel.UiModel(), inState.getParcelable("uiModel")!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Public UI API
|
||||
//
|
||||
|
||||
fun setSendEnabled(enabled: Boolean) {
|
||||
binding.buttonSend.apply {
|
||||
isEnabled = enabled
|
||||
backgroundTintList = ColorStateList.valueOf( resources.getColor( if(enabled) R.color.colorPrimary else R.color.zcashWhite_24) )
|
||||
}
|
||||
}
|
||||
|
||||
fun setProgress(progress: Int) {
|
||||
progress.let {
|
||||
if (it < 100) {
|
||||
setBanner("Downloading . . . $it%", NONE)
|
||||
} else {
|
||||
setBanner("Scanning . . .", NONE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setSendAmount(amount: String) {
|
||||
binding.textSendAmount.text = "\$$amount"
|
||||
mainActivity?.sendViewModel?.zatoshiAmount = amount.safelyConvertToBigDecimal().convertZecToZatoshi()
|
||||
binding.buttonSend.disabledIf(amount == "0")
|
||||
}
|
||||
|
||||
fun setAvailable(availableBalance: Long = -1L, totalBalance: Long = -1L) {
|
||||
val availableString = if (availableBalance < 0) "Updating" else availableBalance.convertZatoshiToZecString()
|
||||
binding.textBalanceAvailable.text = availableString
|
||||
binding.textBalanceDescription.apply {
|
||||
goneIf(availableBalance < 0)
|
||||
text = if (availableBalance != -1L && (availableBalance < totalBalance)) {
|
||||
"(expecting +${(totalBalance - availableBalance).convertZatoshiToZecString()} ZEC in change)"
|
||||
} else {
|
||||
"(enter an amount to send)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setSendText(buttonText: String = "Send Amount") {
|
||||
binding.buttonSend.text = buttonText
|
||||
}
|
||||
|
||||
fun setBanner(message: String = "", action: BannerAction = CLEAR) {
|
||||
with(binding) {
|
||||
val hasMessage = !message.isEmpty() || action != CLEAR
|
||||
groupBalance.goneIf(hasMessage)
|
||||
groupBanner.goneIf(!hasMessage)
|
||||
layerLock.goneIf(!hasMessage)
|
||||
|
||||
textBannerMessage.text = message
|
||||
textBannerAction.text = action.action
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Private UI Events
|
||||
//
|
||||
|
||||
private fun onModelUpdated(old: HomeViewModel.UiModel, new: HomeViewModel.UiModel) {
|
||||
twig(new.toString())
|
||||
uiModel = new
|
||||
if (old.pendingSend != new.pendingSend) {
|
||||
setSendAmount(new.pendingSend)
|
||||
}
|
||||
// TODO: handle stopped and disconnected flows
|
||||
if (new.status == SYNCING) onSyncing(new) else onSynced(new)
|
||||
setSendEnabled(new.isSendEnabled)
|
||||
}
|
||||
|
||||
private fun onSyncing(uiModel: HomeViewModel.UiModel) {
|
||||
setProgress(uiModel.progress) // calls setBanner
|
||||
setAvailable()
|
||||
setSendText("Syncing Blockchain…")
|
||||
}
|
||||
|
||||
private fun onSynced(uiModel: HomeViewModel.UiModel) {
|
||||
if (!uiModel.hasFunds) {
|
||||
onNoFunds()
|
||||
} else {
|
||||
setBanner("")
|
||||
setAvailable(uiModel.availableBalance, uiModel.totalBalance)
|
||||
setSendText()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSend() {
|
||||
mainActivity?.navController?.navigate(R.id.action_nav_home_to_send)
|
||||
}
|
||||
|
||||
private fun onBannerAction(action: BannerAction) {
|
||||
when (action) {
|
||||
LEARN_MORE -> {
|
||||
FUND_NOW -> {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setMessage("To make full use of this wallet, deposit funds to your address or tap the faucet to trigger a tiny automatic deposit.\n\nFaucet funds are made available for the community by the community for testing. So please be kind enough to return what you borrow!")
|
||||
.setTitle("No Balance")
|
||||
|
@ -106,25 +272,19 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||
}
|
||||
|
||||
private fun onNoFunds() {
|
||||
setBanner("No Balance", LEARN_MORE)
|
||||
setBanner("No Balance", FUND_NOW)
|
||||
}
|
||||
|
||||
private fun setBanner(message: String = "", action: BannerAction = CLEAR) {
|
||||
with(binding) {
|
||||
val hasMessage = !message.isEmpty() || action != CLEAR
|
||||
groupBalance.goneIf(hasMessage)
|
||||
groupBanner.goneIf(!hasMessage)
|
||||
layerLock.goneIf(!hasMessage)
|
||||
|
||||
textBannerMessage.text = message
|
||||
textBannerAction.text = action.action
|
||||
}
|
||||
}
|
||||
//
|
||||
// Inner classes and extensions
|
||||
//
|
||||
|
||||
enum class BannerAction(val action: String) {
|
||||
LEARN_MORE("Learn More"),
|
||||
FUND_NOW("Fund Now"),
|
||||
CANCEL("Cancel"),
|
||||
CLEAR("");
|
||||
NONE(""),
|
||||
CLEAR("clear");
|
||||
|
||||
companion object {
|
||||
fun from(action: String?): BannerAction {
|
||||
|
@ -135,6 +295,54 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TextView.asKey(): TextView {
|
||||
val c = text[0]
|
||||
setOnClickListener {
|
||||
lifecycleScope.launch {
|
||||
twig("CHAR TYPED: $c")
|
||||
_typedChars.send(c)
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: remove these troubleshooting logs
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
twig("HomeFragment.onCreate")
|
||||
}
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
twig("HomeFragment.onActivityCreated")
|
||||
}
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
twig("HomeFragment.onStart")
|
||||
}
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
twig("HomeFragment.onPause resumeScope.isActive: ${resumedScope.isActive}")
|
||||
}
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
twig("HomeFragment.onStop")
|
||||
}
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
twig("HomeFragment.onDestroyView")
|
||||
}
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
twig("HomeFragment.onDestroy")
|
||||
}
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
twig("HomeFragment.onDetach")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package cash.z.ecc.android.ui.home
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.ViewModel
|
||||
import cash.z.wallet.sdk.Synchronizer
|
||||
import cash.z.wallet.sdk.Synchronizer.Status.DISCONNECTED
|
||||
import cash.z.wallet.sdk.Synchronizer.Status.SYNCED
|
||||
import cash.z.wallet.sdk.ext.ZcashSdk
|
||||
import cash.z.wallet.sdk.ext.ZcashSdk.MINERS_FEE_ZATOSHI
|
||||
import cash.z.wallet.sdk.ext.ZcashSdk.ZATOSHI_PER_ZEC
|
||||
import cash.z.wallet.sdk.ext.twig
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.coroutines.flow.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class HomeViewModel @Inject constructor() : ViewModel() {
|
||||
|
||||
lateinit var uiModels: Flow<UiModel>
|
||||
|
||||
fun initialize(
|
||||
synchronizer: Synchronizer,
|
||||
typedChars: Flow<Char>
|
||||
) {
|
||||
twig("init called")
|
||||
val zec = typedChars.scan("0") { acc, c ->
|
||||
when {
|
||||
// no-op cases
|
||||
acc == "0" && c == '0'
|
||||
|| (c == '<' && acc == "0")
|
||||
|| (c == '.' && acc.contains('.')) -> {twig("triggered: 1 acc: $acc c: $c $typedChars ")
|
||||
acc
|
||||
}
|
||||
c == '<' && acc.length <= 1 -> {twig("triggered: 2 $typedChars")
|
||||
"0"
|
||||
}
|
||||
c == '<' -> {twig("triggered: 3")
|
||||
acc.substring(0, acc.length - 1)
|
||||
}
|
||||
acc == "0" && c != '.' -> {twig("triggered: 4 $typedChars")
|
||||
c.toString()
|
||||
}
|
||||
else -> {twig("triggered: 5 $typedChars")
|
||||
"$acc$c"
|
||||
}
|
||||
}
|
||||
}
|
||||
uiModels = synchronizer.run {
|
||||
combine(status, progress, balances, zec) { s, p, b, z->
|
||||
UiModel(s, p, b.available, b.total, z)
|
||||
}
|
||||
}.conflate()
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
twig("HomeViewModel cleared!")
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class UiModel( // <- THIS ERROR IS AN IDE BUG WITH PARCELIZE
|
||||
val status: Synchronizer.Status = DISCONNECTED,
|
||||
val progress: Int = 0,
|
||||
val availableBalance: Long = -1L,
|
||||
val totalBalance: Long = -1L,
|
||||
val pendingSend: String = "0"
|
||||
): Parcelable {
|
||||
// Note: the wallet is effectively empty if it cannot cover the miner's fee
|
||||
val hasFunds: Boolean get() = availableBalance > (MINERS_FEE_ZATOSHI.toDouble() / ZATOSHI_PER_ZEC) // 0.0001
|
||||
val isSynced: Boolean get() = status == SYNCED
|
||||
val isSendEnabled: Boolean get() = isSynced && hasFunds
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="@drawable/background_home">
|
||||
|
||||
<View
|
||||
|
@ -27,14 +28,28 @@
|
|||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.04" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline_send_amount_top"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.13" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guideline_send_amount_bottom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.23" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_balance_available"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="12.34581242 ZEC"
|
||||
android:text="Updating"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="@color/text_light"
|
||||
android:visibility="gone"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintEnd_toStartOf="@id/label_balance"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@ -53,6 +68,17 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/text_balance_available" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_balance_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="(enter an amount to send)"
|
||||
android:visibility="gone"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_balance_available" />
|
||||
|
||||
|
||||
<!-- -->
|
||||
<!-- Number Pad -->
|
||||
|
@ -213,20 +239,23 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/button_number_pad_9"
|
||||
app:layout_constraintWidth_percent="@dimen/calculator_button_width_percent" />
|
||||
|
||||
<!-- TODO: properly style this as a button with ripples -->
|
||||
<TextView
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_send"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="46dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:background="@drawable/background_button_rounded"
|
||||
android:gravity="center"
|
||||
style="@style/Zcash.Button"
|
||||
android:text="Send Amount"
|
||||
android:enabled="false"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="#000000"
|
||||
android:gravity="center"
|
||||
android:padding="12dp"
|
||||
app:layout_constraintEnd_toEndOf="@id/guide_keys"
|
||||
app:layout_constraintStart_toStartOf="@id/guide_keys"
|
||||
app:layout_constraintTop_toBottomOf="@id/guide_keys" />
|
||||
app:layout_constraintTop_toBottomOf="@id/guide_keys"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/layer_lock"
|
||||
|
@ -234,6 +263,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:background="#D0000000"
|
||||
tools:visibility="gone"
|
||||
android:elevation="5dp" />
|
||||
|
||||
<!-- -->
|
||||
|
@ -322,36 +352,25 @@
|
|||
app:layout_constraintTop_toBottomOf="@id/button_send"
|
||||
app:layout_constraintVertical_bias="@dimen/ratio_golden_small" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_zec_symbol"
|
||||
android:elevation="6dp"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:tint="@color/colorAccent"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="@id/text_send_amount"
|
||||
app:layout_constraintEnd_toStartOf="@id/text_send_amount"
|
||||
app:layout_constraintHeight_percent="0.052"
|
||||
app:layout_constraintTop_toTopOf="@id/text_send_amount"
|
||||
app:layout_constraintVertical_bias="0.2"
|
||||
app:layout_constraintWidth_percent="0.060"
|
||||
app:srcCompat="@drawable/ic_zec_symbol" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_send_amount"
|
||||
android:elevation="6dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:text="$0"
|
||||
android:textAppearance="@style/Zcash.TextAppearance.Zec"
|
||||
android:textSize="72dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/guide_keys"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
|
||||
app:autoSizeTextType="uniform"
|
||||
app:layout_constraintBottom_toTopOf="@id/guideline_send_amount_bottom"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
app:layout_constraintTop_toTopOf="@id/guideline_send_amount_top" />
|
||||
|
||||
<!-- -->
|
||||
<!-- Banner -->
|
||||
|
@ -379,7 +398,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="Learn More"
|
||||
android:text="Fund Now"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="@color/colorPrimary"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/text_banner_message"
|
||||
|
@ -395,6 +414,7 @@
|
|||
android:id="@+id/group_banner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:constraint_referenced_ids="text_banner_message, text_banner_action" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
<color name="zcashWhite">#F5F5F5</color>
|
||||
<color name="zcashWhite_12">#1FFFFFFF</color>
|
||||
<color name="zcashWhite_24">#3DFFFFFF</color>
|
||||
<color name="zcashWhite_40">#66FFFFFF</color>
|
||||
<color name="zcashWhite_50">#80FFFFFF</color>
|
||||
<color name="zcashWhite_60">#A3FFFFFF</color>
|
||||
|
|
Loading…
Reference in New Issue