feat(mesh): RSSI/SNR dBm tooltip on the existing signal-bars indicator
The bars UI (signalBars/.mesh-signal-bars) was already built and wired to mp.primary_rssi -- it just needed real backend data, which the previous commit provides. Adds primary_snr alongside primary_rssi in MergedPeer and a hover tooltip showing exact dBm/SNR values. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
02b6b52a8c
commit
4a309a3ee4
@ -533,6 +533,7 @@ interface MergedPeer {
|
|||||||
primary_contact_id: number
|
primary_contact_id: number
|
||||||
primary_pubkey_hex: string | null
|
primary_pubkey_hex: string | null
|
||||||
primary_rssi: number | null
|
primary_rssi: number | null
|
||||||
|
primary_snr: number | null
|
||||||
is_archy: boolean
|
is_archy: boolean
|
||||||
reachable: boolean
|
reachable: boolean
|
||||||
// The original active-chat marker uses contact_id equality, so keep a
|
// The original active-chat marker uses contact_id equality, so keep a
|
||||||
@ -669,6 +670,7 @@ const mergedPeers = computed<MergedPeer[]>(() => {
|
|||||||
primary_contact_id: peer.contact_id,
|
primary_contact_id: peer.contact_id,
|
||||||
primary_pubkey_hex: peer.pubkey_hex,
|
primary_pubkey_hex: peer.pubkey_hex,
|
||||||
primary_rssi: peer.rssi,
|
primary_rssi: peer.rssi,
|
||||||
|
primary_snr: peer.snr,
|
||||||
is_archy: isArchyNode(peer) || !!matchedFed,
|
is_archy: isArchyNode(peer) || !!matchedFed,
|
||||||
reachable: peer.reachable ?? true,
|
reachable: peer.reachable ?? true,
|
||||||
primary: peer,
|
primary: peer,
|
||||||
@ -719,6 +721,7 @@ const mergedPeers = computed<MergedPeer[]>(() => {
|
|||||||
primary_contact_id: synthCid,
|
primary_contact_id: synthCid,
|
||||||
primary_pubkey_hex: fed.pubkey,
|
primary_pubkey_hex: fed.pubkey,
|
||||||
primary_rssi: null,
|
primary_rssi: null,
|
||||||
|
primary_snr: null,
|
||||||
is_archy: true,
|
is_archy: true,
|
||||||
reachable: true,
|
reachable: true,
|
||||||
primary: placeholder,
|
primary: placeholder,
|
||||||
@ -1017,6 +1020,14 @@ function signalBars(rssi: number | null): number {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function signalTitle(rssi: number | null, snr: number | null): string {
|
||||||
|
if (rssi === null && snr === null) return 'No signal data yet'
|
||||||
|
const parts: string[] = []
|
||||||
|
if (rssi !== null) parts.push(`${rssi} dBm`)
|
||||||
|
if (snr !== null) parts.push(`SNR ${snr.toFixed(1)} dB`)
|
||||||
|
return parts.join(' · ')
|
||||||
|
}
|
||||||
|
|
||||||
function timeAgo(iso: string): string {
|
function timeAgo(iso: string): string {
|
||||||
const diff = Date.now() - new Date(iso).getTime()
|
const diff = Date.now() - new Date(iso).getTime()
|
||||||
const secs = Math.floor(diff / 1000)
|
const secs = Math.floor(diff / 1000)
|
||||||
@ -1823,7 +1834,7 @@ function isImageMime(mime?: string): boolean {
|
|||||||
<span v-if="mergedUnreadCount(mp)" class="mesh-unread-badge">
|
<span v-if="mergedUnreadCount(mp)" class="mesh-unread-badge">
|
||||||
{{ mergedUnreadCount(mp) }}
|
{{ mergedUnreadCount(mp) }}
|
||||||
</span>
|
</span>
|
||||||
<div class="mesh-peer-signal">
|
<div class="mesh-peer-signal" :title="signalTitle(mp.primary_rssi, mp.primary_snr)">
|
||||||
<div class="mesh-signal-bars">
|
<div class="mesh-signal-bars">
|
||||||
<div v-for="i in 4" :key="i" class="mesh-signal-bar" :class="{ active: i <= signalBars(mp.primary_rssi) }" />
|
<div v-for="i in 4" :key="i" class="mesh-signal-bar" :class="{ active: i <= signalBars(mp.primary_rssi) }" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user