Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Open sidebar
deBeauvoir
samourai-wallet-android
Commits
292c0958
Verified
Commit
292c0958
authored
Dec 01, 2021
by
Sarath
⚔
Browse files
MixTxAdapter for whirlpool transactions list
parent
358472c9
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
334 additions
and
0 deletions
+334
-0
app/src/main/java/com/samourai/wallet/whirlpool/adapters/MixTxAdapter.kt
...va/com/samourai/wallet/whirlpool/adapters/MixTxAdapter.kt
+334
-0
No files found.
app/src/main/java/com/samourai/wallet/whirlpool/adapters/MixTxAdapter.kt
0 → 100644
View file @
292c0958
package
com.samourai.wallet.whirlpool.adapters
import
android.content.Context
import
android.text.format.DateUtils
import
android.transition.ChangeBounds
import
android.transition.TransitionManager
import
android.util.Log
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
android.widget.ImageView
import
android.widget.LinearLayout
import
android.widget.TextView
import
androidx.core.content.ContextCompat
import
androidx.recyclerview.widget.AsyncListDiffer
import
androidx.recyclerview.widget.DiffUtil
import
androidx.recyclerview.widget.RecyclerView
import
com.samourai.wallet.R
import
com.samourai.wallet.api.Tx
import
com.samourai.wallet.bip47.BIP47Meta
import
com.samourai.wallet.send.BlockedUTXO
import
com.samourai.wallet.util.FormatsUtil
import
com.samourai.wallet.util.PrefsUtil
import
io.reactivex.Observable
import
io.reactivex.android.schedulers.AndroidSchedulers
import
io.reactivex.disposables.CompositeDisposable
import
io.reactivex.schedulers.Schedulers
import
org.json.JSONObject
import
java.text.SimpleDateFormat
import
java.util.*
class
MixTxAdapter
(
private
val
mContext
:
Context
)
:
RecyclerView
.
Adapter
<
MixTxAdapter
.
TxViewHolder
>()
{
private
val
VIEW_ITEM
=
1
private
var
postMixTxs
:
List
<
Tx
>
=
listOf
()
private
var
preMixTxs
:
List
<
Tx
>
=
listOf
()
private
val
VIEW_SECTION
=
0
private
val
disposables
=
CompositeDisposable
()
private
var
listener
:
((
tx
:
Tx
)->
Unit
)?
=
null
private
val
mDiffer
=
AsyncListDiffer
(
this
,
DIFF_CALLBACK
)
private
val
fmt
=
SimpleDateFormat
(
"dd MMM yyyy"
,
Locale
.
getDefault
())
interface
OnClickListener
{
fun
onClick
(
position
:
Int
,
tx
:
Tx
?)
}
fun
setClickListener
(
listener
:((
tx
:
Tx
)->
Unit
)?)
{
this
.
listener
=
listener
}
override
fun
onDetachedFromRecyclerView
(
recyclerView
:
RecyclerView
)
{
disposables
.
dispose
()
super
.
onDetachedFromRecyclerView
(
recyclerView
)
}
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
TxViewHolder
{
val
view
:
View
=
if
(
viewType
==
VIEW_ITEM
)
{
LayoutInflater
.
from
(
parent
.
context
)
.
inflate
(
R
.
layout
.
tx_item_layout_
,
parent
,
false
)
}
else
{
LayoutInflater
.
from
(
parent
.
context
)
.
inflate
(
R
.
layout
.
tx_item_section_layout
,
parent
,
false
)
}
return
TxViewHolder
(
view
,
viewType
)
}
override
fun
onBindViewHolder
(
holder
:
TxViewHolder
,
position
:
Int
)
{
val
is_sat_prefs
=
PrefsUtil
.
getInstance
(
mContext
).
getValue
(
PrefsUtil
.
IS_SAT
,
false
)
val
tx
=
mDiffer
.
currentList
[
position
]
val
isPremix
=
this
.
preMixTxs
.
contains
(
tx
)
if
(
tx
!!
.
section
==
null
)
{
var
_amount
=
0L
_amount
=
if
(
tx
.
amount
<
0.0
)
{
Math
.
abs
(
tx
.
amount
.
toLong
())
}
else
{
tx
.
amount
.
toLong
()
}
val
sdf
=
SimpleDateFormat
(
"H:mm"
,
Locale
.
US
)
sdf
.
timeZone
=
TimeZone
.
getDefault
()
holder
.
tvDateView
!!
.
text
=
sdf
.
format
(
tx
.
ts
*
1000L
)
if
(
tx
.
paymentCode
!=
null
)
{
holder
.
txSubText
!!
.
visibility
=
View
.
VISIBLE
holder
.
txSubText
!!
.
text
=
BIP47Meta
.
getInstance
().
getDisplayLabel
(
tx
.
paymentCode
)
}
else
{
holder
.
txSubText
!!
.
visibility
=
View
.
GONE
}
if
(
listener
!=
null
)
holder
.
itemView
.
setOnClickListener
{
view
:
View
?
->
listener
?.
invoke
(
tx
)
}
if
(
tx
.
amount
<
0.0
)
{
holder
.
tvDirection
!!
.
setImageDrawable
(
ContextCompat
.
getDrawable
(
mContext
,
R
.
drawable
.
out_going_tx_whtie_arrow
)
)
holder
.
tvAmount
!!
.
setTextColor
(
ContextCompat
.
getColor
(
mContext
,
R
.
color
.
white
))
holder
.
tvAmount
!!
.
text
=
"-"
+
if
(
is_sat_prefs
)
FormatsUtil
.
formatSats
(
_amount
)
else
FormatsUtil
.
formatBTC
(
_amount
)
holder
.
txSubText
!!
.
visibility
=
View
.
VISIBLE
holder
.
txSubText
!!
.
setText
(
R
.
string
.
postmix_spend
)
}
else
{
TransitionManager
.
beginDelayedTransition
(
holder
.
tvAmount
!!
.
rootView
as
ViewGroup
,
ChangeBounds
()
)
holder
.
tvDirection
!!
.
setImageDrawable
(
ContextCompat
.
getDrawable
(
mContext
,
R
.
drawable
.
incoming_tx_green
)
)
val
amount
=
if
(
is_sat_prefs
)
FormatsUtil
.
formatSats
(
_amount
)
else
FormatsUtil
.
formatBTC
(
_amount
)
holder
.
tvAmount
!!
.
text
=
amount
holder
.
tvAmount
!!
.
setTextColor
(
ContextCompat
.
getColor
(
mContext
,
R
.
color
.
green_ui_2
))
if
(
_amount
==
0L
)
{
holder
.
txSubText
!!
.
visibility
=
View
.
VISIBLE
holder
.
txSubText
!!
.
setText
(
R
.
string
.
remix_note_tag
)
}
else
if
(
BlockedUTXO
.
BLOCKED_UTXO_THRESHOLD
>=
_amount
)
{
holder
.
txSubText
!!
.
visibility
=
View
.
VISIBLE
holder
.
txSubText
!!
.
setText
(
R
.
string
.
dust
)
}
else
{
if
(!
isPremix
)
{
holder
.
txSubText
!!
.
visibility
=
View
.
VISIBLE
holder
.
txSubText
!!
.
setText
(
R
.
string
.
mixed
)
holder
.
tvDirection
!!
.
setImageDrawable
(
ContextCompat
.
getDrawable
(
mContext
,
R
.
drawable
.
ic_whirlpool
)
)
}
else
{
holder
.
txSubText
?.
visibility
=
View
.
VISIBLE
holder
.
txSubText
?.
text
=
holder
.
txSubText
?.
context
?.
getString
(
R
.
string
.
transfer_to_whirlpool
)
holder
.
tvDirection
?.
setImageDrawable
(
ContextCompat
.
getDrawable
(
mContext
,
R
.
drawable
.
incoming_tx_green
)
)
}
}
}
if
(!
isPremix
&&
_amount
==
0L
)
holder
.
tvDirection
!!
.
setImageDrawable
(
ContextCompat
.
getDrawable
(
mContext
,
R
.
drawable
.
ic_repeat_24dp
)
)
holder
.
txNoteGroup
!!
.
visibility
=
View
.
GONE
}
else
{
val
date
=
Date
(
tx
.
ts
)
if
(
tx
.
ts
==
-
1L
)
{
holder
.
tvSection
!!
.
text
=
holder
.
itemView
.
context
.
getString
(
R
.
string
.
pending
)
holder
.
tvSection
!!
.
setTextColor
(
ContextCompat
.
getColor
(
holder
.
itemView
.
context
,
R
.
color
.
white
)
)
}
else
{
holder
.
tvSection
!!
.
setTextColor
(
ContextCompat
.
getColor
(
holder
.
tvSection
!!
.
context
,
R
.
color
.
text_primary
)
)
if
(
DateUtils
.
isToday
(
tx
.
ts
))
{
holder
.
tvSection
!!
.
text
=
holder
.
itemView
.
context
.
getString
(
R
.
string
.
timeline_today
)
}
else
{
holder
.
tvSection
!!
.
text
=
fmt
.
format
(
date
)
}
}
}
}
override
fun
getItemCount
():
Int
{
return
mDiffer
.
currentList
.
size
}
override
fun
getItemViewType
(
position
:
Int
):
Int
{
return
if
(
mDiffer
.
currentList
[
position
]
!!
.
section
!=
null
)
VIEW_SECTION
else
VIEW_ITEM
}
fun
setTx
(
postMix
:
List
<
Tx
>,
premix
:
List
<
Tx
>)
{
this
.
postMixTxs
=
postMix
;
this
.
preMixTxs
=
premix
;
val
list
=
arrayListOf
<
Tx
>()
list
.
addAll
(
postMix
)
list
.
addAll
(
premix
)
updateList
(
list
)
}
private
fun
updateList
(
txes
:
List
<
Tx
>)
{
val
disposable
=
makeSectionedDataSet
(
txes
)
.
subscribeOn
(
Schedulers
.
computation
())
.
observeOn
(
AndroidSchedulers
.
mainThread
())
.
subscribe
{
newList
:
List
<
Tx
?
>?
->
mDiffer
.
submitList
(
newList
)
}
disposables
.
add
(
disposable
)
}
inner
class
TxViewHolder
(
itemView
:
View
,
viewType
:
Int
)
:
RecyclerView
.
ViewHolder
(
itemView
)
{
var
tvSection
:
TextView
?
=
null
var
tvDateView
:
TextView
?
=
null
var
tvAmount
:
TextView
?
=
null
var
txSubText
:
TextView
?
=
null
var
tvNoteView
:
TextView
?
=
null
var
tvDirection
:
ImageView
?
=
null
var
txNoteGroup
:
LinearLayout
?
=
null
init
{
if
(
viewType
==
VIEW_SECTION
)
{
tvSection
=
itemView
.
findViewById
(
R
.
id
.
section_title
)
}
else
{
tvDateView
=
itemView
.
findViewById
(
R
.
id
.
tx_time
)
tvDirection
=
itemView
.
findViewById
(
R
.
id
.
TransactionDirection
)
tvAmount
=
itemView
.
findViewById
(
R
.
id
.
tvAmount
)
txSubText
=
itemView
.
findViewById
(
R
.
id
.
txSubText
)
txNoteGroup
=
itemView
.
findViewById
(
R
.
id
.
tx_note_group
)
tvNoteView
=
itemView
.
findViewById
(
R
.
id
.
tx_note_view
)
}
}
}
@Synchronized
private
fun
makeSectionedDataSet
(
txes
:
List
<
Tx
>):
Observable
<
List
<
Tx
?
>>
{
return
Observable
.
fromCallable
{
Collections
.
sort
(
txes
)
{
tx
:
Tx
,
t1
:
Tx
->
java
.
lang
.
Long
.
compare
(
tx
.
ts
,
t1
.
ts
)
}
val
sectionDates
=
ArrayList
<
Long
>()
val
sectioned
:
MutableList
<
Tx
?
>
=
ArrayList
()
// for pending state
var
contains_pending
=
false
var
containsNonPendingTxForTodaySection
=
false
for
(
i
in
txes
.
indices
)
{
val
tx
=
txes
[
i
]
if
(
tx
.
confirmations
<
MAX_CONFIRM_COUNT
)
{
contains_pending
=
true
}
if
(
tx
.
confirmations
>=
MAX_CONFIRM_COUNT
&&
DateUtils
.
isToday
(
tx
.
ts
*
1000
))
{
containsNonPendingTxForTodaySection
=
true
}
}
for
(
tx
in
txes
)
{
val
date
=
Date
()
date
.
time
=
tx
.
ts
*
1000
val
calendarDM
=
Calendar
.
getInstance
()
calendarDM
.
timeZone
=
TimeZone
.
getDefault
()
calendarDM
.
time
=
date
calendarDM
[
Calendar
.
HOUR_OF_DAY
]
=
0
calendarDM
[
Calendar
.
MINUTE
]
=
0
calendarDM
[
Calendar
.
SECOND
]
=
0
calendarDM
[
Calendar
.
MILLISECOND
]
=
0
if
(!
sectionDates
.
contains
(
calendarDM
.
time
.
time
))
{
if
(
DateUtils
.
isToday
(
calendarDM
.
time
.
time
))
{
if
(
containsNonPendingTxForTodaySection
)
{
sectionDates
.
add
(
calendarDM
.
time
.
time
)
}
}
else
{
sectionDates
.
add
(
calendarDM
.
time
.
time
)
}
}
}
sectionDates
.
sortWith
{
x
:
Long
,
y
:
Long
->
(
x
).
compareTo
(
y
)
}
if
(
contains_pending
)
sectionDates
.
add
(-
1L
)
for
(
key
in
sectionDates
)
{
val
section
=
Tx
(
JSONObject
())
if
(
key
!=
-
1L
)
{
section
.
section
=
Date
(
key
).
toString
()
}
else
{
section
.
section
=
mContext
.
getString
(
R
.
string
.
pending
)
}
section
.
ts
=
key
for
(
tx
in
txes
)
{
val
date
=
Date
()
date
.
time
=
tx
.
ts
*
1000
val
fmt
=
SimpleDateFormat
(
"yyyyMMdd"
,
Locale
.
ENGLISH
)
fmt
.
timeZone
=
TimeZone
.
getDefault
()
if
(
key
==
-
1L
)
{
if
(
tx
.
confirmations
<
MAX_CONFIRM_COUNT
)
{
sectioned
.
add
(
tx
)
}
}
else
if
(
fmt
.
format
(
key
)
==
fmt
.
format
(
date
))
{
if
(
tx
.
confirmations
>=
MAX_CONFIRM_COUNT
)
{
sectioned
.
add
(
tx
)
}
}
}
sectioned
.
add
(
section
)
}
sectioned
.
reverse
()
sectioned
}
}
companion
object
{
private
const
val
MAX_CONFIRM_COUNT
=
3
val
DIFF_CALLBACK
:
DiffUtil
.
ItemCallback
<
Tx
?
>
=
object
:
DiffUtil
.
ItemCallback
<
Tx
?
>()
{
override
fun
areItemsTheSame
(
oldItem
:
Tx
,
newItem
:
Tx
):
Boolean
{
return
oldItem
.
ts
==
newItem
.
ts
}
override
fun
areContentsTheSame
(
oldItem
:
Tx
,
newItem
:
Tx
):
Boolean
{
if
(
oldItem
.
section
!=
null
||
newItem
.
section
!=
null
)
{
return
true
}
var
reRender
=
false
if
(
oldItem
.
confirmations
!=
newItem
.
confirmations
)
{
reRender
=
true
}
if
(
oldItem
.
hash
!=
newItem
.
hash
)
{
reRender
=
true
}
return
reRender
}
}
}
init
{
fmt
.
timeZone
=
TimeZone
.
getDefault
()
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment