mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 05:05:19 +00:00
Location notes: add background counter service and show count next to notes icon on mesh; auto-subscribe to current block geohash
This commit is contained in:
@@ -43,6 +43,8 @@
|
||||
0481A3AA2E74D28800FC845E /* LocationNotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3A82E74D28800FC845E /* LocationNotesView.swift */; };
|
||||
0481A3AC2E74D29400FC845E /* LocationNotesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3AB2E74D29400FC845E /* LocationNotesManager.swift */; };
|
||||
0481A3AD2E74D29400FC845E /* LocationNotesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3AB2E74D29400FC845E /* LocationNotesManager.swift */; };
|
||||
0481A3AF2E74E06300FC845E /* LocationNotesCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3AE2E74E06300FC845E /* LocationNotesCounter.swift */; };
|
||||
0481A3B02E74E06300FC845E /* LocationNotesCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481A3AE2E74E06300FC845E /* LocationNotesCounter.swift */; };
|
||||
048A4BE72E5CCCC300162C4A /* TransportConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 048A4BE62E5CCCC300162C4A /* TransportConfig.swift */; };
|
||||
048A4BE82E5CCCC300162C4A /* TransportConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 048A4BE62E5CCCC300162C4A /* TransportConfig.swift */; };
|
||||
048A4BE92E5CCCC300162C4B /* TransportConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 048A4BE62E5CCCC300162C4A /* TransportConfig.swift */; };
|
||||
@@ -240,6 +242,7 @@
|
||||
0481A38F2E734CAE00FC845E /* CommandProcessorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandProcessorTests.swift; sourceTree = "<group>"; };
|
||||
0481A3A82E74D28800FC845E /* LocationNotesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationNotesView.swift; sourceTree = "<group>"; };
|
||||
0481A3AB2E74D29400FC845E /* LocationNotesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationNotesManager.swift; sourceTree = "<group>"; };
|
||||
0481A3AE2E74E06300FC845E /* LocationNotesCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationNotesCounter.swift; sourceTree = "<group>"; };
|
||||
048A4BE62E5CCCC300162C4A /* TransportConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransportConfig.swift; sourceTree = "<group>"; };
|
||||
048A4C272E5FCD6600162C4A /* GeohashBookmarksStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeohashBookmarksStore.swift; sourceTree = "<group>"; };
|
||||
048A4C2A2E5FCE0300162C4A /* GeohashBookmarksStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeohashBookmarksStoreTests.swift; sourceTree = "<group>"; };
|
||||
@@ -594,8 +597,9 @@
|
||||
D98A3186D7E4C72E35BDF7FE /* Services */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0481A3AB2E74D29400FC845E /* LocationNotesManager.swift */,
|
||||
0481A3452E6D869F00FC845E /* Tor */,
|
||||
0481A3AE2E74E06300FC845E /* LocationNotesCounter.swift */,
|
||||
0481A3AB2E74D29400FC845E /* LocationNotesManager.swift */,
|
||||
048A4C272E5FCD6600162C4A /* GeohashBookmarksStore.swift */,
|
||||
048A4BE62E5CCCC300162C4A /* TransportConfig.swift */,
|
||||
AA77BB10CC22DD33EE44FF55 /* VerificationService.swift */,
|
||||
@@ -836,6 +840,7 @@
|
||||
047502B92E560F690083520F /* RelayController.swift in Sources */,
|
||||
6E7761E21C99F28AE2F9BE5F /* BitchatApp.swift in Sources */,
|
||||
84E3F9B64FB7FB4A140BD0A8 /* BitchatPeer.swift in Sources */,
|
||||
0481A3B02E74E06300FC845E /* LocationNotesCounter.swift in Sources */,
|
||||
923027D6F2F417AFA2488127 /* BitchatProtocol.swift in Sources */,
|
||||
D450CF41F207BDE1A1AAA56E /* ChatViewModel.swift in Sources */,
|
||||
B0CA7796B2B2AC2B33F84548 /* CompressionUtil.swift in Sources */,
|
||||
@@ -903,6 +908,7 @@
|
||||
047502BA2E560F690083520F /* RelayController.swift in Sources */,
|
||||
10E68BB889356219189E38EC /* BitchatApp.swift in Sources */,
|
||||
84D13329AB7EE1D65A37438A /* BitchatPeer.swift in Sources */,
|
||||
0481A3AF2E74E06300FC845E /* LocationNotesCounter.swift in Sources */,
|
||||
6DE056E1EE9850E9FBF50157 /* BitchatProtocol.swift in Sources */,
|
||||
7576A357B278E5733E9D9F33 /* ChatViewModel.swift in Sources */,
|
||||
7DCA0DBCB8884E3B31C7BCE3 /* CompressionUtil.swift in Sources */,
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import Foundation
|
||||
|
||||
/// Lightweight background counter for location notes (kind 1) at block-level geohash.
|
||||
@MainActor
|
||||
final class LocationNotesCounter: ObservableObject {
|
||||
static let shared = LocationNotesCounter()
|
||||
|
||||
@Published private(set) var geohash: String? = nil
|
||||
@Published private(set) var count: Int? = nil
|
||||
|
||||
private var subscriptionID: String? = nil
|
||||
private var noteIDs = Set<String>()
|
||||
|
||||
private init() {}
|
||||
|
||||
func subscribe(geohash gh: String) {
|
||||
let norm = gh.lowercased()
|
||||
if geohash == norm { return }
|
||||
cancel()
|
||||
geohash = norm
|
||||
count = nil
|
||||
noteIDs.removeAll()
|
||||
|
||||
let subID = "locnotes-count-\(norm)-\(UUID().uuidString.prefix(6))"
|
||||
subscriptionID = subID
|
||||
let filter = NostrFilter.geohashNotes(norm, since: nil, limit: 500)
|
||||
let relays = GeoRelayDirectory.shared.closestRelays(toGeohash: norm, count: TransportConfig.nostrGeoRelayCount)
|
||||
NostrRelayManager.shared.subscribe(filter: filter, id: subID, relayUrls: relays) { [weak self] event in
|
||||
guard let self = self else { return }
|
||||
guard event.kind == NostrProtocol.EventKind.textNote.rawValue else { return }
|
||||
guard event.tags.contains(where: { $0.count >= 2 && $0[0].lowercased() == "g" && $0[1].lowercased() == norm }) else { return }
|
||||
if !self.noteIDs.contains(event.id) {
|
||||
self.noteIDs.insert(event.id)
|
||||
self.count = self.noteIDs.count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
if let sub = subscriptionID {
|
||||
NostrRelayManager.shared.unsubscribe(id: sub)
|
||||
}
|
||||
subscriptionID = nil
|
||||
geohash = nil
|
||||
count = nil
|
||||
noteIDs.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ struct ContentView: View {
|
||||
@EnvironmentObject var viewModel: ChatViewModel
|
||||
@ObservedObject private var locationManager = LocationChannelManager.shared
|
||||
@ObservedObject private var bookmarks = GeohashBookmarksStore.shared
|
||||
@ObservedObject private var notesCounter = LocationNotesCounter.shared
|
||||
@State private var messageText = ""
|
||||
@State private var textFieldSelection: NSRange? = nil
|
||||
@FocusState private var isTextFieldFocused: Bool
|
||||
@@ -1156,9 +1157,16 @@ struct ContentView: View {
|
||||
notesGeohash = LocationChannelManager.shared.availableChannels.first(where: { $0.level == .block })?.geohash
|
||||
showLocationNotes = true
|
||||
}) {
|
||||
Image(systemName: "note.text")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(Color(hue: 0.60, saturation: 0.85, brightness: 0.82))
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: "note.text")
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(Color(hue: 0.60, saturation: 0.85, brightness: 0.82))
|
||||
if let c = notesCounter.count {
|
||||
Text("\(c)")
|
||||
.font(.system(size: 11, design: .monospaced))
|
||||
.foregroundColor(Color(hue: 0.60, saturation: 0.85, brightness: 0.82))
|
||||
}
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel("Location notes for this place")
|
||||
@@ -1269,6 +1277,9 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear { updateNotesCounterSubscription() }
|
||||
.onChange(of: locationManager.selectedChannel) { _ in updateNotesCounterSubscription() }
|
||||
.onChange(of: locationManager.availableChannels) { _ in updateNotesCounterSubscription() }
|
||||
.alert("heads up", isPresented: $viewModel.showScreenshotPrivacyWarning) {
|
||||
Button("ok", role: .cancel) {}
|
||||
} message: {
|
||||
@@ -1467,6 +1478,22 @@ struct ContentView: View {
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Notes Counter Subscription Helper
|
||||
extension ContentView {
|
||||
private func updateNotesCounterSubscription() {
|
||||
switch locationManager.selectedChannel {
|
||||
case .mesh:
|
||||
if let block = LocationChannelManager.shared.availableChannels.first(where: { $0.level == .block })?.geohash {
|
||||
LocationNotesCounter.shared.subscribe(geohash: block)
|
||||
} else {
|
||||
LocationNotesCounter.shared.cancel()
|
||||
}
|
||||
case .location:
|
||||
LocationNotesCounter.shared.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helper Views
|
||||
|
||||
// Rounded payment chip button
|
||||
|
||||
Reference in New Issue
Block a user