feat: refactor receive fragment

It's now possible to rename latest address without generating a new one
This commit is contained in:
- 2024-09-18 16:37:12 +02:00
parent 8a769d0e23
commit f0ba6f5ce5
8 changed files with 44 additions and 57 deletions

View File

@ -15,6 +15,7 @@
*/ */
package net.mynero.wallet.adapter package net.mynero.wallet.adapter
import android.graphics.Typeface
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -26,19 +27,19 @@ import net.mynero.wallet.service.PrefService
import net.mynero.wallet.util.Constants import net.mynero.wallet.util.Constants
import net.mynero.wallet.util.Helper import net.mynero.wallet.util.Helper
class SubaddressAdapter(val listener: SubaddressAdapterListener?) : class SubaddressAdapter(
RecyclerView.Adapter<SubaddressAdapter.ViewHolder>() { private var addresses: List<Subaddress>,
private var localDataSet: List<Subaddress> private var selectedAddress: Subaddress?,
val listener: SubaddressAdapterListener?
): RecyclerView.Adapter<SubaddressAdapter.ViewHolder>() {
/** fun submitAddresses(addresses: List<Subaddress>) {
* Initialize the dataset of the Adapter. this.addresses = addresses
*/ notifyDataSetChanged()
init {
localDataSet = ArrayList()
} }
fun submitList(dataSet: List<Subaddress>) { fun submitSelectedAddress(selectedAddress: Subaddress?) {
localDataSet = dataSet this.selectedAddress = selectedAddress
notifyDataSetChanged() notifyDataSetChanged()
} }
@ -52,13 +53,13 @@ class SubaddressAdapter(val listener: SubaddressAdapterListener?) :
// Replace the contents of a view (invoked by the layout manager) // Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
val subaddress = localDataSet[position] val address = addresses[position]
viewHolder.bind(subaddress) viewHolder.bind(address, selectedAddress != null && address == selectedAddress)
} }
// Return the size of your dataset (invoked by the layout manager) // Return the size of your dataset (invoked by the layout manager)
override fun getItemCount(): Int { override fun getItemCount(): Int {
return localDataSet.size return addresses.size
} }
interface SubaddressAdapterListener { interface SubaddressAdapterListener {
@ -71,17 +72,20 @@ class SubaddressAdapter(val listener: SubaddressAdapterListener?) :
* (custom ViewHolder). * (custom ViewHolder).
*/ */
class ViewHolder(view: View, val listener: SubaddressAdapterListener?) : class ViewHolder(view: View, val listener: SubaddressAdapterListener?) :
RecyclerView.ViewHolder( RecyclerView.ViewHolder(view) {
view
) {
fun bind(subaddress: Subaddress) { fun bind(subaddress: Subaddress, isSelected: Boolean) {
val addressTextView = val addressTextView =
itemView.findViewById<TextView>(R.id.address_item_address_textview) itemView.findViewById<TextView>(R.id.address_item_address_textview)
val addressLabelTextView = itemView.findViewById<TextView>(R.id.address_label_textview) val addressLabelTextView = itemView.findViewById<TextView>(R.id.address_label_textview)
val addressAmountTextView = val addressAmountTextView =
itemView.findViewById<TextView>(R.id.address_amount_textview) itemView.findViewById<TextView>(R.id.address_amount_textview)
addressTextView.text = subaddress.address addressTextView.text = subaddress.address
if (isSelected) {
addressTextView.setTypeface(null, Typeface.BOLD)
} else {
addressTextView.setTypeface(null, Typeface.NORMAL)
}
val label = subaddress.displayLabel val label = subaddress.displayLabel
val address = itemView.context.getString( val address = itemView.context.getString(
R.string.subbaddress_info_subtitle, R.string.subbaddress_info_subtitle,

View File

@ -10,7 +10,6 @@ import android.widget.ImageButton
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import net.mynero.wallet.R import net.mynero.wallet.R
import net.mynero.wallet.model.WalletManager import net.mynero.wallet.model.WalletManager
import net.mynero.wallet.service.AddressService
import net.mynero.wallet.util.Helper.getClipBoardText import net.mynero.wallet.util.Helper.getClipBoardText
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -30,7 +29,6 @@ class EditAddressLabelBottomSheetDialog : BottomSheetDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val wallet = WalletManager.instance?.wallet val wallet = WalletManager.instance?.wallet
val addressService = AddressService.instance
val pasteButton = view.findViewById<ImageButton>(R.id.paste_password_imagebutton) val pasteButton = view.findViewById<ImageButton>(R.id.paste_password_imagebutton)
val labelEditText = view.findViewById<EditText>(R.id.wallet_password_edittext) val labelEditText = view.findViewById<EditText>(R.id.wallet_password_edittext)
val saveLabelButton = view.findViewById<Button>(R.id.unlock_wallet_button) val saveLabelButton = view.findViewById<Button>(R.id.unlock_wallet_button)
@ -50,9 +48,6 @@ class EditAddressLabelBottomSheetDialog : BottomSheetDialogFragment() {
pasteButton.setOnClickListener { labelEditText.setText(getClipBoardText(view.context)) } pasteButton.setOnClickListener { labelEditText.setText(getClipBoardText(view.context)) }
saveLabelButton.setOnClickListener { saveLabelButton.setOnClickListener {
val label = labelEditText.text.toString() val label = labelEditText.text.toString()
if (addressService?.latestAddressIndex == addressIndex) {
addressService.freshSubaddress()
}
wallet?.setSubaddressLabel(addressIndex, label) wallet?.setSubaddressLabel(addressIndex, label)
wallet?.store() wallet?.store()
if (listener != null) { if (listener != null) {

View File

@ -17,7 +17,6 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.zxing.BarcodeFormat import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException import com.google.zxing.WriterException
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import com.journeyapps.barcodescanner.BarcodeEncoder import com.journeyapps.barcodescanner.BarcodeEncoder
import net.mynero.wallet.R import net.mynero.wallet.R
@ -36,6 +35,7 @@ class ReceiveFragment : Fragment() {
private var addressImageView: ImageView? = null private var addressImageView: ImageView? = null
private var copyAddressImageButton: ImageButton? = null private var copyAddressImageButton: ImageButton? = null
private var mViewModel: ReceiveViewModel? = null private var mViewModel: ReceiveViewModel? = null
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
@ -61,7 +61,7 @@ class ReceiveFragment : Fragment() {
} }
private fun bindObservers(view: View) { private fun bindObservers(view: View) {
val adapter = SubaddressAdapter(object : SubaddressAdapterListener { val subaddressAdapterListener = object : SubaddressAdapterListener {
override fun onSubaddressSelected(subaddress: Subaddress?) { override fun onSubaddressSelected(subaddress: Subaddress?) {
mViewModel?.selectAddress(subaddress) mViewModel?.selectAddress(subaddress)
} }
@ -69,19 +69,18 @@ class ReceiveFragment : Fragment() {
override fun onSubaddressEditLabel(subaddress: Subaddress?) { override fun onSubaddressEditLabel(subaddress: Subaddress?) {
editAddressLabel(subaddress) editAddressLabel(subaddress)
} }
}) }
val adapter = SubaddressAdapter(emptyList(), null, subaddressAdapterListener)
val recyclerView = view.findViewById<RecyclerView>(R.id.address_list_recyclerview) val recyclerView = view.findViewById<RecyclerView>(R.id.address_list_recyclerview)
recyclerView.layoutManager = LinearLayoutManager(activity) recyclerView.layoutManager = LinearLayoutManager(activity)
recyclerView.adapter = adapter recyclerView.adapter = adapter
mViewModel?.address?.observe(viewLifecycleOwner) { subaddress: Subaddress? -> mViewModel?.address?.observe(viewLifecycleOwner) { address: Subaddress? ->
setAddress( setAddress(address)
subaddress adapter.submitSelectedAddress(address)
)
} }
mViewModel?.addresses?.observe(viewLifecycleOwner) { dataSet: List<Subaddress> -> mViewModel?.addresses?.observe(viewLifecycleOwner) { addresses: List<Subaddress> ->
adapter.submitList( // We want newer addresses addresses to be shown first
dataSet adapter.submitAddresses(addresses.reversed())
)
} }
} }

View File

@ -11,23 +11,25 @@ import java.util.Collections
class ReceiveViewModel : ViewModel() { class ReceiveViewModel : ViewModel() {
private val _address = MutableLiveData<Subaddress?>() private val _address = MutableLiveData<Subaddress?>()
private val _addresses = MutableLiveData<List<Subaddress>>() private val _addresses = MutableLiveData<List<Subaddress>>()
var address: LiveData<Subaddress?> = _address val address: LiveData<Subaddress?> = _address
var addresses: LiveData<List<Subaddress>> = _addresses val addresses: LiveData<List<Subaddress>> = _addresses
fun init() { fun init() {
_address.value = AddressService.instance?.currentSubaddress()
_addresses.value = subaddresses _addresses.value = subaddresses
_address.value = addresses.value?.lastOrNull()
} }
private val subaddresses: List<Subaddress> private val subaddresses: List<Subaddress>
get() { get() {
val wallet = WalletManager.instance?.wallet val wallet = WalletManager.instance?.wallet
val subaddresses = ArrayList<Subaddress>() val subaddresses = ArrayList<Subaddress>()
val addressesSize = AddressService.instance?.latestAddressIndex ?: 0 val numAddresses = AddressService.instance?.numAddresses ?: 1
for (i in addressesSize - 1 downTo 0) { for (i in 0 until numAddresses) {
wallet?.getSubaddressObject(i)?.let { subaddresses.add(it) } wallet?.getSubaddressObject(i)?.let { subaddresses.add(it) }
} }
return Collections.unmodifiableList(subaddresses) return Collections.unmodifiableList(subaddresses)
} }
val freshSubaddress: Unit val freshSubaddress: Unit
get() { get() {
_address.value = AddressService.instance?.freshSubaddress() _address.value = AddressService.instance?.freshSubaddress()

View File

@ -19,9 +19,6 @@ import android.util.Log
import android.util.Pair import android.util.Pair
import net.mynero.wallet.data.Subaddress import net.mynero.wallet.data.Subaddress
import java.io.File import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class Wallet { class Wallet {
var isSynchronized = false var isSynchronized = false
@ -418,16 +415,6 @@ class Wallet {
get() = getNumSubaddresses(accountIndex) get() = getNumSubaddresses(accountIndex)
private external fun getNumSubaddresses(accountIndex: Int): Int private external fun getNumSubaddresses(accountIndex: Int): Int
val newSubaddress: String
get() = getNewSubaddress(accountIndex)
private fun getNewSubaddress(accountIndex: Int): String {
val timeStamp = SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.US).format(Date())
addSubaddress(accountIndex, timeStamp)
val subaddress = getLastSubaddress(accountIndex)
Log.d("Wallet.kt", "${(getNumSubaddresses(accountIndex) - 1)}: $subaddress")
return subaddress
}
external fun addSubaddress(accountIndex: Int, label: String?) external fun addSubaddress(accountIndex: Int, label: String?)
private fun getLastSubaddress(accountIndex: Int): String { private fun getLastSubaddress(accountIndex: Int): String {

View File

@ -7,7 +7,7 @@ import java.util.Date
import java.util.Locale import java.util.Locale
class AddressService(thread: MoneroHandlerThread) : ServiceBase(thread) { class AddressService(thread: MoneroHandlerThread) : ServiceBase(thread) {
var latestAddressIndex = 1 var numAddresses = 1
private set private set
init { init {
@ -15,7 +15,7 @@ class AddressService(thread: MoneroHandlerThread) : ServiceBase(thread) {
} }
fun refreshAddresses() { fun refreshAddresses() {
WalletManager.instance?.wallet?.numSubaddresses?.let { latestAddressIndex = it } WalletManager.instance?.wallet?.numSubaddresses?.let { numAddresses = it }
} }
fun freshSubaddress(): Subaddress? { fun freshSubaddress(): Subaddress? {
@ -24,12 +24,12 @@ class AddressService(thread: MoneroHandlerThread) : ServiceBase(thread) {
wallet?.addSubaddress(wallet.getAccountIndex(), timeStamp) wallet?.addSubaddress(wallet.getAccountIndex(), timeStamp)
refreshAddresses() refreshAddresses()
wallet?.store() wallet?.store()
return wallet?.getSubaddressObject(latestAddressIndex) return wallet?.getSubaddressObject(numAddresses - 1)
} }
fun currentSubaddress(): Subaddress? { fun currentSubaddress(): Subaddress? {
val wallet = WalletManager.instance?.wallet val wallet = WalletManager.instance?.wallet
return wallet?.getSubaddressObject(latestAddressIndex) return wallet?.getSubaddressObject(numAddresses - 1)
} }
companion object { companion object {

View File

@ -109,7 +109,7 @@
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:ellipsize="middle" android:ellipsize="middle"
android:singleLine="true" android:singleLine="true"
android:text="@string/previous_addresses" android:text="@string/all_addresses"
android:textSize="14sp" android:textSize="14sp"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/address_list_recyclerview" app:layout_constraintBottom_toTopOf="@id/address_list_recyclerview"

View File

@ -127,7 +127,7 @@
<string name="trusted_daemon">Trusted daemon</string> <string name="trusted_daemon">Trusted daemon</string>
<string name="use_bundled_tor">Let Mysu start and manage a Tor daemon</string> <string name="use_bundled_tor">Let Mysu start and manage a Tor daemon</string>
<string name="subbaddress_info_subtitle" translatable="false">#%1$d: %2$s</string> <string name="subbaddress_info_subtitle" translatable="false">#%1$d: %2$s</string>
<string name="previous_addresses">Previous addresses</string> <string name="all_addresses">All addresses</string>
<string name="donate_label">Donate to Mysu</string> <string name="donate_label">Donate to Mysu</string>
<string name="donating_label">Donating to Mysu. Thank you!</string> <string name="donating_label">Donating to Mysu. Thank you!</string>
<string name="transactions">Transactions</string> <string name="transactions">Transactions</string>