taler-android

Android apps for GNU Taler (wallet, PoS, cashier)
Log | Files | Refs | README | LICENSE

ExchangeAdapter.kt (7510B)


      1 /*
      2  * This file is part of GNU Taler
      3  * (C) 2020 Taler Systems S.A.
      4  *
      5  * GNU Taler is free software; you can redistribute it and/or modify it under the
      6  * terms of the GNU General Public License as published by the Free Software
      7  * Foundation; either version 3, or (at your option) any later version.
      8  *
      9  * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
     10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11  * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License along with
     14  * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15  */
     16 
     17 package net.taler.wallet.exchanges
     18 
     19 import android.view.LayoutInflater
     20 import android.view.View
     21 import android.view.View.GONE
     22 import android.view.View.VISIBLE
     23 import android.view.ViewGroup
     24 import android.widget.ImageButton
     25 import android.widget.TextView
     26 import androidx.appcompat.widget.PopupMenu
     27 import androidx.recyclerview.widget.DiffUtil
     28 import androidx.recyclerview.widget.RecyclerView
     29 import androidx.recyclerview.widget.RecyclerView.Adapter
     30 import net.taler.wallet.R
     31 import net.taler.wallet.balances.ScopeInfo
     32 import net.taler.wallet.exchanges.ExchangeAdapter.ExchangeItemViewHolder
     33 
     34 interface ExchangeClickListener {
     35     fun onExchangeSelected(item: ExchangeItem)
     36     fun onManualWithdraw(item: ExchangeItem)
     37     fun onPeerReceive(item: ExchangeItem)
     38     fun onExchangeReload(item: ExchangeItem)
     39     fun onExchangeDelete(item: ExchangeItem)
     40     fun onExchangeTosAccept(item: ExchangeItem)
     41     fun onExchangeTosForget(item: ExchangeItem)
     42     fun onExchangeTosView(item: ExchangeItem)
     43     fun onExchangeGlobalCurrencyAdd(item: ExchangeItem)
     44     fun onExchangeGlobalCurrencyDelete(item: ExchangeItem)
     45 }
     46 
     47 internal class ExchangeAdapter(
     48     private val selectOnly: Boolean,
     49     private val listener: ExchangeClickListener,
     50     private val devMode: Boolean,
     51 ) : Adapter<ExchangeItemViewHolder>() {
     52 
     53     private var items = emptyList<ExchangeItem>()
     54 
     55     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ExchangeItemViewHolder {
     56         val view = LayoutInflater.from(parent.context)
     57             .inflate(R.layout.list_item_exchange, parent, false)
     58         return ExchangeItemViewHolder(view)
     59     }
     60 
     61     override fun getItemCount() = items.size
     62 
     63     override fun onBindViewHolder(holder: ExchangeItemViewHolder, position: Int) {
     64         holder.bind(items[position])
     65     }
     66 
     67     fun update(newItems: List<ExchangeItem>) {
     68         val oldItems = this.items
     69 
     70         val diffCallback = ExchangeDiffCallback(oldItems, newItems)
     71         val diffResult = DiffUtil.calculateDiff(diffCallback)
     72         diffResult.dispatchUpdatesTo(this)
     73 
     74         items = newItems
     75     }
     76 
     77     internal inner class ExchangeItemViewHolder(v: View) : RecyclerView.ViewHolder(v) {
     78         private val context = v.context
     79         private val urlView: TextView = v.findViewById(R.id.urlView)
     80         private val currencyView: TextView = v.findViewById(R.id.currencyView)
     81         private val overflowIcon: ImageButton = v.findViewById(R.id.overflowIcon)
     82 
     83         fun bind(item: ExchangeItem) {
     84             urlView.text = item.name
     85             // If currency is null, it's because we have no data from the exchange...
     86             currencyView.text = if (item.currency == null) {
     87                 context.getString(R.string.exchange_not_contacted)
     88             } else {
     89                 context.getString(R.string.exchange_list_currency, item.currency)
     90             }
     91             if (selectOnly) {
     92                 itemView.setOnClickListener { listener.onExchangeSelected(item) }
     93                 overflowIcon.visibility = GONE
     94             } else {
     95                 itemView.setOnClickListener(null)
     96                 itemView.isClickable = false
     97                 // ...thus, we should prevent the user from interacting with it.
     98                 overflowIcon.visibility = if (item.currency != null) VISIBLE else GONE
     99             }
    100             overflowIcon.setOnClickListener { openMenu(overflowIcon, item) }
    101         }
    102 
    103         private fun openMenu(anchor: View, item: ExchangeItem) = PopupMenu(context, anchor).apply {
    104             inflate(R.menu.exchange)
    105             if (item.tosStatus.isAccepted()) {
    106                 menu.findItem(R.id.action_view_tos).isVisible = true
    107                 menu.findItem(R.id.action_accept_tos).isVisible = false
    108                 menu.findItem(R.id.action_forget_tos).isVisible = devMode
    109             } else {
    110                 menu.findItem(R.id.action_view_tos).isVisible = false
    111                 menu.findItem(R.id.action_accept_tos).isVisible = true
    112                 menu.findItem(R.id.action_forget_tos).isVisible = false
    113             }
    114 
    115             if (item.scopeInfo is ScopeInfo.Exchange) {
    116                 menu.findItem(R.id.action_global_add).isVisible = devMode
    117                 menu.findItem(R.id.action_global_delete).isVisible = false
    118             } else if (item.scopeInfo is ScopeInfo.Global) {
    119                 menu.findItem(R.id.action_global_add).isVisible = false
    120                 menu.findItem(R.id.action_global_delete).isVisible = devMode
    121             }
    122 
    123             setOnMenuItemClickListener { menuItem ->
    124                 when (menuItem.itemId) {
    125                     R.id.action_manual_withdrawal -> {
    126                         listener.onManualWithdraw(item)
    127                         true
    128                     }
    129                     R.id.action_receive_peer -> {
    130                         listener.onPeerReceive(item)
    131                         true
    132                     }
    133                     R.id.action_reload -> {
    134                         listener.onExchangeReload(item)
    135                         true
    136                     }
    137                     R.id.action_view_tos -> {
    138                         listener.onExchangeTosView(item)
    139                         true
    140                     }
    141                     R.id.action_accept_tos -> {
    142                         listener.onExchangeTosAccept(item)
    143                         true
    144                     }
    145                     R.id.action_forget_tos -> {
    146                         listener.onExchangeTosForget(item)
    147                         true
    148                     }
    149                     R.id.action_global_add -> {
    150                         listener.onExchangeGlobalCurrencyAdd(item)
    151                         true
    152                     }
    153                     R.id.action_global_delete -> {
    154                         listener.onExchangeGlobalCurrencyDelete(item)
    155                         true
    156                     }
    157                     R.id.action_delete -> {
    158                         listener.onExchangeDelete(item)
    159                         true
    160                     }
    161                     else -> false
    162                 }
    163             }
    164             show()
    165         }
    166     }
    167 }
    168 
    169 internal class ExchangeDiffCallback(
    170     private val oldList: List<ExchangeItem>,
    171     private val newList: List<ExchangeItem>,
    172 ): DiffUtil.Callback() {
    173     override fun getOldListSize() = oldList.size
    174 
    175     override fun getNewListSize() = newList.size
    176 
    177     override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
    178         val old = oldList[oldItemPosition]
    179         val new = newList[newItemPosition]
    180 
    181         return old.exchangeBaseUrl == new.exchangeBaseUrl
    182     }
    183 
    184     override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
    185         val old = oldList[oldItemPosition]
    186         val new = newList[newItemPosition]
    187 
    188         return old == new
    189     }
    190 }