Skip to content

Restore signal indicator#3773

Merged
danieldaquino merged 3 commits into
damus-io:masterfrom
jb55:jb55-ios-2397-restore-signal-indicator
May 18, 2026
Merged

Restore signal indicator#3773
danieldaquino merged 3 commits into
damus-io:masterfrom
jb55:jb55-ios-2397-restore-signal-indicator

Conversation

@jb55

@jb55 jb55 commented May 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fix connectivity indicator that was never appearing because update_signal_from_pool was defined but never called, leaving signal data at 0/0

  • Have RelayPool maintain its own SignalModel, updating it on connection events, relay add/remove

  • Wire views directly to pool signal via NostrNetworkManager instead of the disconnected HomeModel.signal

  • Replace text-based indicator with signal strength bars matching the Android app: 4 progressive-height bars colored red→yellow→green based on connected/total relay ratio

  • Closes Restore signal indicator #3772

Test plan

  • Verify signal bars appear in the toolbar when relays are connected
  • Disconnect relays and verify bars update (color changes red→yellow→green)
  • Tap the signal indicator and verify it navigates to relay config

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Signal indicator redesigned as a visual bar-chart with dynamic color and accessibility preserved
  • Improvements

    • Signal metrics update in real time as relay connections change and are surfaced through the network manager
    • Top header and toolbar now read network signal from the centralized network state
  • Tests

    • Debug print statements in tests were disabled to reduce noisy output

Review Change Stack

The SignalView was never appearing because update_signal_from_pool was
defined but never called, leaving signal data at 0/0. Fix by having
RelayPool maintain its own SignalModel, updating it on connection
events, relay add/remove. Wire views directly to the pool signal via
NostrNetworkManager instead of the disconnected HomeModel.signal.

Replace the text-based indicator with signal strength bars matching
the Android app: 4 progressive-height bars colored red->yellow->green
based on the connected/total relay ratio.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 17c615f0-4a51-468e-90df-4e107d7608ae

📥 Commits

Reviewing files that changed from the base of the PR and between aae43cf and 0e59969.

📒 Files selected for processing (2)
  • damus/Features/Relays/Views/SignalView.swift
  • nostrdb/Test/NdbTests.swift
✅ Files skipped from review due to trivial changes (1)
  • nostrdb/Test/NdbTests.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • damus/Features/Relays/Views/SignalView.swift

📝 Walkthrough

Walkthrough

This PR relocates signal tracking into RelayPool (MainActor), exposes it via NostrNetworkManager.signal, rewires UI to use nostrNetwork.signal, replaces the text indicator with a 4-bar SignalView, removes HomeModel signal code, and disables two test debug prints.

Changes

Signal Indicator Restoration

Layer / File(s) Summary
Signal tracking in RelayPool
damus/Core/Nostr/RelayPool.swift
RelayPool.signal is now @MainActor isolated. New update_signal() computes connected relay count and total relays, updating the SignalModel only on change. Called after relay remove/add and websocket reconnection.
Expose signal through NostrNetworkManager
damus/Core/Networking/NostrNetworkManager/NostrNetworkManager.swift
New @MainActor computed property signal forwards to pool.signal, providing a single access point for UI.
Rewire views to use nostrNetwork.signal
damus/ContentView.swift, damus/Features/Timeline/Views/PostingTimelineView.swift
Top-bar SignalView inputs now use damus_state.nostrNetwork.signal instead of home.signal.
Redesign SignalView with bar-chart visualization
damus/Features/Relays/Views/SignalView.swift
SignalView replaces the numeric fraction with a multi-bar indicator driven by ratio, active_bars, and interpolated active_color (red→yellow→green). Previews updated to show multiple states.
Remove orphaned HomeModel signal code
damus/Features/Timeline/Models/HomeModel.swift
Removed signal stored property and update_signal_from_pool() helper function.
Disable debug prints in tests
nostrdb/Test/NdbTests.swift
Two debug print statements were converted to commented-out prints to silence test output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • danieldaquino

Poem

🐰
I nibbled code in moonlit night,
Found bars of green that now glow bright,
From red to yellow, signals climb,
No more stuck at zero time—
Hooray, the network sings in rhyme!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Restore signal indicator' directly and clearly summarizes the main change—restoring the non-functional connectivity indicator in the toolbar.
Description check ✅ Passed The description covers the key issue (update_signal_from_pool never called), main changes (RelayPool ownership, UI rewiring, visual replacement), and includes a test plan and issue reference, though test plan checkboxes are incomplete.
Linked Issues check ✅ Passed All key requirements from issue #3772 are met: RelayPool maintains SignalModel [RelayPool.swift], pool signal exposed via NostrNetworkManager [NostrNetworkManager.swift], views wired to pool signal [ContentView.swift, PostingTimelineView.swift], text indicator replaced with 4-bar visualization [SignalView.swift], and dead code removed [HomeModel.swift].
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #3772: signal restoration, RelayPool updates, view rewiring, indicator visualization, and code cleanup. Only minor out-of-scope change is commenting debug prints in NdbTests.swift, which is unrelated but does not affect the feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jb55
jb55 requested a review from danieldaquino May 18, 2026 18:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
damus/Features/Relays/Views/SignalView.swift (1)

51-68: 💤 Low value

Consider adding a safeguard for the bar_heights array access.

Line 59 accesses Self.bar_heights[i] where i ranges from 0..<Self.num_bars. Currently this is safe because both are 4, but if someone changes num_bars without updating the bar_heights array length, a crash will occur.

🛡️ Proposed safeguard

Add a static assertion or precondition:

 struct SignalView: View {
     let state: DamusState
     `@ObservedObject` var signal: SignalModel
 
     static let num_bars = 4
     static let bar_heights: [CGFloat] = [4, 7, 10, 13]
     static let bar_width: CGFloat = 3
     static let bar_spacing: CGFloat = 2
+    
+    // Ensure bar_heights array matches num_bars
+    private static let _ = {
+        precondition(bar_heights.count == num_bars, "bar_heights.count must equal num_bars")
+    }()

Alternatively, add a comment documenting the dependency:

     static let num_bars = 4
+    // IMPORTANT: bar_heights must have exactly num_bars elements
     static let bar_heights: [CGFloat] = [4, 7, 10, 13]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@damus/Features/Relays/Views/SignalView.swift` around lines 51 - 68, The
ForEach in SignalView's body indexes Self.bar_heights[i] using 0..<Self.num_bars
which will crash if num_bars and bar_heights length diverge; fix by either
adding a runtime safeguard (precondition(Self.bar_heights.count >=
Self.num_bars) or assertion in the type) or by changing the iteration to use the
actual bar_heights indices (e.g., iterate over 0..<min(Self.num_bars,
Self.bar_heights.count) or bar_heights.indices.prefix(Self.num_bars)) so
Self.bar_heights[i] is always valid; update the ForEach and/or add a static
comment/assert near the definitions of num_bars and bar_heights to document the
invariant.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@damus/Core/Networking/NostrNetworkManager/NostrNetworkManager.swift`:
- Around line 250-253: Add a concise docstring above the `@MainActor` computed
property `signal` describing its purpose (exposing the network pool's signaling
model), its thread-affinity (main actor), and what it returns (the `SignalModel`
from `pool.signal`), e.g. one or two sentences that mention it forwards to
`pool.signal` for consumers to observe network signals; place the docstring
immediately above `var signal` in `NostrNetworkManager`.

In `@damus/Core/Nostr/RelayPool.swift`:
- Around line 129-139: The method update_signal lacks a docstring; add a concise
Swift doc comment above the `@MainActor` func update_signal() that explains its
purpose (synchronizes the signal fields with current connection state),
describes behavior (reads num_connected and relays.count, updates signal.signal
and signal.max_signal only when values change), mentions thread context
(`@MainActor`) and any side effects on signal, and notes expected invariants
(e.g., non-negative counts); reference the symbols update_signal, signal,
num_connected, and relays in the comment for clarity.

---

Nitpick comments:
In `@damus/Features/Relays/Views/SignalView.swift`:
- Around line 51-68: The ForEach in SignalView's body indexes
Self.bar_heights[i] using 0..<Self.num_bars which will crash if num_bars and
bar_heights length diverge; fix by either adding a runtime safeguard
(precondition(Self.bar_heights.count >= Self.num_bars) or assertion in the type)
or by changing the iteration to use the actual bar_heights indices (e.g.,
iterate over 0..<min(Self.num_bars, Self.bar_heights.count) or
bar_heights.indices.prefix(Self.num_bars)) so Self.bar_heights[i] is always
valid; update the ForEach and/or add a static comment/assert near the
definitions of num_bars and bar_heights to document the invariant.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee4c8b4f-fe20-48ea-9c48-b8b1d40c96ec

📥 Commits

Reviewing files that changed from the base of the PR and between 5bc13d6 and aae43cf.

📒 Files selected for processing (6)
  • damus/ContentView.swift
  • damus/Core/Networking/NostrNetworkManager/NostrNetworkManager.swift
  • damus/Core/Nostr/RelayPool.swift
  • damus/Features/Relays/Views/SignalView.swift
  • damus/Features/Timeline/Models/HomeModel.swift
  • damus/Features/Timeline/Views/PostingTimelineView.swift
💤 Files with no reviewable changes (1)
  • damus/Features/Timeline/Models/HomeModel.swift

Comment on lines +250 to +253
@MainActor
var signal: SignalModel {
self.pool.signal
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add docstring to document the property's purpose.

This new computed property lacks documentation. According to coding guidelines, all added or modified code must have docstring coverage.

📝 Proposed docstring
+    /// The current network signal model reflecting relay connectivity status.
+    ///
+    /// This property forwards the relay pool's signal state, providing access
+    /// to the number of connected relays (`signal`) and total relays (`max_signal`)
+    /// for UI components and observers.
     `@MainActor`
     var signal: SignalModel {

As per coding guidelines: "Ensure docstring coverage for any code added or modified"

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@MainActor
var signal: SignalModel {
self.pool.signal
}
/// The current network signal model reflecting relay connectivity status.
///
/// This property forwards the relay pool's signal state, providing access
/// to the number of connected relays (`signal`) and total relays (`max_signal`)
/// for UI components and observers.
`@MainActor`
var signal: SignalModel {
self.pool.signal
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@damus/Core/Networking/NostrNetworkManager/NostrNetworkManager.swift` around
lines 250 - 253, Add a concise docstring above the `@MainActor` computed property
`signal` describing its purpose (exposing the network pool's signaling model),
its thread-affinity (main actor), and what it returns (the `SignalModel` from
`pool.signal`), e.g. one or two sentences that mention it forwards to
`pool.signal` for consumers to observe network signals; place the docstring
immediately above `var signal` in `NostrNetworkManager`.

Comment on lines +129 to +139
@MainActor
func update_signal() {
let connected = num_connected
let total = relays.count
if signal.signal != connected {
signal.signal = connected
}
if signal.max_signal != total {
signal.max_signal = total
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add docstring to document the method's purpose and behavior.

This new method lacks documentation. According to coding guidelines, all added or modified code must have docstring coverage.

📝 Proposed docstring
+    /// Updates the signal model with current relay connection statistics.
+    ///
+    /// Computes the number of connected relays and total relay count, then updates
+    /// `signal.signal` and `signal.max_signal` if the values have changed.
+    /// This reduces unnecessary publishes to observers when values are unchanged.
     `@MainActor`
     func update_signal() {

As per coding guidelines: "Ensure docstring coverage for any code added or modified"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@damus/Core/Nostr/RelayPool.swift` around lines 129 - 139, The method
update_signal lacks a docstring; add a concise Swift doc comment above the
`@MainActor` func update_signal() that explains its purpose (synchronizes the
signal fields with current connection state), describes behavior (reads
num_connected and relays.count, updates signal.signal and signal.max_signal only
when values change), mentions thread context (`@MainActor`) and any side effects
on signal, and notes expected invariants (e.g., non-negative counts); reference
the symbols update_signal, signal, num_connected, and relays in the comment for
clarity.

jb55 and others added 2 commits May 18, 2026 12:12
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jb55

jb55 commented May 18, 2026

Copy link
Copy Markdown
Collaborator Author

I made one more change: hide the signal indicator if we're fully connected. this was the original behavior

@danieldaquino danieldaquino left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@danieldaquino
danieldaquino merged commit 73eddea into damus-io:master May 18, 2026
1 of 2 checks passed
@danieldaquino

Copy link
Copy Markdown
Collaborator

Added changelog items on the merge commit.

@jb55

jb55 commented May 19, 2026

Copy link
Copy Markdown
Collaborator Author

I added #3776 to enforce this as a check like we do on the notedeck side

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Restore signal indicator

2 participants