Basic support for transaction history.

This commit is contained in:
Kevin Gorham 2019-12-23 19:07:10 -05:00
parent 5cdfc97945
commit b53992534a
No known key found for this signature in database
GPG Key ID: CCA55602DF49FC38
7 changed files with 178 additions and 2 deletions

View File

@ -98,6 +98,10 @@ dependencies {
implementation Deps.AndroidX.Lifecycle.LIFECYCLE_RUNTIME_KTX implementation Deps.AndroidX.Lifecycle.LIFECYCLE_RUNTIME_KTX
implementation Deps.AndroidX.Navigation.FRAGMENT_KTX implementation Deps.AndroidX.Navigation.FRAGMENT_KTX
implementation Deps.AndroidX.Navigation.UI_KTX implementation Deps.AndroidX.Navigation.UI_KTX
implementation "androidx.room:room-ktx:2.2.3"
implementation "androidx.paging:paging-runtime-ktx:2.1.1"
implementation 'com.google.guava:guava:27.0.1-android'
kapt "androidx.room:room-compiler:2.2.3"
// Google // Google
implementation Deps.Google.MATERIAL implementation Deps.Google.MATERIAL

View File

@ -0,0 +1,38 @@
package cash.z.ecc.android.ui.detail
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.DiffUtil
import cash.z.ecc.android.R
import cash.z.wallet.sdk.demoapp.demos.listtransactions.TransactionViewHolder
import cash.z.wallet.sdk.entity.ConfirmedTransaction
class TransactionAdapter<T : ConfirmedTransaction> :
PagedListAdapter<T, TransactionViewHolder<T>>(
object : DiffUtil.ItemCallback<T>() {
override fun areItemsTheSame(
oldItem: T,
newItem: T
) = oldItem.minedHeight == newItem.minedHeight
override fun areContentsTheSame(
oldItem: T,
newItem: T
) = oldItem.equals(newItem)
}
) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
) = TransactionViewHolder<T>(
LayoutInflater.from(parent.context).inflate(R.layout.item_transaction, parent, false)
)
override fun onBindViewHolder(
holder: TransactionViewHolder<T>,
position: Int
) = holder.bindTo(getItem(position))
}

View File

@ -0,0 +1,23 @@
package cash.z.wallet.sdk.demoapp.demos.listtransactions
import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import cash.z.ecc.android.R
import cash.z.wallet.sdk.entity.ConfirmedTransaction
import cash.z.wallet.sdk.ext.convertZatoshiToZecString
import java.text.SimpleDateFormat
import java.util.*
class TransactionViewHolder<T : ConfirmedTransaction>(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val amountText = itemView.findViewById<TextView>(R.id.text_transaction_amount)
private val timeText = itemView.findViewById<TextView>(R.id.text_transaction_timestamp)
private val formatter = SimpleDateFormat("M/d h:mma", Locale.getDefault())
fun bindTo(transaction: T?) {
amountText.text = transaction?.value.convertZatoshiToZecString()
timeText.text =
if (transaction == null || transaction?.blockTimeInSeconds == 0L) "Pending"
else formatter.format(transaction.blockTimeInSeconds * 1000L)
}
}

View File

@ -4,6 +4,8 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import androidx.paging.PagedList
import androidx.recyclerview.widget.LinearLayoutManager
import cash.z.ecc.android.R import cash.z.ecc.android.R
import cash.z.ecc.android.databinding.FragmentDetailBinding import cash.z.ecc.android.databinding.FragmentDetailBinding
import cash.z.ecc.android.di.annotation.FragmentScope import cash.z.ecc.android.di.annotation.FragmentScope
@ -11,13 +13,19 @@ import cash.z.ecc.android.ext.onClick
import cash.z.ecc.android.ext.onClickNavUp import cash.z.ecc.android.ext.onClickNavUp
import cash.z.ecc.android.feedback.FeedbackFile import cash.z.ecc.android.feedback.FeedbackFile
import cash.z.ecc.android.ui.base.BaseFragment import cash.z.ecc.android.ui.base.BaseFragment
import cash.z.wallet.sdk.entity.ConfirmedTransaction
import cash.z.wallet.sdk.ext.twig
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import okio.Okio import okio.Okio
class WalletDetailFragment : BaseFragment<FragmentDetailBinding>() { class WalletDetailFragment : BaseFragment<FragmentDetailBinding>() {
private lateinit var adapter: TransactionAdapter<ConfirmedTransaction>
override fun inflate(inflater: LayoutInflater): FragmentDetailBinding = override fun inflate(inflater: LayoutInflater): FragmentDetailBinding =
FragmentDetailBinding.inflate(inflater) FragmentDetailBinding.inflate(inflater)
@ -36,10 +44,23 @@ class WalletDetailFragment : BaseFragment<FragmentDetailBinding>() {
} }
} }
private fun onSendFeedback() { override fun onResume() {
mainActivity?.showSnackbar("Feedback not yet implemented.") super.onResume()
initTransactionUI()
} }
private fun initTransactionUI() {
binding.recyclerTransactions.layoutManager =
LinearLayoutManager(activity, LinearLayoutManager.VERTICAL, false)
adapter = TransactionAdapter()
resumedScope.launch {
mainActivity?.synchronizer?.receivedTransactions?.collect { onTransactionsUpdated(it) }
}
binding.recyclerTransactions.adapter = adapter
}
private fun onSendFeedback() {
mainActivity?.showSnackbar("Feedback not yet implemented.")
} }
private fun onViewLogs() { private fun onViewLogs() {
@ -63,6 +84,11 @@ class WalletDetailFragment : BaseFragment<FragmentDetailBinding>() {
mainActivity?.navController?.navigate(R.id.action_nav_detail_to_backup_wallet) mainActivity?.navController?.navigate(R.id.action_nav_detail_to_backup_wallet)
} }
private fun onTransactionsUpdated(transactions: PagedList<ConfirmedTransaction>) {
twig("got a new paged list of transactions")
adapter.submitList(transactions)
}
private fun loadLogFileAsText(): String? { private fun loadLogFileAsText(): String? {
val feedbackFile: FeedbackFile = val feedbackFile: FeedbackFile =
mainActivity?.feedbackCoordinator?.findObserver() ?: return null mainActivity?.feedbackCoordinator?.findObserver() ?: return null

View File

@ -0,0 +1,5 @@
<vector android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF66BB6A" android:pathData="M20,5.41L18.59,4 7,15.59V9H5v10h10v-2H8.41z"/>
</vector>

View File

@ -4,6 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/background_home"> android:background="@drawable/background_home">
<!-- --> <!-- -->
@ -76,6 +77,21 @@
app:layout_constraintEnd_toEndOf="@id/guideline_keyline_end" app:layout_constraintEnd_toEndOf="@id/guideline_keyline_end"
app:layout_constraintTop_toTopOf="@id/back_button" /> app:layout_constraintTop_toTopOf="@id/back_button" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_transactions"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="12dp"
app:layout_constraintBottom_toTopOf="@+id/guideline_bottom_buttons"
app:layout_constraintStart_toStartOf="@id/guideline_keyline_start"
app:layout_constraintEnd_toEndOf="@id/guideline_keyline_end"
app:layout_constraintTop_toBottomOf="@id/button_backup"
tools:itemCount="15"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_transaction"
tools:orientation="vertical" />
<View <View
android:id="@+id/text_banner_message" android:id="@+id/text_banner_message"
android:layout_width="0dp" android:layout_width="0dp"

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container_transaction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background_banner"
android:elevation="1dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingEnd="10dp"
android:paddingStart="8dp"
android:layout_marginTop="4dp"
tools:ignore="RtlSymmetry">
<ImageView
android:id="@+id/image_transaction_type"
android:layout_width="40dp"
android:layout_height="40dp"
app:srcCompat="@drawable/ic_receive"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_transaction_timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/text_transaction_address"
app:layout_constraintStart_toEndOf="@id/image_transaction_type"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="8/23 3:24pm" />
<TextView
android:id="@+id/text_transaction_address"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="12sp"
android:paddingEnd="16dp"
android:maxLines="1"
android:ellipsize="end"
app:layout_constraintEnd_toStartOf="@id/text_transaction_amount"
app:layout_constraintStart_toStartOf="@id/text_transaction_timestamp"
app:layout_constraintTop_toBottomOf="@id/text_transaction_timestamp"
app:layout_constraintBottom_toBottomOf="parent"
android:text="funds received" />
<TextView
android:id="@+id/text_transaction_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="+ 4.244"
android:textColor="@color/colorPrimary"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>