Skip to content

Commit

Permalink
feat: update tx list with observeTransactions, improve contact support (
Browse files Browse the repository at this point in the history
#1331)

* feat: update tx list with observeTransactions

* fix: improve WalletBalanceObserver

* fix: remove update functions from TransactionRowView

* fix: use TransactionRowViewList

* fix: improve TX details

* fix: more improvements to MainViewModel

* fix: problems showing Tx details and going to home screen afterwards

* fix: always submit a new list for the UI

* fix: add reset listener

* fix: batch updates

* fix: replace batch updates method and only process tx confidence changes for the past hour of tx's

* fix: update dashj to 21.1.5-SNAPSHOT

* chore: refactor telephony manager usage

* chore: upgrade gradle & AGP

* fix: optimize contact support report and change wifi warning(#1333)

* feat: add ContactSupportDialogFragment and ViewModel

* feat: use ContactSupportDialogFragment

* fix: improve wallet dump

* fix: sort logFiles by most recent date first, then limit to 20MB

* fix: disable auto logout when creating report

* chore: remove ReportIssueDialogBuilder

* fix: update wifi warning for mixing fees (#1334)

* fix: mixing icon and row view id type

* chore: upgrade kotlin & ksp to fix deadlock

* feat: performance, uncoupling metadata & contacts

* fix: confirmation dialog UI with contact

* fix: observing contacts bugs

* fix: send to contact from send tab

* fix: sticky info panel on EnterAmountFragment

* fix: more proguard rules

* fix: log date format attempted fix

* fix: attempting to fix log date format

* fix: add logback to proguard

* fix: proper isComplete check for CrowdNode tx set

* fix: change the way topup tx observed for CrowdNode

* fix: build error - missing file

* fix: proguard fixes

* fix: check if identity is null in observeContacts

---------

Co-authored-by: Andrei Ashikhmin <[email protected]>
  • Loading branch information
HashEngineering and Syn-McJ authored Jan 16, 2025
1 parent dd8dd7b commit 2bbfb45
Show file tree
Hide file tree
Showing 66 changed files with 2,005 additions and 1,135 deletions.
12 changes: 6 additions & 6 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
buildscript {
ext {
kotlin_version = '1.9.23'
kotlin_version = '1.9.24'
coroutinesVersion = '1.6.4'
ok_http_version = '4.9.1'
dashjVersion = '21.1.4'
dashjVersion = '21.1.5-SNAPSHOT'
dppVersion = "1.7.0-SNAPSHOT"
hiltVersion = '2.51'
hiltCompilerVersion = '1.2.0'
Expand Down Expand Up @@ -52,10 +52,10 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:7.2.2'
classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.android.tools.build:gradle:8.7.3'
classpath 'com.google.gms:google-services:4.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2' // Crashlytics
classpath 'com.google.firebase:firebase-crashlytics-gradle:3.0.2' // Crashlytics
classpath "com.google.dagger:hilt-android-gradle-plugin:$hiltVersion"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1"
Expand All @@ -64,7 +64,7 @@ buildscript {
}

plugins {
id 'com.google.devtools.ksp' version '1.9.23-1.0.19' apply false
id 'com.google.devtools.ksp' version '1.9.24-1.0.20' apply false
}

allprojects {
Expand Down
2 changes: 1 addition & 1 deletion common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.11"
kotlinCompilerExtensionVersion = "1.5.14"
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ interface WalletDataProvider {

fun observeWalletChanged(): Flow<Unit>

fun observeWalletReset(): Flow<Unit>

fun observeBalance(
balanceType: Wallet.BalanceType = Wallet.BalanceType.ESTIMATED,
coinSelector: CoinSelector? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,4 @@ class TransactionComparator: Comparator<Transaction> {

return tx1.txId.compareTo(tx2.txId)
}
}

class TransactionWrapperComparator: Comparator<TransactionWrapper> {
private val txComparator = TransactionComparator()

override fun compare(wrapper1: TransactionWrapper, wrapper2: TransactionWrapper): Int {
return txComparator.compare(wrapper1.transactions.last(), wrapper2.transactions.last())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.dash.wallet.common.transactions

import kotlinx.coroutines.suspendCancellableCoroutine
import org.bitcoinj.core.Transaction
import org.bitcoinj.core.TransactionConfidence
import org.bitcoinj.utils.Threading
import org.dash.wallet.common.transactions.filters.TransactionFilter
import kotlin.coroutines.resume

suspend fun Transaction.waitToMatchFilters(vararg filters: TransactionFilter) {
return suspendCancellableCoroutine { continuation ->
var transactionConfidenceListener: TransactionConfidence.Listener? = null
transactionConfidenceListener = TransactionConfidence.Listener { _, _ ->
if (filters.isEmpty() || filters.any { it.matches(this) }) {
confidence.removeEventListener(transactionConfidenceListener)
continuation.resume(Unit)
}
}

// Check if already matches
if (filters.isEmpty() || filters.any { it.matches(this) }) {
continuation.resume(Unit)
return@suspendCancellableCoroutine
}

this.confidence.addEventListener(Threading.USER_THREAD, transactionConfidenceListener)

continuation.invokeOnCancellation {
confidence.removeEventListener(transactionConfidenceListener)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

@file:OptIn(FlowPreview::class)

package org.dash.wallet.common.transactions

import android.util.Log
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import org.bitcoinj.core.Address
import org.bitcoinj.core.Sha256Hash
import org.bitcoinj.core.Transaction
import org.bitcoinj.core.TransactionBag
import org.bitcoinj.script.ScriptException
import java.util.concurrent.ConcurrentHashMap
import org.bitcoinj.script.ScriptPattern

object TransactionUtils {
Expand Down Expand Up @@ -135,4 +146,21 @@ object TransactionUtils {
}
return result
}
}
}

fun Flow<Transaction>.batchAndFilterUpdates(timeInterval: Long = 500): Flow<List<Transaction>> {
val latestTransactions = ConcurrentHashMap<Sha256Hash, Transaction>()

return this
.onEach { transaction ->
// Update the latest transaction for the hash
latestTransactions[transaction.txId] = transaction
}
.sample(timeInterval) // Emit events every [timeInterval]
.map {
latestTransactions.values.toList().also {
latestTransactions.clear()
}
}
.filter { it.isNotEmpty() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@
package org.dash.wallet.common.transactions

import org.bitcoinj.core.Coin
import org.bitcoinj.core.Sha256Hash
import org.bitcoinj.core.Transaction
import org.bitcoinj.core.TransactionBag
import java.time.LocalDate

interface TransactionWrapper {
val transactions: Set<Transaction>
val id: String
val transactions: HashMap<Sha256Hash, Transaction>
val groupDate: LocalDate
fun tryInclude(tx: Transaction): Boolean
fun getValue(bag: TransactionBag): Coin
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package org.dash.wallet.common.transactions
import org.bitcoinj.core.Transaction

interface TransactionWrapperFactory {
fun tryInclude(tx: Transaction): Pair<Boolean, TransactionWrapper?>
val averageTransactions: Long
val wrappers: List<TransactionWrapper>
fun tryInclude(tx: Transaction): Pair<Boolean, TransactionWrapper?>
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,21 @@ package org.dash.wallet.common.transactions.filters
import org.bitcoinj.core.Sha256Hash
import org.bitcoinj.core.Transaction
import org.bitcoinj.core.TransactionConfidence
import org.dash.wallet.common.transactions.filters.TransactionFilter

class LockedTransaction(private val topUpTxId: Sha256Hash): TransactionFilter {
class LockedTransaction(private val topUpTxId: Sha256Hash? = null): TransactionFilter {
constructor() : this(null)

override fun matches(tx: Transaction): Boolean {
val confidence = tx.confidence
val type = confidence.confidenceType
val isLocked = confidence.isTransactionLocked ||
type == TransactionConfidence.ConfidenceType.BUILDING ||
(type == TransactionConfidence.ConfidenceType.PENDING && confidence.numBroadcastPeers() > 1)

return tx.txId == topUpTxId && isLocked
return if (topUpTxId != null) {
tx.txId == topUpTxId && isLocked
} else {
isLocked
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -297,5 +297,6 @@ class EnterAmountFragment : Fragment(R.layout.fragment_enter_amount) {

fun setMessage(message: String) {
binding.messageText.text = message
binding.messageText.isVisible = message.isNotEmpty()
}
}
29 changes: 29 additions & 0 deletions common/src/main/java/org/dash/wallet/common/util/FlowExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.AbstractFlow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlin.time.Duration

Expand Down Expand Up @@ -41,3 +42,31 @@ fun <T> Flow<T>.observe(lifecycleOwner: LifecycleOwner, collector: FlowCollector
}
}
}

/** from ChatGPT */
fun <T> Flow<T>.window(intervalMillis: Long): Flow<List<T>> = flow {
val buffer = mutableListOf<T>()
val lock = Any()
var lastEmitTime = System.currentTimeMillis()

this@window.collect { value ->
var batchToEmit: List<T>? = null

synchronized(lock) {
buffer.add(value)
val currentTime = System.currentTimeMillis()
if (currentTime - lastEmitTime >= intervalMillis) {
batchToEmit = buffer.toList()
buffer.clear()
lastEmitTime = currentTime
}
}

batchToEmit?.let { emit(it) }
}

val finalBatch = synchronized(lock) {
if (buffer.isNotEmpty()) buffer.toList() else null
}
finalBatch?.let { emit(it) }
}
1 change: 1 addition & 0 deletions common/src/main/res/layout/fragment_enter_amount.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
android:layout_marginHorizontal="20dp"
android:paddingHorizontal="8dp"
android:gravity="center_horizontal"
android:visibility="gone"
android:background="@drawable/gray_button_background"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
Expand Down
6 changes: 6 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx4G
org.gradle.daemon=true
org.gradle.parallel=true
kotlin.incremental=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 3 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#Mon Oct 02 18:25:36 ICT 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit 2bbfb45

Please sign in to comment.