summaryrefslogtreecommitdiff
path: root/wallet/src/main/java/net
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2024-03-27 13:54:19 -0600
committerIván Ávalos <avalos@disroot.org>2024-03-28 12:21:11 -0600
commitccc6b47f8daf6e07fbfdf91d9ac2b84313172968 (patch)
tree3987a4f3f8053ee5208ba38a44cdf8d149d15174 /wallet/src/main/java/net
parentc3c7cd00b6fd2110bc8ca6c36b4a561d9d3d0f2d (diff)
downloadtaler-android-ccc6b47f8daf6e07fbfdf91d9ac2b84313172968.tar.gz
taler-android-ccc6b47f8daf6e07fbfdf91d9ac2b84313172968.tar.bz2
taler-android-ccc6b47f8daf6e07fbfdf91d9ac2b84313172968.zip
[wallet] Improve observability UI and make it globally reachable from the toolbar
bug 0008509
Diffstat (limited to 'wallet/src/main/java/net')
-rw-r--r--wallet/src/main/java/net/taler/wallet/MainActivity.kt23
-rw-r--r--wallet/src/main/java/net/taler/wallet/MainViewModel.kt15
-rw-r--r--wallet/src/main/java/net/taler/wallet/events/ObservabilityDialog.kt82
3 files changed, 84 insertions, 36 deletions
diff --git a/wallet/src/main/java/net/taler/wallet/MainActivity.kt b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
index 5dfd920..80b26a5 100644
--- a/wallet/src/main/java/net/taler/wallet/MainActivity.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainActivity.kt
@@ -25,6 +25,7 @@ import android.content.IntentFilter
import android.net.Uri
import android.os.Bundle
import android.util.Log
+import android.view.Menu
import android.view.MenuItem
import android.view.View.GONE
import android.view.View.INVISIBLE
@@ -66,6 +67,7 @@ import net.taler.wallet.HostCardEmulatorService.Companion.MERCHANT_NFC_CONNECTED
import net.taler.wallet.HostCardEmulatorService.Companion.MERCHANT_NFC_DISCONNECTED
import net.taler.wallet.HostCardEmulatorService.Companion.TRIGGER_PAYMENT_ACTION
import net.taler.wallet.databinding.ActivityMainBinding
+import net.taler.wallet.events.ObservabilityDialog
import net.taler.wallet.refund.RefundStatus
import java.io.IOException
import java.net.HttpURLConnection
@@ -144,6 +146,10 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener,
model.networkManager.networkStatus.observe(this) { online ->
ui.content.offlineBanner.visibility = if (online) GONE else VISIBLE
}
+
+ model.devMode.observe(this) {
+ invalidateMenu()
+ }
}
@Deprecated("Deprecated in Java")
@@ -159,6 +165,14 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener,
}
}
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ if (model.devMode.value == true) {
+ menuInflater.inflate(R.menu.global_dev, menu)
+ }
+
+ return super.onCreateOptionsMenu(menu)
+ }
+
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_home -> nav.navigate(R.id.nav_main)
@@ -168,6 +182,15 @@ class MainActivity : AppCompatActivity(), OnNavigationItemSelectedListener,
return true
}
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.action_show_logs -> {
+ ObservabilityDialog().show(supportFragmentManager, "OBSERVABILITY")
+ }
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
override fun onDestroy() {
unregisterReceiver(triggerPaymentReceiver)
unregisterReceiver(nfcConnectedReceiver)
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index cd1fbac..b4da875 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -51,6 +51,7 @@ import net.taler.wallet.withdraw.WithdrawManager
import org.json.JSONObject
const val TAG = "taler-wallet"
+const val OBSERVABILITY_LIMIT = 100
private val transactionNotifications = listOf(
"transaction-state-transition",
@@ -88,8 +89,8 @@ class MainViewModel(
private val mTransactionsEvent = MutableLiveData<Event<ScopeInfo>>()
val transactionsEvent: LiveData<Event<ScopeInfo>> = mTransactionsEvent
- private val mObservabilityStream = MutableLiveData<Event<ObservabilityEvent>>()
- val observabilityStream: LiveData<Event<ObservabilityEvent>> = mObservabilityStream
+ private val mObservabilityLog = MutableLiveData<List<ObservabilityEvent>>(emptyList())
+ val observabilityLog: LiveData<List<ObservabilityEvent>> = mObservabilityLog
private val mScanCodeEvent = MutableLiveData<Event<Boolean>>()
val scanCodeEvent: LiveData<Event<Boolean>> = mScanCodeEvent
@@ -112,8 +113,14 @@ class MainViewModel(
balanceManager.loadBalances()
}
- if (payload.type == "task-observability-event" && payload.event != null) {
- mObservabilityStream.postValue(payload.event.toEvent())
+ if (payload.type == "task-observability-event"
+ && payload.event != null
+ && devMode.value == true) {
+ val logs = mObservabilityLog.value
+ ?.takeLast(OBSERVABILITY_LIMIT)
+ ?.toMutableList() ?: mutableListOf()
+ logs.add(payload.event)
+ mObservabilityLog.postValue(logs)
}
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 9164e77..eae5758 100644
--- a/wallet/src/main/java/net/taler/wallet/events/ObservabilityDialog.kt
+++ b/wallet/src/main/java/net/taler/wallet/events/ObservabilityDialog.kt
@@ -27,14 +27,19 @@ 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.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.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
@@ -42,18 +47,16 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.getAndUpdate
+import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.encodeToString
-import net.taler.common.EventObserver
+import kotlinx.serialization.json.Json
import net.taler.wallet.MainViewModel
import net.taler.wallet.R
-import net.taler.wallet.backend.BackendManager
import net.taler.wallet.compose.copyToClipBoard
+import net.taler.wallet.events.ObservabilityDialog.Companion.json
class ObservabilityDialog: DialogFragment() {
private val model: MainViewModel by activityViewModels()
- private val eventsFlow: MutableStateFlow<List<ObservabilityEvent>> = MutableStateFlow(emptyList())
override fun onCreateView(
inflater: LayoutInflater,
@@ -61,22 +64,19 @@ class ObservabilityDialog: DialogFragment() {
savedInstanceState: Bundle?
): View = ComposeView(requireContext()).apply {
setContent {
- val events by eventsFlow.collectAsState()
- ObservabilityComposable(events = events) {
+ val events by model.observabilityLog.observeAsState()
+ ObservabilityComposable(events?.reversed() ?: emptyList()) {
dismiss()
}
}
}
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- model.observabilityStream.observe(viewLifecycleOwner, EventObserver { event ->
- eventsFlow.getAndUpdate {
- it.toMutableList().apply {
- add(0, event)
- }.toList()
- }
- })
+ companion object {
+ @OptIn(ExperimentalSerializationApi::class)
+ val json = Json {
+ prettyPrint = true
+ prettyPrintIndent = " "
+ }
}
}
@@ -85,45 +85,63 @@ fun ObservabilityComposable(
events: List<ObservabilityEvent>,
onDismiss: () -> Unit,
) {
+ var showJson by remember { mutableStateOf(false) }
+
AlertDialog(
title = { Text(stringResource(R.string.observability_title)) },
text = {
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(events) { event ->
- ObservabilityItem(event)
+ ObservabilityItem(event, showJson)
}
}
},
onDismissRequest = onDismiss,
- confirmButton = {},
dismissButton = {
+ Button(onClick = { showJson = !showJson }) {
+ Text(if (showJson) {
+ stringResource(R.string.observability_hide_json)
+ } else {
+ stringResource(R.string.observability_show_json)
+ })
+ }
+ },
+ confirmButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.close))
}
- }
+ },
)
}
@Composable
-fun ObservabilityItem(event: ObservabilityEvent) {
+fun ObservabilityItem(
+ event: ObservabilityEvent,
+ showJson: Boolean,
+) {
val context = LocalContext.current
val title = event.getTitle(context)
- val body = BackendManager.json.encodeToString(event.body)
+ val body = json.encodeToString(event.body)
ListItem(
modifier = Modifier.fillMaxWidth(),
headlineContent = { Text(title) },
- supportingContent = { Text(body, fontFamily = FontFamily.Monospace) },
- trailingContent = {
- IconButton(
- content = { Icon(
+ 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),
- ) },
- onClick = {
- copyToClipBoard(context, "Event", body)
- }
- )
- }
+ )
+ }
+ },
)
} \ No newline at end of file