mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 08:04:45 +00:00
feat(notifications): open the subscriptions screen from the ongoing notification
Tapping the always-on notification landed on whatever tab was last open, which does not answer the question that notification raises. It now deep-links to Active Relay Subscriptions via an `activesubs` route, and the screen gets its own entry in All Settings. The expanded breakdown also held its last value across reconnects. It is derived from the *connected* relays, so a drop to zero — the "connecting" state — emptied it and collapsed the expanded view to a single line exactly when someone was most likely reading it. What each connection is for does not change while it re-establishes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0ad4726d41
commit
5f6d09425d
+21
-2
@@ -36,6 +36,7 @@ import android.os.SystemClock
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.ServiceCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.LocalPreferences
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -79,6 +80,10 @@ class NotificationRelayService : Service() {
|
||||
companion object {
|
||||
private const val TAG = "NotificationRelayService"
|
||||
private const val CHANNEL_ID = "notification_relay_service"
|
||||
|
||||
/** Parsed back into `Route.ActiveSubscriptions` by `MainActivity.uriToRoute`. */
|
||||
private const val ACTIVE_SUBSCRIPTIONS_URI = "activesubs"
|
||||
|
||||
private const val NOTIFICATION_ID = 9832
|
||||
|
||||
private const val ACTION_START = "com.vitorpamplona.amethyst.START_NOTIFICATION_SERVICE"
|
||||
@@ -141,6 +146,9 @@ class NotificationRelayService : Service() {
|
||||
private var relayServiceCollectorJob: Job? = null
|
||||
private var connectedRelayCount = 0
|
||||
|
||||
/** Last non-empty per-job breakdown, kept so a reconnect does not blank the expanded view. */
|
||||
private var lastBreakdown: List<String> = emptyList()
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? = null
|
||||
|
||||
override fun onCreate() {
|
||||
@@ -336,9 +344,12 @@ class NotificationRelayService : Service() {
|
||||
pluralStringRes(this, R.plurals.always_on_notif_connected, connectedRelays, connectedRelays)
|
||||
}
|
||||
|
||||
// Tapping goes to the screen that answers the question the notification raises — "why is it
|
||||
// connected to N relays" — rather than to whatever tab was last open.
|
||||
val openAppIntent =
|
||||
Intent(this, MainActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
data = ACTIVE_SUBSCRIPTIONS_URI.toUri()
|
||||
}
|
||||
val pendingIntent =
|
||||
PendingIntent.getActivity(
|
||||
@@ -351,8 +362,16 @@ class NotificationRelayService : Service() {
|
||||
// Expanded only. The collapsed line stays the bare count it has always been — that is all
|
||||
// most people want from an ongoing notification — and the per-job breakdown appears solely
|
||||
// when someone deliberately expands it to ask why the phone is talking to N relays.
|
||||
// Skipped entirely when nothing is attributed yet, so we never render an empty section.
|
||||
val breakdown = RelayPurposeSummary.lines(this).takeIf { it.isNotEmpty() }
|
||||
//
|
||||
// Held across reconnects rather than recomputed blindly: the breakdown is derived from the
|
||||
// *connected* relays, so a drop to zero (the "connecting…" state) would otherwise empty it and
|
||||
// the expanded view would collapse to a single line exactly when someone is most likely
|
||||
// looking at it. What each connection is *for* does not change while it is re-establishing,
|
||||
// so the last known answer is still the right one; only the count above it goes stale, and
|
||||
// that count is already labelled "connecting".
|
||||
val fresh = RelayPurposeSummary.lines(this)
|
||||
if (fresh.isNotEmpty()) lastBreakdown = fresh
|
||||
val breakdown = fresh.ifEmpty { lastBreakdown }.takeIf { it.isNotEmpty() }
|
||||
|
||||
return NotificationCompat
|
||||
.Builder(this, CHANNEL_ID)
|
||||
|
||||
@@ -203,6 +203,13 @@ fun isWalletConnectRoute(uri: String) = uri.startsWith("dlnwc?value=") || uri.st
|
||||
|
||||
fun isMarmotGroupRoute(uri: String) = uri.startsWith("marmot:")
|
||||
|
||||
/**
|
||||
* Tapping the always-on service notification. That notification's whole subject is the relay
|
||||
* connections it is holding open, so it lands on the screen that explains them rather than on
|
||||
* whatever tab happened to be last open.
|
||||
*/
|
||||
fun isActiveSubscriptionsRoute(uri: String) = uri.startsWith("activesubs", true) || uri.startsWith("nostr:activesubs", true)
|
||||
|
||||
private val MARMOT_HEX = Regex("^[0-9a-fA-F]+$")
|
||||
|
||||
fun uriToRoute(
|
||||
@@ -213,6 +220,9 @@ fun uriToRoute(
|
||||
val scrollTo = runCatching { java.net.URI(uri.removePrefix(NOSTR_URI_PREFIX)).findParameterValue("scrollTo") }.getOrNull()
|
||||
return Route.Notification(scrollToEventId = scrollTo)
|
||||
}
|
||||
if (isActiveSubscriptionsRoute(uri)) {
|
||||
return Route.ActiveSubscriptions
|
||||
}
|
||||
if (isHashtagRoute(uri)) {
|
||||
return Route.Hashtag(uri.removePrefix(NOSTR_URI_PREFIX).removePrefix("hashtag?id=").lowercase())
|
||||
}
|
||||
|
||||
@@ -592,7 +592,7 @@ fun BuildNavigation(
|
||||
composableFromEndArgs<Route.UpdateZapAmount> { UpdateZapAmountScreen(accountViewModel, nav, it.nip47) }
|
||||
composableFromEndArgs<Route.EditRelays> { AllRelayListScreen(accountViewModel, nav) }
|
||||
|
||||
composableFromEndArgs<Route.ActiveSubscriptions> { ActiveSubscriptionsScreen() }
|
||||
composableFromEndArgs<Route.ActiveSubscriptions> { ActiveSubscriptionsScreen(accountViewModel, nav) }
|
||||
composableFromEnd<Route.EventSync> { EventSyncScreen(accountViewModel, nav) }
|
||||
composableFromEnd<Route.RequestToVanish> { RequestToVanishScreen(accountViewModel, nav) }
|
||||
composableFromEnd<Route.VanishEvents> { VanishEventsScreen(accountViewModel, nav) }
|
||||
|
||||
+1
@@ -104,6 +104,7 @@ fun buildSettingsCatalog(
|
||||
symEntry(R.string.calendar_reminder_settings_title, MaterialSymbols.CalendarMonth, R.string.calendar_reminder_search_keywords, Route.CalendarReminderSettings),
|
||||
symEntry(R.string.ots_explorer_settings, MaterialSymbols.Search, R.string.ots_explorer_search_keywords, Route.OtsSettings),
|
||||
symEntry(R.string.namecoin_settings, MaterialSymbols.Security, R.string.namecoin_search_keywords, Route.NamecoinSettings),
|
||||
symEntry(R.string.active_subs_title, MaterialSymbols.CloudSync, R.string.active_subs_search_keywords, Route.ActiveSubscriptions),
|
||||
symEntry(R.string.resource_usage_title, MaterialSymbols.Bolt, R.string.resource_usage_search_keywords, Route.ResourceUsage),
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user