summaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2024-03-28 13:23:44 -0600
committerIván Ávalos <avalos@disroot.org>2024-03-28 13:23:44 -0600
commite33bc723687328eec69e7580dd3e5698d4679167 (patch)
treedf61aa442264d9b596ad7154610cdb344bb13bb1 /wallet/src/main/java/net
parentccc6b47f8daf6e07fbfdf91d9ac2b84313172968 (diff)
downloadtaler-android-e33bc723687328eec69e7580dd3e5698d4679167.tar.gz
taler-android-e33bc723687328eec69e7580dd3e5698d4679167.tar.bz2
taler-android-e33bc723687328eec69e7580dd3e5698d4679167.zip
[wallet] Make observability log atomic and improve dialog UI
bug 0008509
Diffstat (limited to 'wallet/src/main/java/net')
-rw-r--r--wallet/src/main/java/net/taler/wallet/MainViewModel.kt26
-rw-r--r--wallet/src/main/java/net/taler/wallet/events/ObservabilityDialog.kt61
-rw-r--r--wallet/src/main/java/net/taler/wallet/events/ObservabilityEvent.kt3
3 files changed, 61 insertions, 29 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index b4da875..4b53d15 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -24,6 +24,9 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import net.taler.common.Amount
@@ -57,6 +60,11 @@ private val transactionNotifications = listOf(
"transaction-state-transition",
)
+private val observabilityNotifications = listOf(
+ "task-observability-event",
+ "request-observability-event",
+)
+
class MainViewModel(
app: Application,
) : AndroidViewModel(app), VersionReceiver, NotificationReceiver {
@@ -89,8 +97,8 @@ class MainViewModel(
private val mTransactionsEvent = MutableLiveData<Event<ScopeInfo>>()
val transactionsEvent: LiveData<Event<ScopeInfo>> = mTransactionsEvent
- private val mObservabilityLog = MutableLiveData<List<ObservabilityEvent>>(emptyList())
- val observabilityLog: LiveData<List<ObservabilityEvent>> = mObservabilityLog
+ private val mObservabilityLog = MutableStateFlow<List<ObservabilityEvent>>(emptyList())
+ val observabilityLog: StateFlow<List<ObservabilityEvent>> = mObservabilityLog
private val mScanCodeEvent = MutableLiveData<Event<Boolean>>()
val scanCodeEvent: LiveData<Event<Boolean>> = mScanCodeEvent
@@ -113,14 +121,16 @@ class MainViewModel(
balanceManager.loadBalances()
}
- if (payload.type == "task-observability-event"
+ if (payload.type in observabilityNotifications
&& payload.event != null
&& devMode.value == true) {
- val logs = mObservabilityLog.value
- ?.takeLast(OBSERVABILITY_LIMIT)
- ?.toMutableList() ?: mutableListOf()
- logs.add(payload.event)
- mObservabilityLog.postValue(logs)
+ mObservabilityLog.getAndUpdate { logs ->
+ logs.takeLast(OBSERVABILITY_LIMIT)
+ .toMutableList().apply {
+ add(payload.event)
+ }
+
+ }
}
if (payload.type in transactionNotifications) viewModelScope.launch(Dispatchers.Main) {
diff --git a/wallet/src/main/java/net/taler/wallet/events/ObservabilityDialog.kt b/wallet/src/main/java/net/taler/wallet/events/ObservabilityDialog.kt
index eae5758..91733c3 100644
--- a/wallet/src/main/java/net/taler/wallet/events/ObservabilityDialog.kt
+++ b/wallet/src/main/java/net/taler/wallet/events/ObservabilityDialog.kt
@@ -20,31 +20,34 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
+import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.unit.dp
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import kotlinx.serialization.ExperimentalSerializationApi
@@ -52,8 +55,10 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import net.taler.wallet.MainViewModel
import net.taler.wallet.R
-import net.taler.wallet.compose.copyToClipBoard
+import net.taler.wallet.compose.CopyToClipboardButton
import net.taler.wallet.events.ObservabilityDialog.Companion.json
+import java.time.format.DateTimeFormatter
+import java.time.format.FormatStyle
class ObservabilityDialog: DialogFragment() {
private val model: MainViewModel by activityViewModels()
@@ -64,8 +69,8 @@ class ObservabilityDialog: DialogFragment() {
savedInstanceState: Bundle?
): View = ComposeView(requireContext()).apply {
setContent {
- val events by model.observabilityLog.observeAsState()
- ObservabilityComposable(events?.reversed() ?: emptyList()) {
+ val events by model.observabilityLog.collectAsState()
+ ObservabilityComposable(events.reversed()) {
dismiss()
}
}
@@ -122,24 +127,38 @@ fun ObservabilityItem(
val context = LocalContext.current
val title = event.getTitle(context)
val body = json.encodeToString(event.body)
+ val timestamp = DateTimeFormatter
+ .ofLocalizedDateTime(FormatStyle.MEDIUM)
+ .format(event.timestamp)
ListItem(
modifier = Modifier.fillMaxWidth(),
headlineContent = { Text(title) },
+ overlineContent = { Text(timestamp) },
supportingContent = if (!showJson) null else { ->
- Text(
- text = body,
- fontFamily = FontFamily.Monospace,
- style = MaterialTheme.typography.bodySmall,
- )
- },
- trailingContent = if(!showJson) null else { ->
- IconButton(onClick = {
- copyToClipBoard(context, "Event", body)
- }) {
- Icon(
- Icons.Default.ContentCopy,
- contentDescription = stringResource(R.string.copy),
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Box(
+ modifier = Modifier.background(
+ MaterialTheme.colorScheme.secondaryContainer,
+ shape = MaterialTheme.shapes.small,
+ )
+ ) {
+ Text(
+ modifier = Modifier
+ .padding(10.dp)
+ .fillMaxWidth(),
+ text = body,
+ fontFamily = FontFamily.Monospace,
+ style = MaterialTheme.typography.bodySmall,
+ )
+ }
+
+ CopyToClipboardButton(
+ label = "Event",
+ content = body,
+ colors = ButtonDefaults.textButtonColors(),
)
}
},
diff --git a/wallet/src/main/java/net/taler/wallet/events/ObservabilityEvent.kt b/wallet/src/main/java/net/taler/wallet/events/ObservabilityEvent.kt
index cb710f7..a726045 100644
--- a/wallet/src/main/java/net/taler/wallet/events/ObservabilityEvent.kt
+++ b/wallet/src/main/java/net/taler/wallet/events/ObservabilityEvent.kt
@@ -28,11 +28,13 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import net.taler.wallet.R
+import java.time.LocalDateTime
@Serializable(with = ObservabilityEventSerializer::class)
class ObservabilityEvent(
val body: JsonObject,
+ val timestamp: LocalDateTime,
val type: String,
) {
@@ -78,6 +80,7 @@ class ObservabilityEventSerializer: KSerializer<ObservabilityEvent> {
return ObservabilityEvent(
body = jsonObject,
+ timestamp = LocalDateTime.now(),
type = type,
)
}