incorporate new sdk changes and refactor the way transactions and polling work
This commit is contained in:
parent
c3e59f4ed9
commit
9bee43be37
Binary file not shown.
|
@ -14,7 +14,6 @@ import cash.z.android.wallet.sample.Servers
|
|||
import cash.z.android.wallet.sample.WalletConfig
|
||||
import cash.z.android.wallet.ui.util.Broom
|
||||
import cash.z.wallet.sdk.block.*
|
||||
import cash.z.wallet.sdk.dao.ClearedTransaction
|
||||
import cash.z.wallet.sdk.data.*
|
||||
import cash.z.wallet.sdk.ext.DEFAULT_BATCH_SIZE
|
||||
import cash.z.wallet.sdk.ext.DEFAULT_RETRIES
|
||||
|
@ -44,7 +43,6 @@ internal object SynchronizerModule {
|
|||
private val pollingTransactionRepository = PollingTransactionRepository(
|
||||
ZcashWalletApplication.instance,
|
||||
walletConfig.dataDbName,
|
||||
rustBackend,
|
||||
DEFAULT_TRANSACTION_POLL_FREQUENCY_MILLIS
|
||||
)
|
||||
|
||||
|
@ -168,25 +166,6 @@ internal object SynchronizerModule {
|
|||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideManager(wallet: Wallet, repository: TransactionRepository, service: LightWalletService): ActiveTransactionManager {
|
||||
return ActiveTransactionManager(repository, service, wallet)
|
||||
}
|
||||
//
|
||||
// @JvmStatic
|
||||
// @Provides
|
||||
// @Singleton
|
||||
// fun provideSynchronizer(
|
||||
// processor: CompactBlockProcessor,
|
||||
// repository: TransactionRepository,
|
||||
// manager: ActiveTransactionManager,
|
||||
// wallet: Wallet
|
||||
// ): Synchronizer {
|
||||
// return SdkSynchronizer(processor, repository, manager, wallet, DEFAULT_STALE_TOLERANCE)
|
||||
// }
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
|
@ -204,14 +183,6 @@ internal object SynchronizerModule {
|
|||
)
|
||||
}
|
||||
|
||||
// @JvmStatic
|
||||
// @Provides
|
||||
// @Singleton
|
||||
// fun provideChipBucket(): ChipBucket {
|
||||
// return InMemoryChipBucket()
|
||||
// }
|
||||
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
|
@ -233,20 +204,20 @@ internal object SynchronizerModule {
|
|||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTransactionEncoder(wallet: Wallet, repository: TransactionRepository): RawTransactionEncoder {
|
||||
fun provideTransactionEncoder(wallet: Wallet, repository: TransactionRepository): TransactionEncoder {
|
||||
return WalletTransactionEncoder(wallet, repository)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDataSynchronizer(
|
||||
fun provideSynchronizer(
|
||||
wallet: Wallet,
|
||||
ledger: PollingTransactionRepository,
|
||||
sender: TransactionSender,
|
||||
processor: CompactBlockProcessor,
|
||||
encoder: RawTransactionEncoder
|
||||
): DataSynchronizer {
|
||||
encoder: TransactionEncoder
|
||||
): Synchronizer {
|
||||
return StableSynchronizer(wallet, ledger, sender, processor, encoder)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import cash.z.android.wallet.PokerChipSeedProvider
|
|||
import cash.z.android.wallet.ZcashWalletApplication
|
||||
import cash.z.android.wallet.extention.Toaster
|
||||
import cash.z.android.wallet.extention.tryIgnore
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import cash.z.wallet.sdk.data.StableSynchronizer
|
||||
import cash.z.wallet.sdk.ext.MINERS_FEE_ZATOSHI
|
||||
import cash.z.wallet.sdk.ext.convertZecToZatoshi
|
||||
|
@ -27,7 +27,7 @@ import kotlin.properties.ReadOnlyProperty
|
|||
class SendReceiver : DaggerBroadcastReceiver() {
|
||||
|
||||
@Inject
|
||||
lateinit var synchronizer: DataSynchronizer
|
||||
lateinit var synchronizer: Synchronizer
|
||||
|
||||
@Inject
|
||||
lateinit var rustBackend: RustBackendWelding
|
||||
|
|
|
@ -9,7 +9,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||
|
||||
// TODO: reverse this hierarchy so that Polling depends on this class and has all the overhead specific to polling, leaving this class more streamlined and efficient
|
||||
class StaticTransactionRepository(dataDbName: String, rustBackend: RustBackendWelding, dbCallback: (DerivedDataDb) -> Unit = {}) :
|
||||
PollingTransactionRepository(ZcashWalletApplication.instance, dataDbName, rustBackend,2000L, dbCallback) {
|
||||
PollingTransactionRepository(ZcashWalletApplication.instance, dataDbName,2000L) {
|
||||
|
||||
// override fun start(parentScope: CoroutineScope) {
|
||||
// twig("starting repository ignored because this DB does not poll")
|
||||
|
|
|
@ -40,11 +40,11 @@ import cash.z.android.wallet.ui.util.Analytics.trackAction
|
|||
import cash.z.android.wallet.ui.util.Analytics.trackCrash
|
||||
import cash.z.android.wallet.ui.util.Analytics.trackFunnelStep
|
||||
import cash.z.android.wallet.ui.util.Broom
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import cash.z.wallet.sdk.data.StableSynchronizer
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.db.isMined
|
||||
import cash.z.wallet.sdk.db.isSubmitted
|
||||
import cash.z.wallet.sdk.entity.isMined
|
||||
import cash.z.wallet.sdk.entity.isSubmitted
|
||||
import cash.z.wallet.sdk.ext.MINERS_FEE_ZATOSHI
|
||||
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
|
||||
import cash.z.wallet.sdk.secure.Wallet
|
||||
|
@ -59,7 +59,7 @@ class MainActivity : BaseActivity(), Animator.AnimatorListener, ScanFragment.Bar
|
|||
|
||||
|
||||
@Inject
|
||||
lateinit var synchronizer: DataSynchronizer
|
||||
lateinit var synchronizer: Synchronizer
|
||||
|
||||
@Inject
|
||||
lateinit var mainPresenter: MainPresenter
|
||||
|
@ -101,7 +101,9 @@ class MainActivity : BaseActivity(), Animator.AnimatorListener, ScanFragment.Bar
|
|||
super.onResume()
|
||||
// chipBucket.restore()
|
||||
launch {
|
||||
synchronizer.onCriticalErrorListener = ::onCriticalError
|
||||
synchronizer.onCriticalErrorHandler = ::onCriticalError
|
||||
synchronizer.onProcessorErrorHandler = ::onProcessorError
|
||||
synchronizer.onSubmissionErrorHandler = ::onCriticalError
|
||||
synchronizer.start(this)
|
||||
balancePresenter.start(this, synchronizer.balances())
|
||||
mainPresenter.start()
|
||||
|
@ -125,14 +127,14 @@ class MainActivity : BaseActivity(), Animator.AnimatorListener, ScanFragment.Bar
|
|||
}
|
||||
}
|
||||
|
||||
private fun onCriticalError(error: Throwable): Boolean {
|
||||
private fun onCriticalError(error: Throwable?): Boolean {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
//TODO proper error parsing, with strongly typed exceptions
|
||||
var title: String? = null
|
||||
var message: String? = null
|
||||
|
||||
when {
|
||||
(error.message?.contains("UNAVAILABLE") == true) -> {
|
||||
(error?.message?.contains("UNAVAILABLE") == true) -> {
|
||||
title = "Server Error!"
|
||||
message = "Unable to reach the server. Either it is down or you are not connected to the internet."
|
||||
}
|
||||
|
@ -150,6 +152,12 @@ class MainActivity : BaseActivity(), Animator.AnimatorListener, ScanFragment.Bar
|
|||
return true
|
||||
}
|
||||
|
||||
private fun onProcessorError(error: Throwable?): Boolean {
|
||||
twig("Error while processing blocks: $error")
|
||||
twig("The processor will keep trying and then throw a critical error after a while so this can be ignored for now.")
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
balancePresenter.stop()
|
||||
|
@ -410,7 +418,7 @@ class MainActivity : BaseActivity(), Animator.AnimatorListener, ScanFragment.Bar
|
|||
|
||||
// For now, empty happens when back is pressed
|
||||
if (value.isEmpty()) return
|
||||
synchronizer.getPending()?.firstOrNull { it.memo.contains("#${value.hashCode()}") }?.let { existingTransaction ->
|
||||
synchronizer.lastPending().firstOrNull { it.memo?.contains("#${value.hashCode()}") == true }?.let { existingTransaction ->
|
||||
if (existingTransaction.isMined()) {
|
||||
alert(title = "Successfully Redeemed!", message = "We scanned this one already and the funds went to this wallet!")
|
||||
} else {
|
||||
|
@ -534,7 +542,7 @@ class MainActivity : BaseActivity(), Animator.AnimatorListener, ScanFragment.Bar
|
|||
|
||||
fun buyProduct(product: Zcon1Store.CartItem) {
|
||||
trackFunnelStep(PurchasedItem(product))
|
||||
val balance = (synchronizer as StableSynchronizer).getBalance()
|
||||
val balance = (synchronizer as StableSynchronizer).lastBalance()
|
||||
if (balance.available < (product.zatoshiValue + MINERS_FEE_ZATOSHI)) {
|
||||
val message = if (balance.total >= (product.zatoshiValue + MINERS_FEE_ZATOSHI)) {
|
||||
"Sorry, some of your funds are still awaiting 10 network confirmations before they are available for spending! Try again after your \"amount syncing\" is zero."
|
||||
|
@ -606,8 +614,8 @@ class MainActivity : BaseActivity(), Animator.AnimatorListener, ScanFragment.Bar
|
|||
}
|
||||
|
||||
fun calculatePendingChipBalance(): Long {
|
||||
return synchronizer.getPending()?.filter {
|
||||
it.memo.toLowerCase().contains("poker chip") && !it.isMined()
|
||||
return synchronizer.lastPending()?.filter {
|
||||
it.memo?.toLowerCase()?.contains("poker chip") == true && !it.isMined()
|
||||
}?.fold(0L) { acc, item ->
|
||||
acc + item.value
|
||||
} ?: 0L
|
||||
|
|
|
@ -12,8 +12,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import cash.z.android.wallet.R
|
||||
import cash.z.android.wallet.extention.toAppColor
|
||||
import cash.z.android.wallet.extention.toRelativeTimeString
|
||||
import cash.z.android.wallet.extention.truncate
|
||||
import cash.z.wallet.sdk.dao.ClearedTransaction
|
||||
import cash.z.wallet.sdk.entity.SentTransaction
|
||||
import cash.z.wallet.sdk.ext.MINERS_FEE_ZATOSHI
|
||||
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
|
||||
import java.text.SimpleDateFormat
|
||||
|
@ -21,7 +20,7 @@ import java.util.*
|
|||
import kotlin.math.absoluteValue
|
||||
|
||||
|
||||
class TransactionAdapter(@LayoutRes val itemResId: Int = R.layout.item_transaction) : ListAdapter<ClearedTransaction, TransactionViewHolder>(DIFF_CALLBACK) {
|
||||
class TransactionAdapter(@LayoutRes val itemResId: Int = R.layout.item_transaction) : ListAdapter<TransactionUiModel, TransactionViewHolder>(DIFF_CALLBACK) {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionViewHolder {
|
||||
val itemView = LayoutInflater.from(parent.context).inflate(itemResId, parent, false)
|
||||
return TransactionViewHolder(itemView)
|
||||
|
@ -29,9 +28,9 @@ class TransactionAdapter(@LayoutRes val itemResId: Int = R.layout.item_transacti
|
|||
override fun onBindViewHolder(holder: TransactionViewHolder, position: Int) = holder.bind(getItem(position))
|
||||
}
|
||||
|
||||
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ClearedTransaction>() {
|
||||
override fun areItemsTheSame(oldItem: ClearedTransaction, newItem: ClearedTransaction) = oldItem.height == newItem.height
|
||||
override fun areContentsTheSame(oldItem: ClearedTransaction, newItem: ClearedTransaction) = oldItem == newItem
|
||||
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<TransactionUiModel>() {
|
||||
override fun areItemsTheSame(oldItem: TransactionUiModel, newItem: TransactionUiModel) = oldItem.minedHeight == newItem.minedHeight
|
||||
override fun areContentsTheSame(oldItem: TransactionUiModel, newItem: TransactionUiModel): Boolean = oldItem == newItem
|
||||
}
|
||||
|
||||
class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
@ -43,47 +42,41 @@ class TransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
|||
private val memo = itemView.findViewById<TextView>(R.id.text_transaction_memo)
|
||||
private val formatter = SimpleDateFormat("M/d h:mma", Locale.getDefault())
|
||||
|
||||
fun bind(tx: ClearedTransaction) {
|
||||
val isChip = tx.isPokerChip()
|
||||
val isSwag = tx.isSend && (tx.memo ?: "").toLowerCase().contains("swag")
|
||||
val useSend = tx.isSend && !isChip
|
||||
fun bind(tx: TransactionUiModel) {
|
||||
val useSend = (tx.isSend) && !tx.isPokerChip
|
||||
val isHistory = icon != null
|
||||
val sign = if (useSend) "- " else "+ "
|
||||
val amountColor = if (useSend) R.color.colorAccent else R.color.zcashPurple_accent
|
||||
val defaultColor = R.color.text_light_dimmed
|
||||
val actionColor = if (tx.action == null) amountColor else defaultColor
|
||||
val transactionColor = if (useSend) R.color.send_associated else R.color.receive_associated
|
||||
val transactionIcon = if (useSend || (isChip && tx.address != "Redeemed")) R.drawable.ic_sent_transaction else R.drawable.ic_received_transaction
|
||||
val zecAbsoluteValue = tx.value.absoluteValue + if(tx.isSend) MINERS_FEE_ZATOSHI else 0
|
||||
val toOrFrom = if (useSend) "to" else "from"
|
||||
val srcOrDestination = tx.address?.truncate() ?: "shielded address"
|
||||
val transactionIcon = if (useSend || (tx.isPokerChip && (tx as? SentTransaction)?.toAddress != "Redeemed")) R.drawable.ic_sent_transaction else R.drawable.ic_received_transaction
|
||||
val zecAbsoluteValue = tx.zatoshiValue.absoluteValue + if(tx.isSend) MINERS_FEE_ZATOSHI else 0
|
||||
|
||||
fun createActionText(): Pair<String, Int> {
|
||||
return when {
|
||||
tx.isSend && isChip -> "Scan" to R.color.text_light_dimmed
|
||||
tx.isMined && !(tx.isSend && tx.noteId <= 0) -> "$sign${zecAbsoluteValue.convertZatoshiToZecString(2)}" to amountColor
|
||||
isSwag -> "Purchase" to R.color.text_light_dimmed
|
||||
else -> (if (tx.isSend) "Transfer" else "Pending") to R.color.text_light_dimmed
|
||||
}
|
||||
}
|
||||
|
||||
val actionText = createActionText()
|
||||
timestamp.text = if (tx.timeInSeconds == 0L) "Pending"
|
||||
else (if (isHistory) formatter.format(tx.timeInSeconds * 1000) else (tx.timeInSeconds * 1000L).toRelativeTimeString())
|
||||
amount.text = actionText.first
|
||||
amount.setTextColor(actionText.second.toAppColor())
|
||||
timestamp.text = if (tx.timestampMillis == 0L) "Pending"
|
||||
else (if (isHistory) formatter.format(tx.timestampMillis) else (tx.timestampMillis).toRelativeTimeString())
|
||||
amount.text = tx.action ?: "$sign${zecAbsoluteValue.convertZatoshiToZecString(2)}"
|
||||
amount.setTextColor(actionColor.toAppColor())
|
||||
|
||||
// maybes - and if this gets to be too much, then pass in a custom holder when constructing the adapter, instead
|
||||
status?.setBackgroundColor(transactionColor.toAppColor())
|
||||
address?.text = if (tx.isSend) {
|
||||
if (tx.isMined) {
|
||||
if (isSwag && tx.isMined && tx.status == null) "Purchase accepted."
|
||||
else "Transfer complete."
|
||||
} else tx.status
|
||||
} else "$toOrFrom $srcOrDestination"
|
||||
memo?.text = tx.memo
|
||||
address?.text = tx.status
|
||||
memo?.text = tx?.memo ?: ""
|
||||
icon?.setImageResource(transactionIcon)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClearedTransaction.isPokerChip(): Boolean {
|
||||
return memo?.contains("Poker Chip") == true
|
||||
}
|
||||
data class TransactionUiModel(
|
||||
val action: String? = null,
|
||||
val status: String? = null,
|
||||
val isSend: Boolean = false,
|
||||
val isPending: Boolean = false,
|
||||
val isPokerChip: Boolean = false,
|
||||
val isSwag: Boolean = false,
|
||||
val timestampMillis: Long = 0L,
|
||||
val zatoshiValue: Long = 0L,
|
||||
val minedHeight: Int = 0,
|
||||
val memo: String? = null
|
||||
)
|
||||
|
||||
val TransactionUiModel.isMined get() = this.minedHeight > 0
|
|
@ -11,10 +11,11 @@ import cash.z.android.wallet.R
|
|||
import cash.z.android.wallet.databinding.FragmentHistoryBinding
|
||||
import cash.z.android.wallet.di.annotation.FragmentScope
|
||||
import cash.z.android.wallet.ui.adapter.TransactionAdapter
|
||||
import cash.z.android.wallet.ui.adapter.TransactionUiModel
|
||||
import cash.z.android.wallet.ui.presenter.HistoryPresenter
|
||||
import cash.z.android.wallet.ui.presenter.HistoryPresenterModule
|
||||
import cash.z.android.wallet.ui.util.AlternatingRowColorDecoration
|
||||
import cash.z.wallet.sdk.dao.ClearedTransaction
|
||||
import cash.z.wallet.sdk.entity.ClearedTransaction
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -58,7 +59,7 @@ class HistoryFragment : BaseFragment(), HistoryPresenter.HistoryView {
|
|||
historyPresenter.stop()
|
||||
}
|
||||
|
||||
override fun setTransactions(transactions: List<ClearedTransaction>) {
|
||||
override fun setTransactions(transactions: List<TransactionUiModel>) {
|
||||
mainActivity?.supportActionBar?.title = resources.getQuantityString(R.plurals.history_transaction_count_title,
|
||||
transactions.size, transactions.size)
|
||||
with (binding.recyclerTransactionsHistory) {
|
||||
|
|
|
@ -27,16 +27,14 @@ import cash.z.android.wallet.di.annotation.FragmentScope
|
|||
import cash.z.android.wallet.extention.*
|
||||
import cash.z.android.wallet.sample.SampleProperties
|
||||
import cash.z.android.wallet.ui.adapter.TransactionAdapter
|
||||
import cash.z.android.wallet.ui.adapter.TransactionUiModel
|
||||
import cash.z.android.wallet.ui.presenter.HomePresenter
|
||||
import cash.z.android.wallet.ui.presenter.HomePresenterModule
|
||||
import cash.z.android.wallet.ui.util.AlternatingRowColorDecoration
|
||||
import cash.z.android.wallet.ui.util.LottieLooper
|
||||
import cash.z.android.wallet.ui.util.TopAlignedSpan
|
||||
import cash.z.wallet.sdk.dao.ClearedTransaction
|
||||
import cash.z.wallet.sdk.data.ActiveSendTransaction
|
||||
import cash.z.wallet.sdk.data.ActiveTransaction
|
||||
import cash.z.wallet.sdk.data.TransactionState
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.entity.ClearedTransaction
|
||||
import cash.z.wallet.sdk.ext.*
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.leinardi.android.speeddial.SpeedDialActionItem
|
||||
|
@ -136,7 +134,7 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
|
|||
// SendView Implementation
|
||||
//
|
||||
|
||||
override fun setTransactions(transactions: List<ClearedTransaction>) {
|
||||
override fun setTransactions(transactions: List<TransactionUiModel>) {
|
||||
val recent = if(transactions.size > maxTransactionsShown) transactions.subList(0, maxTransactionsShown) else transactions
|
||||
with (binding.includeContent.recyclerTransactions) {
|
||||
(adapter as TransactionAdapter).submitList(recent)
|
||||
|
@ -160,21 +158,21 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
|
|||
|
||||
onContentRefreshComplete(new <= 0)
|
||||
}
|
||||
|
||||
override fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>) {
|
||||
if (activeTransactionMap.isEmpty()) {
|
||||
twig("A.T.: setActiveTransactionsShown(false) because map is empty")
|
||||
setActiveTransactionsShown(false)
|
||||
return
|
||||
}
|
||||
|
||||
val transactions = activeTransactionMap.entries.toTypedArray()
|
||||
// primary is the last one that was inserted
|
||||
val primaryEntry = transactions[transactions.size - 1]
|
||||
updatePrimaryTransaction(primaryEntry.key, primaryEntry.value)
|
||||
|
||||
onContentRefreshComplete(false)
|
||||
}
|
||||
//
|
||||
// override fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>) {
|
||||
// if (activeTransactionMap.isEmpty()) {
|
||||
// twig("A.T.: setActiveTransactionsShown(false) because map is empty")
|
||||
// setActiveTransactionsShown(false)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// val transactions = activeTransactionMap.entries.toTypedArray()
|
||||
// // primary is the last one that was inserted
|
||||
// val primaryEntry = transactions[transactions.size - 1]
|
||||
// updatePrimaryTransaction(primaryEntry.key, primaryEntry.value)
|
||||
//
|
||||
// onContentRefreshComplete(false)
|
||||
// }
|
||||
|
||||
override fun onCancelledTooLate() {
|
||||
snackbar = snackbar.showOk(view!!, "Oops! It was too late to cancel!")
|
||||
|
@ -236,82 +234,82 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
|
|||
setRefreshAnimationPlaying(false).also { twig("refresh false from onInitialLoadComplete") }
|
||||
}
|
||||
|
||||
private fun updatePrimaryTransaction(transaction: ActiveTransaction, transactionState: TransactionState) {
|
||||
|
||||
twig("setting transaction state to ${transactionState::class.simpleName}")
|
||||
var title = binding.includeContent.textActiveTransactionTitle.text?.toString() ?: ""
|
||||
var subtitle: CharSequence = binding.includeContent.textActiveTransactionSubtitle.text?.toString() ?: ""
|
||||
var isShown = binding.includeContent.textActiveTransactionHeader.visibility == View.VISIBLE
|
||||
var isShownDelay = 10L
|
||||
when (transactionState) {
|
||||
TransactionState.Creating -> {
|
||||
binding.includeContent.headerActiveTransaction.visibility = View.VISIBLE
|
||||
title = "Preparing ${transaction.value.convertZatoshiToZecString(3)} ZEC"
|
||||
subtitle = "to ${(transaction as ActiveSendTransaction).toAddress.truncate()}"
|
||||
setTransactionActive(transaction, true)
|
||||
isShown = true
|
||||
}
|
||||
TransactionState.SendingToNetwork -> {
|
||||
title = "Sending Transaction"
|
||||
subtitle = "to ${(transaction as ActiveSendTransaction).toAddress.truncate()}"
|
||||
binding.includeContent.textActiveTransactionValue.text = "${transaction.value.convertZatoshiToZecString(3)}"
|
||||
binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
|
||||
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
|
||||
setTransactionActive(transaction, true)
|
||||
isShown = true
|
||||
}
|
||||
is TransactionState.Failure -> {
|
||||
binding.includeContent.lottieActiveTransaction.setAnimation(R.raw.lottie_send_failure)
|
||||
binding.includeContent.lottieActiveTransaction.playAnimation()
|
||||
title = "Failed"
|
||||
subtitle = when(transactionState.failedStep) {
|
||||
TransactionState.Creating -> "Failed to create transaction"
|
||||
TransactionState.SendingToNetwork -> "Failed to submit transaction to the network"
|
||||
else -> "Unrecoginzed error"
|
||||
}
|
||||
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
|
||||
binding.includeContent.textActiveTransactionValue.visibility = View.GONE
|
||||
setTransactionActive(transaction, false)
|
||||
isShown = false
|
||||
isShownDelay = 10_000L
|
||||
}
|
||||
is TransactionState.AwaitingConfirmations -> {
|
||||
if (transactionState.confirmationCount < 1) {
|
||||
binding.includeContent.lottieActiveTransaction.setAnimation(R.raw.lottie_send_success)
|
||||
binding.includeContent.lottieActiveTransaction.playAnimation()
|
||||
title = "ZEC Sent"
|
||||
subtitle = "Waiting to be mined..."
|
||||
binding.includeContent.textActiveTransactionValue.text = transaction.value.convertZatoshiToZecString(3)
|
||||
binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
|
||||
binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
|
||||
isShown = true
|
||||
} else if (transactionState.confirmationCount > 1) {
|
||||
isShown = false
|
||||
} else {
|
||||
title = "Confirmation Received"
|
||||
subtitle = transactionState.timestamp.toRelativeTimeString()
|
||||
isShown = false
|
||||
isShownDelay = 5_000L
|
||||
// take it out of the list in a bit and skip counting confirmation animation for now (i.e. one is enough)
|
||||
}
|
||||
}
|
||||
is TransactionState.Cancelled -> {
|
||||
title = binding.includeContent.textActiveTransactionTitle.text.toString()
|
||||
subtitle = binding.includeContent.textActiveTransactionSubtitle.text.toString()
|
||||
setTransactionActive(transaction, false)
|
||||
isShown = false
|
||||
isShownDelay = 10_000L
|
||||
}
|
||||
else -> {
|
||||
Log.e(javaClass.simpleName, "Warning: unrecognized transaction state $transactionState is being ignored")
|
||||
return
|
||||
}
|
||||
}
|
||||
binding.includeContent.textActiveTransactionTitle.text = title
|
||||
binding.includeContent.textActiveTransactionSubtitle.text = subtitle
|
||||
twig("A.T.: setActiveTransactionsShown($isShown, $isShownDelay) because ${transactionState}")
|
||||
setActiveTransactionsShown(isShown, isShownDelay)
|
||||
}
|
||||
// private fun updatePrimaryTransaction(transaction: ActiveTransaction, transactionState: TransactionState) {
|
||||
//
|
||||
// twig("setting transaction state to ${transactionState::class.simpleName}")
|
||||
// var title = binding.includeContent.textActiveTransactionTitle.text?.toString() ?: ""
|
||||
// var subtitle: CharSequence = binding.includeContent.textActiveTransactionSubtitle.text?.toString() ?: ""
|
||||
// var isShown = binding.includeContent.textActiveTransactionHeader.visibility == View.VISIBLE
|
||||
// var isShownDelay = 10L
|
||||
// when (transactionState) {
|
||||
// TransactionState.Creating -> {
|
||||
// binding.includeContent.headerActiveTransaction.visibility = View.VISIBLE
|
||||
// title = "Preparing ${transaction.value.convertZatoshiToZecString(3)} ZEC"
|
||||
// subtitle = "to ${(transaction as ActiveSendTransaction).toAddress.truncate()}"
|
||||
// setTransactionActive(transaction, true)
|
||||
// isShown = true
|
||||
// }
|
||||
// TransactionState.SendingToNetwork -> {
|
||||
// title = "Sending Transaction"
|
||||
// subtitle = "to ${(transaction as ActiveSendTransaction).toAddress.truncate()}"
|
||||
// binding.includeContent.textActiveTransactionValue.text = "${transaction.value.convertZatoshiToZecString(3)}"
|
||||
// binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
|
||||
// binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
|
||||
// setTransactionActive(transaction, true)
|
||||
// isShown = true
|
||||
// }
|
||||
// is TransactionState.Failure -> {
|
||||
// binding.includeContent.lottieActiveTransaction.setAnimation(R.raw.lottie_send_failure)
|
||||
// binding.includeContent.lottieActiveTransaction.playAnimation()
|
||||
// title = "Failed"
|
||||
// subtitle = when(transactionState.failedStep) {
|
||||
// TransactionState.Creating -> "Failed to create transaction"
|
||||
// TransactionState.SendingToNetwork -> "Failed to submit transaction to the network"
|
||||
// else -> "Unrecoginzed error"
|
||||
// }
|
||||
// binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
|
||||
// binding.includeContent.textActiveTransactionValue.visibility = View.GONE
|
||||
// setTransactionActive(transaction, false)
|
||||
// isShown = false
|
||||
// isShownDelay = 10_000L
|
||||
// }
|
||||
// is TransactionState.AwaitingConfirmations -> {
|
||||
// if (transactionState.confirmationCount < 1) {
|
||||
// binding.includeContent.lottieActiveTransaction.setAnimation(R.raw.lottie_send_success)
|
||||
// binding.includeContent.lottieActiveTransaction.playAnimation()
|
||||
// title = "ZEC Sent"
|
||||
// subtitle = "Waiting to be mined..."
|
||||
// binding.includeContent.textActiveTransactionValue.text = transaction.value.convertZatoshiToZecString(3)
|
||||
// binding.includeContent.textActiveTransactionValue.visibility = View.VISIBLE
|
||||
// binding.includeContent.buttonActiveTransactionCancel.visibility = View.GONE
|
||||
// isShown = true
|
||||
// } else if (transactionState.confirmationCount > 1) {
|
||||
// isShown = false
|
||||
// } else {
|
||||
// title = "Confirmation Received"
|
||||
// subtitle = transactionState.timestamp.toRelativeTimeString()
|
||||
// isShown = false
|
||||
// isShownDelay = 5_000L
|
||||
// // take it out of the list in a bit and skip counting confirmation animation for now (i.e. one is enough)
|
||||
// }
|
||||
// }
|
||||
// is TransactionState.Cancelled -> {
|
||||
// title = binding.includeContent.textActiveTransactionTitle.text.toString()
|
||||
// subtitle = binding.includeContent.textActiveTransactionSubtitle.text.toString()
|
||||
// setTransactionActive(transaction, false)
|
||||
// isShown = false
|
||||
// isShownDelay = 10_000L
|
||||
// }
|
||||
// else -> {
|
||||
// Log.e(javaClass.simpleName, "Warning: unrecognized transaction state $transactionState is being ignored")
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// binding.includeContent.textActiveTransactionTitle.text = title
|
||||
// binding.includeContent.textActiveTransactionSubtitle.text = subtitle
|
||||
// twig("A.T.: setActiveTransactionsShown($isShown, $isShownDelay) because ${transactionState}")
|
||||
// setActiveTransactionsShown(isShown, isShownDelay)
|
||||
// }
|
||||
|
||||
|
||||
//
|
||||
|
@ -335,12 +333,12 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
|
|||
private fun init() {
|
||||
zcashLogoAnimation = LottieLooper(binding.lottieZcashBadge, 20..47, 69)
|
||||
binding.includeContent.buttonActiveTransactionCancel.setOnClickListener {
|
||||
val transaction = it.tag as? ActiveSendTransaction
|
||||
if (transaction != null) {
|
||||
homePresenter.onCancelActiveTransaction(transaction)
|
||||
} else {
|
||||
// val transaction = it.tag as? ActiveSendTransaction
|
||||
// if (transaction != null) {
|
||||
// homePresenter.onCancelActiveTransaction(transaction)
|
||||
// } else {
|
||||
Toaster.short("Error: unable to find transaction to cancel!")
|
||||
}
|
||||
// }
|
||||
}
|
||||
binding.lottieZcashBadge.setOnClickListener {
|
||||
binding.lottieZcashBadge.playAnimation()
|
||||
|
@ -471,29 +469,29 @@ class HomeFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener, HomeP
|
|||
}
|
||||
}
|
||||
|
||||
private fun setTransactionActive(transaction: ActiveTransaction, isActive: Boolean) {
|
||||
// TODO: get view for transaction, mostly likely keep a sparse array of these or something
|
||||
if (isActive) {
|
||||
binding.includeContent.buttonActiveTransactionCancel.setText(R.string.cancel)
|
||||
binding.includeContent.buttonActiveTransactionCancel.isEnabled = true
|
||||
binding.includeContent.buttonActiveTransactionCancel.tag = transaction
|
||||
binding.includeContent.headerActiveTransaction.animate().apply {
|
||||
translationZ(10f)
|
||||
duration = 200L
|
||||
interpolator = DecelerateInterpolator()
|
||||
}
|
||||
} else {
|
||||
binding.includeContent.buttonActiveTransactionCancel.setText(R.string.cancelled)
|
||||
binding.includeContent.buttonActiveTransactionCancel.isEnabled = false
|
||||
binding.includeContent.buttonActiveTransactionCancel.tag = null
|
||||
binding.includeContent.headerActiveTransaction.animate().apply {
|
||||
translationZ(2f)
|
||||
duration = 300L
|
||||
interpolator = AccelerateInterpolator()
|
||||
}
|
||||
binding.includeContent.lottieActiveTransaction.cancelAnimation()
|
||||
}
|
||||
}
|
||||
// private fun setTransactionActive(transaction: ActiveTransaction, isActive: Boolean) {
|
||||
// // TODO: get view for transaction, mostly likely keep a sparse array of these or something
|
||||
// if (isActive) {
|
||||
// binding.includeContent.buttonActiveTransactionCancel.setText(R.string.cancel)
|
||||
// binding.includeContent.buttonActiveTransactionCancel.isEnabled = true
|
||||
// binding.includeContent.buttonActiveTransactionCancel.tag = transaction
|
||||
// binding.includeContent.headerActiveTransaction.animate().apply {
|
||||
// translationZ(10f)
|
||||
// duration = 200L
|
||||
// interpolator = DecelerateInterpolator()
|
||||
// }
|
||||
// } else {
|
||||
// binding.includeContent.buttonActiveTransactionCancel.setText(R.string.cancelled)
|
||||
// binding.includeContent.buttonActiveTransactionCancel.isEnabled = false
|
||||
// binding.includeContent.buttonActiveTransactionCancel.tag = null
|
||||
// binding.includeContent.headerActiveTransaction.animate().apply {
|
||||
// translationZ(2f)
|
||||
// duration = 300L
|
||||
// interpolator = AccelerateInterpolator()
|
||||
// }
|
||||
// binding.includeContent.lottieActiveTransaction.cancelAnimation()
|
||||
// }
|
||||
// }
|
||||
|
||||
private inner class Ticker : Runnable {
|
||||
override fun run() {
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.view.View
|
|||
import android.widget.ProgressBar
|
||||
import androidx.annotation.IdRes
|
||||
import cash.z.android.wallet.ui.presenter.ProgressPresenter
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -15,7 +15,7 @@ abstract class ProgressFragment(
|
|||
ProgressPresenter.ProgressView {
|
||||
|
||||
@Inject
|
||||
protected lateinit var synchronizer: DataSynchronizer
|
||||
protected lateinit var synchronizer: Synchronizer
|
||||
|
||||
protected lateinit var progressPresenter: ProgressPresenter
|
||||
private lateinit var progressBar: ProgressBar
|
||||
|
|
|
@ -12,7 +12,7 @@ import cash.z.android.qrecycler.QRecycler
|
|||
import cash.z.android.wallet.R
|
||||
import cash.z.android.wallet.di.annotation.FragmentScope
|
||||
import cash.z.android.wallet.ui.util.AddressPartNumberSpan
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import kotlinx.android.synthetic.main.fragment_receive.*
|
||||
|
@ -28,7 +28,7 @@ class ReceiveFragment : BaseFragment() {
|
|||
lateinit var qrecycler: QRecycler
|
||||
|
||||
@Inject
|
||||
lateinit var synchronizer: DataSynchronizer
|
||||
lateinit var synchronizer: Synchronizer
|
||||
|
||||
lateinit var addressParts: Array<TextView>
|
||||
|
||||
|
|
|
@ -6,20 +6,19 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import cash.z.android.wallet.*
|
||||
import cash.z.android.wallet.R
|
||||
import cash.z.android.wallet.ZcashWalletApplication
|
||||
import cash.z.android.wallet.databinding.FragmentZcon1HomeBinding
|
||||
import cash.z.android.wallet.di.annotation.FragmentScope
|
||||
import cash.z.android.wallet.extention.Toaster
|
||||
import cash.z.android.wallet.ui.adapter.TransactionAdapter
|
||||
import cash.z.android.wallet.ui.adapter.TransactionUiModel
|
||||
import cash.z.android.wallet.ui.presenter.BalancePresenter
|
||||
import cash.z.android.wallet.ui.presenter.TransactionPresenter
|
||||
import cash.z.android.wallet.ui.presenter.TransactionPresenterModule
|
||||
import cash.z.wallet.sdk.dao.ClearedTransaction
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.ext.MINERS_FEE_ZATOSHI
|
||||
import cash.z.wallet.sdk.entity.ClearedTransaction
|
||||
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
|
||||
import cash.z.wallet.sdk.secure.Wallet
|
||||
import dagger.Module
|
||||
|
@ -45,7 +44,7 @@ class Zcon1HomeFragment : BaseFragment(), BalancePresenter.BalanceView, Transact
|
|||
|
||||
private val balanceInfo: Wallet.WalletBalance get() = mainActivity?.balancePresenter?.lastBalance!!
|
||||
|
||||
private var transactions: List<ClearedTransaction> = emptyList()
|
||||
private var transactions: List<TransactionUiModel> = emptyList()
|
||||
|
||||
|
||||
|
||||
|
@ -167,7 +166,7 @@ class Zcon1HomeFragment : BaseFragment(), BalancePresenter.BalanceView, Transact
|
|||
// TransactionView Implementation
|
||||
//
|
||||
|
||||
override fun setTransactions(transactions: List<ClearedTransaction>) {
|
||||
override fun setTransactions(transactions: List<TransactionUiModel>) {
|
||||
this.transactions = transactions
|
||||
refreshTransactions()
|
||||
}
|
||||
|
@ -196,16 +195,16 @@ class Zcon1HomeFragment : BaseFragment(), BalancePresenter.BalanceView, Transact
|
|||
// }
|
||||
}
|
||||
|
||||
private fun PokerChip.toClearedTransaction(): ClearedTransaction {
|
||||
return ClearedTransaction(
|
||||
value = zatoshiValue - MINERS_FEE_ZATOSHI,
|
||||
isSend = true,
|
||||
timeInSeconds = created/1000L,
|
||||
status = "Verifying funds...",
|
||||
address = "PokerChip",
|
||||
memo = toMemo()
|
||||
)
|
||||
}
|
||||
//private fun PokerChip.toClearedTransaction(): ClearedTransaction {
|
||||
// return ClearedTransaction(
|
||||
// value = zatoshiValue - MINERS_FEE_ZATOSHI,
|
||||
// isSend = true,
|
||||
// timeInSeconds = created/1000L,
|
||||
// status = "Verifying funds...",
|
||||
// address = "PokerChip",
|
||||
// memo = toMemo()
|
||||
// )
|
||||
//}
|
||||
|
||||
|
||||
@Module
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package cash.z.android.wallet.ui.presenter
|
||||
|
||||
import cash.z.android.wallet.ui.adapter.TransactionUiModel
|
||||
import cash.z.android.wallet.ui.fragment.HistoryFragment
|
||||
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
|
||||
import cash.z.wallet.sdk.dao.ClearedTransaction
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
@ -16,13 +16,13 @@ import javax.inject.Singleton
|
|||
|
||||
class HistoryPresenter @Inject constructor(
|
||||
private val view: HistoryFragment,
|
||||
private var synchronizer: DataSynchronizer
|
||||
private var synchronizer: Synchronizer
|
||||
) : Presenter {
|
||||
|
||||
private var job: Job? = null
|
||||
|
||||
interface HistoryView : PresenterView {
|
||||
fun setTransactions(transactions: List<ClearedTransaction>)
|
||||
fun setTransactions(transactions: List<TransactionUiModel>)
|
||||
}
|
||||
|
||||
override suspend fun start() {
|
||||
|
@ -37,7 +37,7 @@ class HistoryPresenter @Inject constructor(
|
|||
job?.cancel()?.also { job = null }
|
||||
}
|
||||
|
||||
private fun CoroutineScope.launchTransactionBinder(channel: ReceiveChannel<List<ClearedTransaction>>) = launch {
|
||||
private fun CoroutineScope.launchTransactionBinder(channel: ReceiveChannel<List<TransactionUiModel>>) = launch {
|
||||
twig("transaction binder starting!")
|
||||
for (clearedTransactionList in channel) {
|
||||
twig("received ${clearedTransactionList.size} transactions for presenting")
|
||||
|
@ -51,11 +51,9 @@ class HistoryPresenter @Inject constructor(
|
|||
// View Callbacks on Main Thread
|
||||
//
|
||||
|
||||
private fun bind(transactions: List<ClearedTransaction>) {
|
||||
private fun bind(transactions: List<TransactionUiModel>) {
|
||||
twig("binding ${transactions.size} clearedTransactions")
|
||||
view.setTransactions(transactions.sortedByDescending {
|
||||
if (!it.isMined && it.isSend) Long.MAX_VALUE else it.timeInSeconds
|
||||
})
|
||||
view.setTransactions(transactions)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package cash.z.android.wallet.ui.presenter
|
||||
|
||||
import cash.z.android.wallet.ui.adapter.TransactionUiModel
|
||||
import cash.z.android.wallet.ui.fragment.HomeFragment
|
||||
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
|
||||
import cash.z.wallet.sdk.dao.ClearedTransaction
|
||||
import cash.z.wallet.sdk.data.*
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.entity.ClearedTransaction
|
||||
import cash.z.wallet.sdk.secure.Wallet
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
@ -16,15 +18,15 @@ import javax.inject.Singleton
|
|||
|
||||
class HomePresenter @Inject constructor(
|
||||
private val view: HomeFragment,
|
||||
private val synchronizer: DataSynchronizer
|
||||
private val synchronizer: Synchronizer
|
||||
) : Presenter {
|
||||
|
||||
private var job: Job? = null
|
||||
|
||||
interface HomeView : PresenterView {
|
||||
fun setTransactions(transactions: List<ClearedTransaction>)
|
||||
fun setTransactions(transactions: List<TransactionUiModel>)
|
||||
fun updateBalance(old: Long, new: Long)
|
||||
fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>)
|
||||
// fun setActiveTransactions(activeTransactionMap: Map<ActiveTransaction, TransactionState>)
|
||||
fun onCancelledTooLate()
|
||||
fun onSynchronizerError(error: Throwable?): Boolean
|
||||
}
|
||||
|
@ -56,7 +58,7 @@ class HomePresenter @Inject constructor(
|
|||
twig("balance binder exiting!")
|
||||
}
|
||||
|
||||
private fun CoroutineScope.launchTransactionBinder(channel: ReceiveChannel<List<ClearedTransaction>>) = launch {
|
||||
private fun CoroutineScope.launchTransactionBinder(channel: ReceiveChannel<List<TransactionUiModel>>) = launch {
|
||||
twig("transaction binder starting!")
|
||||
for (clearedTransactionList in channel) {
|
||||
twig("received ${clearedTransactionList.size} transactions for presenting")
|
||||
|
@ -65,13 +67,13 @@ class HomePresenter @Inject constructor(
|
|||
twig("transaction binder exiting!")
|
||||
}
|
||||
|
||||
private fun CoroutineScope.launchActiveTransactionMonitor(channel: ReceiveChannel<Map<ActiveTransaction, TransactionState>>) = launch {
|
||||
twig("active transaction monitor starting!")
|
||||
for (i in channel) {
|
||||
bind(i)
|
||||
}
|
||||
twig("active transaction monitor exiting!")
|
||||
}
|
||||
// private fun CoroutineScope.launchActiveTransactionMonitor(channel: ReceiveChannel<Map<ActiveTransaction, TransactionState>>) = launch {
|
||||
// twig("active transaction monitor starting!")
|
||||
// for (i in channel) {
|
||||
// bind(i)
|
||||
// }
|
||||
// twig("active transaction monitor exiting!")
|
||||
// }
|
||||
|
||||
|
||||
//
|
||||
|
@ -84,25 +86,23 @@ class HomePresenter @Inject constructor(
|
|||
}
|
||||
|
||||
|
||||
private fun bind(transactions: List<ClearedTransaction>) {
|
||||
private fun bind(transactions: List<TransactionUiModel>) {
|
||||
twig("binding ${transactions.size} clearedTransactions")
|
||||
view.setTransactions(transactions.sortedByDescending {
|
||||
if (!it.isMined && it.isSend) Long.MAX_VALUE else it.timeInSeconds
|
||||
})
|
||||
view.setTransactions(transactions)
|
||||
}
|
||||
|
||||
private fun bind(activeTransactionMap: Map<ActiveTransaction, TransactionState>) {
|
||||
twig("binding a.t. map of size ${activeTransactionMap.size}")
|
||||
if (activeTransactionMap.isNotEmpty()) view.setActiveTransactions(activeTransactionMap)
|
||||
}
|
||||
// private fun bind(activeTransactionMap: Map<ActiveTransaction, TransactionState>) {
|
||||
// twig("binding a.t. map of size ${activeTransactionMap.size}")
|
||||
// if (activeTransactionMap.isNotEmpty()) view.setActiveTransactions(activeTransactionMap)
|
||||
// }
|
||||
|
||||
fun onCancelActiveTransaction(transaction: ActiveSendTransaction) {
|
||||
// fun onCancelActiveTransaction(transaction: ActiveSendTransaction) {
|
||||
// twig("requesting to cancel send for transaction ${transaction.internalId}")
|
||||
// val isTooLate = !synchronizer.cancelSend(transaction)
|
||||
// if (isTooLate) {
|
||||
// view.onCancelledTooLate()
|
||||
// }
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package cash.z.android.wallet.ui.presenter
|
||||
|
||||
import cash.z.android.wallet.Zcon1Store
|
||||
import cash.z.android.wallet.Zcon1Store.address
|
||||
import cash.z.android.wallet.ui.activity.MainActivity
|
||||
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import cash.z.wallet.sdk.data.Twig
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.db.PendingTransaction
|
||||
import cash.z.wallet.sdk.db.isFailure
|
||||
import cash.z.wallet.sdk.entity.PendingTransaction
|
||||
import cash.z.wallet.sdk.entity.isFailure
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -18,7 +19,7 @@ import javax.inject.Inject
|
|||
|
||||
class MainPresenter @Inject constructor(
|
||||
private val view: MainActivity,
|
||||
private val synchronizer: DataSynchronizer
|
||||
private val synchronizer: Synchronizer
|
||||
) : Presenter {
|
||||
|
||||
interface MainView : PresenterView {
|
||||
|
@ -80,7 +81,7 @@ class MainPresenter @Inject constructor(
|
|||
}
|
||||
|
||||
private fun PendingTransaction.isSwag(): Boolean {
|
||||
return address == Zcon1Store.address && memo.toLowerCase().contains("swag")
|
||||
return address == Zcon1Store.address && (memo?.toLowerCase()?.contains("swag") == true)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cash.z.android.wallet.ui.presenter
|
||||
|
||||
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import cash.z.wallet.sdk.data.Twig
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -12,7 +12,7 @@ import javax.inject.Inject
|
|||
|
||||
class ProgressPresenter @Inject constructor(
|
||||
private val view: ProgressView,
|
||||
private var synchronizer: DataSynchronizer
|
||||
private var synchronizer: Synchronizer
|
||||
) : Presenter {
|
||||
|
||||
private var job: Job? = null
|
||||
|
|
|
@ -6,7 +6,7 @@ import cash.z.android.wallet.extention.toAppString
|
|||
import cash.z.android.wallet.sample.SampleProperties
|
||||
import cash.z.android.wallet.ui.fragment.SendFragment
|
||||
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import cash.z.wallet.sdk.data.Twig
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.ext.*
|
||||
|
@ -22,7 +22,7 @@ import javax.inject.Inject
|
|||
|
||||
class SendPresenter @Inject constructor(
|
||||
private val view: SendFragment,
|
||||
private val synchronizer: DataSynchronizer
|
||||
private val synchronizer: Synchronizer
|
||||
) : Presenter {
|
||||
|
||||
interface SendView : PresenterView {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package cash.z.android.wallet.ui.presenter
|
||||
|
||||
import cash.z.android.wallet.extention.truncate
|
||||
import cash.z.android.wallet.ui.adapter.TransactionUiModel
|
||||
import cash.z.android.wallet.ui.fragment.Zcon1HomeFragment
|
||||
import cash.z.android.wallet.ui.presenter.Presenter.PresenterView
|
||||
import cash.z.wallet.sdk.dao.ClearedTransaction
|
||||
import cash.z.wallet.sdk.data.DataSynchronizer
|
||||
import cash.z.wallet.sdk.data.TransactionState
|
||||
import cash.z.wallet.sdk.data.Synchronizer
|
||||
import cash.z.wallet.sdk.data.Twig
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.db.*
|
||||
import cash.z.wallet.sdk.entity.*
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -17,18 +17,18 @@ import javax.inject.Inject
|
|||
|
||||
class TransactionPresenter @Inject constructor(
|
||||
private val view: Zcon1HomeFragment,
|
||||
private val synchronizer: DataSynchronizer
|
||||
private val synchronizer: Synchronizer
|
||||
) : Presenter {
|
||||
|
||||
interface TransactionView : PresenterView {
|
||||
fun setTransactions(transactions: List<ClearedTransaction>)
|
||||
fun setTransactions(transactions: List<TransactionUiModel>)
|
||||
}
|
||||
|
||||
private var pendingJob: Job? = null
|
||||
private var clearedJob: Job? = null
|
||||
|
||||
private var latestPending: List<PendingTransaction> = listOf()
|
||||
private var latestCleared: List<ClearedTransaction> = listOf()
|
||||
private var latestPending: List<TransactionUiModel> = listOf()
|
||||
private var latestCleared: List<TransactionUiModel> = listOf()
|
||||
|
||||
//
|
||||
// LifeCycle
|
||||
|
@ -57,7 +57,7 @@ class TransactionPresenter @Inject constructor(
|
|||
twig("pending transaction binder starting")
|
||||
for (new in channel) {
|
||||
twig("pending transactions have been modified... binding to the view")
|
||||
latestPending = new
|
||||
latestPending = new.map { it.toTransactionUiModel() }
|
||||
bind()
|
||||
}
|
||||
twig("pending transaction binder exiting!")
|
||||
|
@ -68,7 +68,13 @@ class TransactionPresenter @Inject constructor(
|
|||
twig("cleared transaction binder starting")
|
||||
for (new in channel) {
|
||||
twig("cleared transactions have been modified... binding to the view")
|
||||
latestCleared = new
|
||||
latestCleared = new.map {
|
||||
when(it) {
|
||||
is SentTransaction -> it.toTransactionUiModel()
|
||||
is ReceivedTransaction -> it.toTransactionUiModel()
|
||||
else -> throw UnsupportedTransactionException(it)
|
||||
}
|
||||
}
|
||||
bind()
|
||||
}
|
||||
twig("cleared transaction binder exiting!")
|
||||
|
@ -82,11 +88,12 @@ class TransactionPresenter @Inject constructor(
|
|||
private fun bind() {
|
||||
twig("binding ${latestPending.size} pending transactions and ${latestCleared.size} cleared transactions")
|
||||
// merge transactions
|
||||
val mergedTransactions = mutableListOf<ClearedTransaction>()
|
||||
latestPending.forEach { mergedTransactions.add(it.toClearedTransaction()) }
|
||||
val mergedTransactions = mutableListOf<TransactionUiModel>()
|
||||
|
||||
mergedTransactions.addAll(latestCleared)
|
||||
mergedTransactions.addAll(latestPending)
|
||||
mergedTransactions.sortByDescending {
|
||||
it.timeInSeconds
|
||||
if (it.timestampMillis > 0) it.timestampMillis else it.minedHeight.toLong()
|
||||
}
|
||||
view.setTransactions(mergedTransactions)
|
||||
// twig("MERGED_TX---------vvvvvv")
|
||||
|
@ -97,36 +104,87 @@ class TransactionPresenter @Inject constructor(
|
|||
}
|
||||
|
||||
|
||||
sealed class PurchaseResult {
|
||||
data class Processing(val state: TransactionState = TransactionState.Creating) : PurchaseResult()
|
||||
data class Failure(val reason: String = "") : PurchaseResult()
|
||||
}
|
||||
// sealed class PurchaseResult {
|
||||
// data class Processing(val state: TransactionState = TransactionState.Creating) : PurchaseResult()
|
||||
// data class Failure(val reason: String = "") : PurchaseResult()
|
||||
// }
|
||||
}
|
||||
|
||||
private fun PendingTransaction.toClearedTransaction(): ClearedTransaction {
|
||||
var description = when {
|
||||
isFailedEncoding() -> "Failed to create! Aborted."
|
||||
isFailedSubmit() -> "Failed to send...Retrying!"
|
||||
isCreating() -> if (memo.toLowerCase().contains("poker chip")) "Redeeming..." else "Creating transaction..."
|
||||
isSubmitted() && !isMined() -> "Submitted, awaiting response."
|
||||
isSubmitted() && isMined() -> "Successfully mined!"
|
||||
else -> "Pending..."
|
||||
}
|
||||
if (!isSubmitted() && (submitAttempts > 2 || encodeAttempts > 2)) {
|
||||
description += " aborting in ${ttl() / 60L}m${ttl().rem(60)}s"
|
||||
}
|
||||
return ClearedTransaction(
|
||||
value = value,
|
||||
private fun SentTransaction.toTransactionUiModel(): TransactionUiModel {
|
||||
return TransactionUiModel(
|
||||
status = "to ${toAddress.truncate()}",
|
||||
isSend = true,
|
||||
isMined = isMined(),
|
||||
height = minedHeight,
|
||||
timeInSeconds = createTime / 1000L,
|
||||
address = address,
|
||||
status = description,
|
||||
memo = memo
|
||||
minedHeight = minedHeight,
|
||||
zatoshiValue = value,
|
||||
memo = memo,
|
||||
isSwag = memo?.toLowerCase()?.contains("swag") ?: false,
|
||||
timestampMillis = blockTimeInSeconds * 1000L,
|
||||
isPokerChip = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun ReceivedTransaction.toTransactionUiModel(): TransactionUiModel {
|
||||
return TransactionUiModel(
|
||||
status = "from shielded address",
|
||||
minedHeight = minedHeight,
|
||||
zatoshiValue = value,
|
||||
timestampMillis = blockTimeInSeconds * 1000L,
|
||||
isPokerChip = false
|
||||
)
|
||||
}
|
||||
|
||||
private fun PendingTransaction.toTransactionUiModel(): TransactionUiModel {
|
||||
val isPokerChip = memo?.toLowerCase()?.contains("poker chip") == true
|
||||
val isSwag = memo?.toLowerCase()?.contains("swag") ?: false
|
||||
var description = when {
|
||||
isSwag && isMined() -> "Purchase accepted."
|
||||
isFailedEncoding() -> "Failed to create! Aborted."
|
||||
isFailedSubmit() -> "Failed to send...Retrying!"
|
||||
isCreating() -> if (isPokerChip) "Redeeming..." else "Creating transaction..."
|
||||
isSwag && !isMined() -> "Purchase pending"
|
||||
isSubmitted() && !isMined() -> "Submitted, awaiting response."
|
||||
isSubmitted() && isMined() -> if (isPokerChip) "Successfully mined!" else "to ${toAddress.truncate()}"
|
||||
else -> "Pending..."
|
||||
}
|
||||
return TransactionUiModel(
|
||||
action = if (isPokerChip) "Scan" else null,
|
||||
status = description,
|
||||
isPending = true,
|
||||
isSend = true,
|
||||
isSwag = isSwag,
|
||||
minedHeight = minedHeight,
|
||||
zatoshiValue = value,
|
||||
memo = memo,
|
||||
timestampMillis = createTime,
|
||||
isPokerChip = isPokerChip
|
||||
)
|
||||
}
|
||||
|
||||
class UnsupportedTransactionException(tx: ClearedTransaction) :
|
||||
RuntimeException("Unsupported transaction type. " +
|
||||
"Expected either SentTransaction or ReceivedTransaction but was ${tx.javaClass.canonicalName}")
|
||||
|
||||
//private fun PendingTransaction.toClearedTransaction(): ClearedTransaction {
|
||||
// var description = when {
|
||||
// isFailedEncoding() -> "Failed to create! Aborted."
|
||||
// isFailedSubmit() -> "Failed to send...Retrying!"
|
||||
// isCreating() -> if (memo?.toLowerCase()?.contains("poker chip") == true) "Redeeming..." else "Creating transaction..."
|
||||
// isSubmitted() && !isMined() -> "Submitted, awaiting response."
|
||||
// isSubmitted() && isMined() -> "Successfully mined!"
|
||||
// else -> "Pending..."
|
||||
// }
|
||||
//// if (!isSubmitted() && (submitAttempts > 2 || encodeAttempts > 2)) {
|
||||
//// description += " aborting in ${ttl() / 60L}m${ttl().rem(60)}s"
|
||||
//// }
|
||||
// return SentTransaction(
|
||||
// value = value,
|
||||
// minedHeight = minedHeight,
|
||||
// blockTimeInSeconds = createTime / 1000L,
|
||||
// toAddress = toAddress,
|
||||
// status = description,
|
||||
// memo = memo
|
||||
// )
|
||||
//}
|
||||
|
||||
@Module
|
||||
abstract class TransactionPresenterModule {
|
||||
@Binds
|
||||
|
|
|
@ -8,7 +8,7 @@ import cash.z.android.wallet.ZcashWalletApplication
|
|||
import cash.z.android.wallet.Zcon1Store
|
||||
import cash.z.android.wallet.extention.toAppString
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.db.PendingTransaction
|
||||
import cash.z.wallet.sdk.entity.PendingTransaction
|
||||
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
|
||||
import com.mixpanel.android.mpmetrics.MixpanelAPI
|
||||
import java.io.PrintWriter
|
||||
|
|
|
@ -8,7 +8,7 @@ import cash.z.wallet.sdk.data.TransactionSender
|
|||
import cash.z.wallet.sdk.data.Twig
|
||||
import cash.z.wallet.sdk.data.WalletTransactionEncoder
|
||||
import cash.z.wallet.sdk.data.twig
|
||||
import cash.z.wallet.sdk.db.PendingTransaction
|
||||
import cash.z.wallet.sdk.entity.PendingTransaction
|
||||
import cash.z.wallet.sdk.ext.MINERS_FEE_ZATOSHI
|
||||
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
|
||||
import cash.z.wallet.sdk.jni.RustBackendWelding
|
||||
|
|
|
@ -60,7 +60,7 @@ buildscript {
|
|||
'speeddial': 'com.leinardi.android:speed-dial:2.0.0',
|
||||
'stetho': 'com.facebook.stetho:stetho:1.5.1',
|
||||
'zcash': [
|
||||
'walletSdk': "cash.z.android.wallet:zcash-android-testnet:1.9.0-alpha@aar"
|
||||
'walletSdk': "cash.z.android.wallet:zcash-android-testnet:1.9.1-alpha@aar"
|
||||
]
|
||||
]
|
||||
repositories {
|
||||
|
|
Loading…
Reference in New Issue