mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 17:45:21 +00:00
Notes: subscribe counter to building + parent block (merge results); hide notes icon unless location is authorized; replace 10s timer with live location updates while sheet open
This commit is contained in:
@@ -9,7 +9,8 @@ final class LocationNotesCounter: ObservableObject {
|
|||||||
@Published private(set) var count: Int? = 0
|
@Published private(set) var count: Int? = 0
|
||||||
@Published private(set) var initialLoadComplete: Bool = false
|
@Published private(set) var initialLoadComplete: Bool = false
|
||||||
|
|
||||||
private var subscriptionID: String? = nil
|
// Support multiple subscriptions (e.g., building + parent block fallback)
|
||||||
|
private var subscriptionIDs: Set<String> = []
|
||||||
private var noteIDs = Set<String>()
|
private var noteIDs = Set<String>()
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
@@ -23,28 +24,40 @@ final class LocationNotesCounter: ObservableObject {
|
|||||||
noteIDs.removeAll()
|
noteIDs.removeAll()
|
||||||
initialLoadComplete = false
|
initialLoadComplete = false
|
||||||
|
|
||||||
let subID = "locnotes-count-\(norm)-\(UUID().uuidString.prefix(6))"
|
// Subscribe to both building and parent block to capture legacy notes
|
||||||
subscriptionID = subID
|
var targets: [String] = [norm]
|
||||||
let filter = NostrFilter.geohashNotes(norm, since: nil, limit: 500)
|
if norm.count >= 8 {
|
||||||
let relays = GeoRelayDirectory.shared.closestRelays(toGeohash: norm, count: TransportConfig.nostrGeoRelayCount)
|
let parent7 = String(norm.prefix(7))
|
||||||
NostrRelayManager.shared.subscribe(filter: filter, id: subID, relayUrls: relays, handler: { [weak self] event in
|
if parent7 != norm { targets.append(parent7) }
|
||||||
guard let self = self else { return }
|
}
|
||||||
guard event.kind == NostrProtocol.EventKind.textNote.rawValue else { return }
|
var pendingEOSE = Set<String>()
|
||||||
guard event.tags.contains(where: { $0.count >= 2 && $0[0].lowercased() == "g" && $0[1].lowercased() == norm }) else { return }
|
for target in targets {
|
||||||
if !self.noteIDs.contains(event.id) {
|
let subID = "locnotes-count-\(target)-\(UUID().uuidString.prefix(6))"
|
||||||
self.noteIDs.insert(event.id)
|
subscriptionIDs.insert(subID)
|
||||||
self.count = self.noteIDs.count
|
pendingEOSE.insert(subID)
|
||||||
}
|
let filter = NostrFilter.geohashNotes(target, since: nil, limit: 500)
|
||||||
}, onEOSE: { [weak self] in
|
let relays = GeoRelayDirectory.shared.closestRelays(toGeohash: target, count: TransportConfig.nostrGeoRelayCount)
|
||||||
self?.initialLoadComplete = true
|
NostrRelayManager.shared.subscribe(filter: filter, id: subID, relayUrls: relays, handler: { [weak self] event in
|
||||||
})
|
guard let self = self else { return }
|
||||||
|
guard event.kind == NostrProtocol.EventKind.textNote.rawValue else { return }
|
||||||
|
// Ensure matching g-tag for either building or parent block
|
||||||
|
let matches = event.tags.contains(where: { $0.count >= 2 && $0[0].lowercased() == "g" && targets.contains($0[1].lowercased()) })
|
||||||
|
guard matches else { return }
|
||||||
|
if !self.noteIDs.contains(event.id) {
|
||||||
|
self.noteIDs.insert(event.id)
|
||||||
|
self.count = self.noteIDs.count
|
||||||
|
}
|
||||||
|
}, onEOSE: { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
pendingEOSE.remove(subID)
|
||||||
|
if pendingEOSE.isEmpty { self.initialLoadComplete = true }
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cancel() {
|
func cancel() {
|
||||||
if let sub = subscriptionID {
|
for sub in subscriptionIDs { NostrRelayManager.shared.unsubscribe(id: sub) }
|
||||||
NostrRelayManager.shared.unsubscribe(id: sub)
|
subscriptionIDs.removeAll()
|
||||||
}
|
|
||||||
subscriptionID = nil
|
|
||||||
geohash = nil
|
geohash = nil
|
||||||
count = 0
|
count = 0
|
||||||
noteIDs.removeAll()
|
noteIDs.removeAll()
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ struct ContentView: View {
|
|||||||
@State private var expandedMessageIDs: Set<String> = []
|
@State private var expandedMessageIDs: Set<String> = []
|
||||||
@State private var showLocationNotes = false
|
@State private var showLocationNotes = false
|
||||||
@State private var notesGeohash: String? = nil
|
@State private var notesGeohash: String? = nil
|
||||||
@State private var notesRefreshTimer: Timer? = nil
|
// Timer-based refresh removed; use LocationChannelManager live updates instead
|
||||||
// Window sizes for rendering (infinite scroll up)
|
// Window sizes for rendering (infinite scroll up)
|
||||||
@State private var windowCountPublic: Int = 300
|
@State private var windowCountPublic: Int = 300
|
||||||
@State private var windowCountPrivate: [String: Int] = [:]
|
@State private var windowCountPrivate: [String: Int] = [:]
|
||||||
@@ -1174,8 +1174,8 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
|
|
||||||
// Notes icon (mesh only), to the right of #mesh
|
// Notes icon (mesh only and when location is authorized), to the right of #mesh
|
||||||
if case .mesh = locationManager.selectedChannel {
|
if case .mesh = locationManager.selectedChannel, locationManager.permissionState == .authorized {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
// Kick a one-shot refresh and show the sheet immediately.
|
// Kick a one-shot refresh and show the sheet immediately.
|
||||||
LocationChannelManager.shared.enableLocationChannels()
|
LocationChannelManager.shared.enableLocationChannels()
|
||||||
@@ -1277,17 +1277,12 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
// Ensure we are authorized and start periodic refresh while the sheet is open
|
// Ensure we are authorized and start live location updates (distance-filtered)
|
||||||
LocationChannelManager.shared.enableLocationChannels()
|
LocationChannelManager.shared.enableLocationChannels()
|
||||||
LocationChannelManager.shared.refreshChannels()
|
LocationChannelManager.shared.beginLiveRefresh()
|
||||||
notesRefreshTimer?.invalidate()
|
|
||||||
notesRefreshTimer = Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true) { _ in
|
|
||||||
LocationChannelManager.shared.refreshChannels()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
notesRefreshTimer?.invalidate()
|
LocationChannelManager.shared.endLiveRefresh()
|
||||||
notesRefreshTimer = nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear { updateNotesCounterSubscription() }
|
.onAppear { updateNotesCounterSubscription() }
|
||||||
|
|||||||
Reference in New Issue
Block a user