Refactor relay status tracking and update quartz to 1.05.1

- Upgrade `quartz` dependency from 1.04.2 to 1.05.1.
- Refactor `AmberRelayStats` to use `combine` on `availableRelaysFlow` and `connectedRelaysFlow` instead of `relayStatusFlow`.
- Move notification update logic directly into the `relayStatus` flow collection.
- Update `AmberTopAppBar`, `EditRelaysDialog`, and `MainScreen` to consume the updated relay flow structures.
- Remove unused `addReceived` method and `CoroutineScope` parameter from `AmberRelayStats`.
This commit is contained in:
greenart7c3
2026-01-09 09:04:35 -03:00
parent a131098f03
commit 8a8358c71b
6 changed files with 36 additions and 38 deletions
@@ -91,7 +91,7 @@ class Amber :
val client: NostrClient = NostrClient(factory, applicationIOScope)
val stats = AmberRelayStats(client, applicationIOScope, this)
val stats = AmberRelayStats(client, this)
// logs and stat counts.
val listener = NostrClientLoggerListener(this, stats, applicationIOScope).also {
@@ -1,6 +1,7 @@
package com.greenart7c3.nostrsigner.relays
import android.Manifest
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent
@@ -20,20 +21,38 @@ import com.greenart7c3.nostrsigner.service.KillSwitchReceiver
import com.greenart7c3.nostrsigner.service.ReconnectReceiver
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
class AmberRelayStats(
client: NostrClient,
scope: CoroutineScope,
val appContext: Context,
) {
var oldMessage = ""
val relayStatus = client.relayStatusFlow()
var available = emptySet<NormalizedRelayUrl>()
var connected = emptySet<NormalizedRelayUrl>()
@OptIn(FlowPreview::class)
@SuppressLint("MissingPermission")
val relayStatus = combine(client.availableRelaysFlow(), client.connectedRelaysFlow()) { available, connected ->
available to connected
}.debounce(300).onEach {
this.available = it.first
this.connected = it.second
val notificationManager = NotificationManagerCompat.from(appContext)
if (ActivityCompat.checkSelfPermission(appContext, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
createNotification(
it.second,
it.first,
false,
)?.let { notification ->
Log.d(Amber.TAG, "updateNotification")
notificationManager.notify(2, notification)
}
}
}
lateinit var group: NotificationChannelGroupCompat
lateinit var channel: NotificationChannelCompat
@@ -72,26 +91,8 @@ class AmberRelayStats(
notificationManager.createNotificationChannel(statusChannel)
}
@OptIn(FlowPreview::class)
val relayStatusUpdater = client.relayStatusFlow().debounce(300).onEach {
try {
updateNotification()
} catch (_: NullPointerException) {
}
}.stateIn(
scope,
SharingStarted.Eagerly,
relayStatus.value,
)
private val innerCache = mutableMapOf<NormalizedRelayUrl, AmberRelayStat>()
fun createNotification(forceCreate: Boolean = false) = createNotification(
relayStatus.value.connected,
relayStatus.value.available,
forceCreate,
)
fun createForegroundNotification(): Notification {
val contentIntent = Intent(appContext, MainActivity::class.java)
contentIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
@@ -189,7 +190,10 @@ class AmberRelayStats(
fun updateNotification() {
val notificationManager = NotificationManagerCompat.from(appContext)
if (ActivityCompat.checkSelfPermission(appContext, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
createNotification()?.let {
createNotification(
connected,
available,
)?.let {
Log.d(Amber.TAG, "updateNotification")
notificationManager.notify(2, it)
}
@@ -203,11 +207,6 @@ class AmberRelayStats(
updateNotification()
}
fun addReceived(url: NormalizedRelayUrl) {
get(url).addReceived()
updateNotification()
}
fun addFailed(url: NormalizedRelayUrl) {
get(url).addFailed()
updateNotification()
@@ -110,7 +110,7 @@ private fun askNotificationPermission(
@SuppressLint("BatteryLife")
fun requestIgnoreBatteryOptimizations(context: Context) {
if (BuildFlavorChecker.isOfflineFlavor()) return
if (Amber.instance.client.relayStatusFlow().value.connected.isEmpty()) return
if (Amber.instance.client.connectedRelaysFlow().value.isEmpty()) return
val packageName = context.packageName
val pm = context.getSystemService(PowerManager::class.java)
if (!pm.isIgnoringBatteryOptimizations(packageName) && !LocalPreferences.getBatteryOptimization(context)) {
@@ -547,9 +547,9 @@ fun ActiveRelaysScreen(
Column(
verticalArrangement = Arrangement.Center,
) {
val isConnected by Amber.instance.client.relayStatusFlow().map { status ->
relay in status.connected
}.collectAsStateWithLifecycle(relay in Amber.instance.client.relayStatusFlow().value.connected)
val isConnected by Amber.instance.client.connectedRelaysFlow().map { status ->
relay in status
}.collectAsStateWithLifecycle(relay in Amber.instance.client.connectedRelaysFlow().value)
Text(
modifier = Modifier.padding(top = 16.dp),
@@ -5,7 +5,6 @@ import android.graphics.drawable.Drawable
import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Shield
import androidx.compose.material3.CenterAlignedTopAppBar
@@ -91,8 +90,8 @@ fun AmberTopAppBar(
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
val relayStats = Amber.instance.client.relayStatusFlow().collectAsStateWithLifecycle()
Text("${relayStats.value.connected.size}/${relayStats.value.available.size}")
val relayStats = Amber.instance.stats.relayStatus.collectAsStateWithLifecycle(Pair(emptySet(), emptySet()))
Text("${relayStats.value.second.size}/${relayStats.value.first.size}")
Icon(
imageVector = ImageVector.vectorResource(R.drawable.relays),
contentDescription = context.getString(R.string.reconnect),
+1 -1
View File
@@ -12,7 +12,7 @@ junitVersion = "1.3.0"
lifecycle_version = "2.10.0"
material3 = "1.4.0"
nav_version = "2.9.6"
quartz = "1.04.2"
quartz = "1.05.1"
compose_ui = "1.10.0"
richtextUi = "e1151c8"
roomKtx = "2.8.4"