Home screen improvements and bug fixes.
- Implemented long press to clear amount - fixed bugs around No Funds being shown when available was zero but change was pending confirmation - colored the gray z-icon on the home screen - added color emphasis when change is pending - added profile button
This commit is contained in:
parent
4c8adf5180
commit
d5c8d17c3d
|
@ -0,0 +1,13 @@
|
|||
package cash.z.ecc.android.ext
|
||||
|
||||
import android.text.Spannable
|
||||
import android.text.Spanned
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import androidx.core.text.toSpannable
|
||||
|
||||
fun String.toColoredSpan(colorResId: Int, coloredPortion: String): Spannable {
|
||||
return toSpannable().apply {
|
||||
val start = this@toColoredSpan.indexOf(coloredPortion)
|
||||
setSpan(ForegroundColorSpan(colorResId.toAppColor()), start, start + coloredPortion.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
|
@ -3,17 +3,19 @@ package cash.z.ecc.android.ui.home
|
|||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
import android.text.Spanned
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import cash.z.ecc.android.R
|
||||
import cash.z.ecc.android.databinding.FragmentHomeBinding
|
||||
import cash.z.ecc.android.di.viewmodel.activityViewModel
|
||||
import cash.z.ecc.android.di.viewmodel.viewModel
|
||||
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.ext.*
|
||||
import cash.z.ecc.android.ext.toAppColor
|
||||
import cash.z.ecc.android.ui.base.BaseFragment
|
||||
import cash.z.ecc.android.ui.home.HomeFragment.BannerAction.*
|
||||
import cash.z.ecc.android.ui.send.SendViewModel
|
||||
|
@ -87,7 +89,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||
buttonNumberPadDecimal.asKey(),
|
||||
buttonNumberPadBack.asKey()
|
||||
)
|
||||
hitAreaReceive.onClickNavTo(R.id.action_nav_home_to_nav_receive)
|
||||
hitAreaReceive.onClickNavTo(R.id.action_nav_home_to_nav_profile)
|
||||
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_scan)
|
||||
|
@ -98,17 +100,33 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||
buttonSend.setOnClickListener {
|
||||
onSend()
|
||||
}
|
||||
setSendAmount("0")
|
||||
}
|
||||
|
||||
binding.buttonNumberPadBack.setOnLongClickListener {
|
||||
onClearAmount()
|
||||
true
|
||||
}
|
||||
|
||||
// if (::uiModel.isInitialized) {
|
||||
// twig("uiModel exists!")
|
||||
// onModelUpdated(HomeViewModel.UiModel(), uiModel)
|
||||
// }
|
||||
}
|
||||
|
||||
private fun onClearAmount() {
|
||||
repeat(binding.textSendAmount.text.length) {
|
||||
resumedScope.launch {
|
||||
_typedChars.send('<')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
viewModel.initialize(typedChars)
|
||||
twig("HomeFragment.onResume resumeScope.isActive: ${resumedScope.isActive} $resumedScope")
|
||||
onClearAmount()
|
||||
viewModel.uiModels.scanReduce { old, new ->
|
||||
onModelUpdated(old, new)
|
||||
new
|
||||
|
@ -163,8 +181,11 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param amount the amount to send represented as ZEC, without the dollar sign.
|
||||
*/
|
||||
fun setSendAmount(amount: String) {
|
||||
binding.textSendAmount.text = "\$$amount"
|
||||
binding.textSendAmount.text = "\$$amount".toColoredSpan(R.color.text_light_dimmed, "$")
|
||||
sendViewModel.zatoshiAmount = amount.safelyConvertToBigDecimal().convertZecToZatoshi()
|
||||
binding.buttonSend.disabledIf(amount == "0")
|
||||
}
|
||||
|
@ -175,7 +196,8 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||
binding.textBalanceDescription.apply {
|
||||
goneIf(availableBalance < 0)
|
||||
text = if (availableBalance != -1L && (availableBalance < totalBalance)) {
|
||||
"(expecting +${(totalBalance - availableBalance).convertZatoshiToZecString()} ZEC in change)"
|
||||
val change = (totalBalance - availableBalance).convertZatoshiToZecString()
|
||||
"(expecting +$change ZEC in change)".toColoredSpan(R.color.text_light, "+$change")
|
||||
} else {
|
||||
"(enter an amount to send)"
|
||||
}
|
||||
|
@ -221,7 +243,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>() {
|
|||
}
|
||||
|
||||
private fun onSynced(uiModel: HomeViewModel.UiModel) {
|
||||
if (!uiModel.hasFunds) {
|
||||
if (!uiModel.hasBalance) {
|
||||
onNoFunds()
|
||||
} else {
|
||||
setBanner("")
|
||||
|
|
|
@ -57,7 +57,7 @@ class HomeViewModel @Inject constructor() : ViewModel() {
|
|||
}
|
||||
uiModels = synchronizer.run {
|
||||
combine(status, progress, balances, zec) { s, p, b, z->
|
||||
UiModel(s, p, b.available, b.total, z)
|
||||
UiModel(s, p, b.availableZatoshi, b.totalZatoshi, z)
|
||||
}
|
||||
}.conflate()
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ class HomeViewModel @Inject constructor() : ViewModel() {
|
|||
): 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 hasBalance: Boolean get() = totalBalance > (MINERS_FEE_ZATOSHI.toDouble() / ZATOSHI_PER_ZEC) // 0.0001
|
||||
val isSynced: Boolean get() = status == SYNCED
|
||||
val isSendEnabled: Boolean get() = isSynced && hasFunds
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.content.Context
|
|||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import cash.z.android.qrecycler.QRecycler
|
||||
import cash.z.ecc.android.R
|
||||
import cash.z.ecc.android.databinding.FragmentReceiveNewBinding
|
||||
|
@ -12,7 +11,7 @@ import cash.z.ecc.android.di.viewmodel.viewModel
|
|||
import cash.z.ecc.android.ext.onClickNavBack
|
||||
import cash.z.ecc.android.ext.onClickNavTo
|
||||
import cash.z.ecc.android.ui.base.BaseFragment
|
||||
import cash.z.wallet.sdk.ext.abbreviatedAddress
|
||||
import cash.z.wallet.sdk.ext.toAbbreviatedAddress
|
||||
import cash.z.wallet.sdk.ext.twig
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.roundToInt
|
||||
|
@ -63,7 +62,7 @@ class ReceiveFragment : BaseFragment<FragmentReceiveNewBinding>() {
|
|||
.withCorrectionLevel(QRecycler.CorrectionLevel.MEDIUM)
|
||||
.into(binding.receiveQrCode)
|
||||
|
||||
binding.receiveAddress.text = address.abbreviatedAddress(12, 12)
|
||||
binding.receiveAddress.text = address.toAbbreviatedAddress(12, 12)
|
||||
|
||||
// address.distribute(8) { i, part ->
|
||||
// setAddressPart(i, part)
|
||||
|
|
|
@ -47,6 +47,9 @@ class SendViewModel @Inject constructor() : ViewModel() {
|
|||
zatoshiAmount < ZcashSdk.MINERS_FEE_ZATOSHI -> {
|
||||
emit("Please enter a larger amount")
|
||||
}
|
||||
synchronizer.getAddress() == toAddress -> {
|
||||
emit("That appears to be your address!")
|
||||
}
|
||||
else -> emit(null)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import kotlinx.coroutines.withContext
|
|||
class BackupFragment : BaseFragment<FragmentBackupBinding>() {
|
||||
val walletSetup: WalletSetupViewModel by activityViewModel(false)
|
||||
|
||||
private var hasBackUp: Boolean? = null
|
||||
private var hasBackUp: Boolean = true //TODO: implement backup and then check for it here-ish
|
||||
|
||||
override fun inflate(inflater: LayoutInflater): FragmentBackupBinding =
|
||||
FragmentBackupBinding.inflate(inflater)
|
||||
|
@ -80,7 +80,7 @@ class BackupFragment : BaseFragment<FragmentBackupBinding>() {
|
|||
if (showMessage) {
|
||||
Toast.makeText(activity, "Backup verification coming soon!", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
mainActivity?.navController?.popBackStack(R.id.wallet_setup_navigation, true)
|
||||
mainActivity?.navController?.popBackStack()
|
||||
}
|
||||
|
||||
private fun applySpan(vararg textViews: TextView) = lifecycleScope.launch {
|
||||
|
|
|
@ -74,7 +74,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="(enter an amount to send)"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="@color/text_light_dimmed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_balance_available" />
|
||||
|
@ -291,14 +293,14 @@
|
|||
android:layout_height="0dp"
|
||||
android:elevation="6dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="H,1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHeight_percent="0.03825136612"
|
||||
app:layout_constraintHorizontal_bias="0.8883"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.8883"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.06420765027"
|
||||
app:layout_constraintWidth_percent="0.05582524272"
|
||||
app:srcCompat="@drawable/ic_receive_funds" />
|
||||
app:layout_constraintVertical_bias="0.064"
|
||||
app:layout_constraintWidth_percent="0.08"
|
||||
app:srcCompat="@drawable/ic_account_circle" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_detail"
|
||||
|
@ -359,7 +361,7 @@
|
|||
android:layout_height="0dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:text="$0"
|
||||
tools:text="$0"
|
||||
android:textAppearance="@style/Zcash.TextAppearance.Zec"
|
||||
android:textSize="72dp"
|
||||
android:maxLines="1"
|
||||
|
|
|
@ -88,7 +88,6 @@
|
|||
android:id="@+id/icon_qr_logo"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:onClick="copyAddress"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_zcash_primary"
|
||||
|
@ -135,6 +134,27 @@
|
|||
app:layout_constraintStart_toEndOf="@id/receive_address"
|
||||
app:layout_constraintTop_toTopOf="@id/receive_address" />
|
||||
|
||||
<Space
|
||||
android:id="@+id/space_address_median"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="1dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/receive_address"
|
||||
app:layout_constraintBottom_toTopOf="@id/button_scan"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintVertical_bias="0.4"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/hit_area_address"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:onClick="copyAddress"
|
||||
app:layout_constraintStart_toStartOf="@id/receive_address"
|
||||
app:layout_constraintEnd_toEndOf="@id/background_qr"
|
||||
app:layout_constraintTop_toTopOf="@id/receive_title"
|
||||
app:layout_constraintBottom_toTopOf="@id/space_address_median"
|
||||
tools:background="@color/spacer" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_scan"
|
||||
android:layout_width="0dp"
|
||||
|
|
Loading…
Reference in New Issue