mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 16:05:19 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42cdc4c123 | ||
|
|
fb94e799a5 | ||
|
|
04671caeb8 | ||
|
|
a485335649 | ||
|
|
de2b5ed142 | ||
|
|
57cc9028cb | ||
|
|
b0a50c663f |
+102
-766
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Lightweight background counter for location notes (kind 1) at block-level geohash.
|
/// Lightweight background counter for location notes (kind 1) at building-level geohash (8 chars).
|
||||||
@MainActor
|
@MainActor
|
||||||
final class LocationNotesCounter: ObservableObject {
|
final class LocationNotesCounter: ObservableObject {
|
||||||
static let shared = LocationNotesCounter()
|
static let shared = LocationNotesCounter()
|
||||||
@@ -16,10 +16,11 @@ final class LocationNotesCounter: ObservableObject {
|
|||||||
|
|
||||||
func subscribe(geohash gh: String) {
|
func subscribe(geohash gh: String) {
|
||||||
let norm = gh.lowercased()
|
let norm = gh.lowercased()
|
||||||
if geohash == norm { return }
|
if geohash == norm, subscriptionID != nil { return }
|
||||||
cancel()
|
// Unsubscribe previous without clearing count to avoid flicker
|
||||||
|
if let sub = subscriptionID { NostrRelayManager.shared.unsubscribe(id: sub) }
|
||||||
|
subscriptionID = nil
|
||||||
geohash = norm
|
geohash = norm
|
||||||
count = 0
|
|
||||||
noteIDs.removeAll()
|
noteIDs.removeAll()
|
||||||
initialLoadComplete = false
|
initialLoadComplete = false
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ final class NotificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sendPrivateMessageNotification(from sender: String, message: String, peerID: String) {
|
func sendPrivateMessageNotification(from sender: String, message: String, peerID: String) {
|
||||||
let title = "🔒 private message from \(sender)"
|
let title = "🔒 DM from \(sender)"
|
||||||
let body = message
|
let body = message
|
||||||
let identifier = "private-\(UUID().uuidString)"
|
let identifier = "private-\(UUID().uuidString)"
|
||||||
let userInfo = ["peerID": peerID, "senderName": sender]
|
let userInfo = ["peerID": peerID, "senderName": sender]
|
||||||
|
|||||||
@@ -40,7 +40,11 @@ static void *tor_thread_main(void *arg) {
|
|||||||
int rc = tor_run_main(cfg); // blocks until tor exits
|
int rc = tor_run_main(cfg); // blocks until tor exits
|
||||||
tor_main_configuration_free(cfg);
|
tor_main_configuration_free(cfg);
|
||||||
if (argv_owned) { free(argv_owned); argv_owned = NULL; argv_owned_argc = 0; }
|
if (argv_owned) { free(argv_owned); argv_owned = NULL; argv_owned_argc = 0; }
|
||||||
if (owning_fd_tor != -1) { close(owning_fd_tor); owning_fd_tor = -1; }
|
// Do not close owning_fd_tor here: Tor may have already closed it and the
|
||||||
|
// fd number could have been re-used by the time we get here. On iOS 18,
|
||||||
|
// attempting to close a re-used guarded fd can trigger EXC_GUARD. Treat the
|
||||||
|
// tor-side end as owned by Tor and simply forget our reference.
|
||||||
|
owning_fd_tor = -1;
|
||||||
return (void*)(intptr_t)rc;
|
return (void*)(intptr_t)rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,10 +86,14 @@ struct AppInfoView: View {
|
|||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .navigationBarTrailing) {
|
ToolbarItem(placement: .navigationBarTrailing) {
|
||||||
Button("close") {
|
Button(action: { dismiss() }) {
|
||||||
dismiss()
|
Image(systemName: "xmark")
|
||||||
}
|
.font(.system(size: 13, weight: .semibold, design: .monospaced))
|
||||||
.foregroundColor(textColor)
|
.foregroundColor(textColor)
|
||||||
|
.frame(width: 32, height: 32)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.accessibilityLabel("Close")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1140,7 +1140,31 @@ struct ContentView: View {
|
|||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.accessibilityLabel("Open unread private chat")
|
.accessibilityLabel("Open unread private chat")
|
||||||
}
|
}
|
||||||
// Bookmark toggle for current geohash (not shown for mesh)
|
// Notes icon (mesh only and when location is authorized), to the left of #mesh
|
||||||
|
if case .mesh = locationManager.selectedChannel, locationManager.permissionState == .authorized {
|
||||||
|
Button(action: {
|
||||||
|
// Kick a one-shot refresh and show the sheet immediately.
|
||||||
|
LocationChannelManager.shared.enableLocationChannels()
|
||||||
|
LocationChannelManager.shared.refreshChannels()
|
||||||
|
// If we already have a block geohash, pass it; otherwise wait in the sheet.
|
||||||
|
notesGeohash = LocationChannelManager.shared.availableChannels.first(where: { $0.level == .building })?.geohash
|
||||||
|
showLocationNotes = true
|
||||||
|
}) {
|
||||||
|
HStack(alignment: .center, spacing: 4) {
|
||||||
|
let currentCount = (notesCounter.count ?? 0)
|
||||||
|
let hasNotes = (!notesCounter.initialLoadComplete ? max(currentCount, sheetNotesCount) : currentCount) > 0
|
||||||
|
Image(systemName: "long.text.page.and.pencil")
|
||||||
|
.font(.system(size: 12))
|
||||||
|
.foregroundColor(hasNotes ? textColor : Color.gray)
|
||||||
|
.padding(.top, 1)
|
||||||
|
}
|
||||||
|
.fixedSize(horizontal: true, vertical: false)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.accessibilityLabel("Location notes for this place")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bookmark toggle (geochats): to the left of #geohash
|
||||||
if case .location(let ch) = locationManager.selectedChannel {
|
if case .location(let ch) = locationManager.selectedChannel {
|
||||||
Button(action: { GeohashBookmarksStore.shared.toggle(ch.geohash) }) {
|
Button(action: { GeohashBookmarksStore.shared.toggle(ch.geohash) }) {
|
||||||
Image(systemName: GeohashBookmarksStore.shared.isBookmarked(ch.geohash) ? "bookmark.fill" : "bookmark")
|
Image(systemName: GeohashBookmarksStore.shared.isBookmarked(ch.geohash) ? "bookmark.fill" : "bookmark")
|
||||||
@@ -1149,6 +1173,7 @@ struct ContentView: View {
|
|||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.accessibilityLabel("Toggle bookmark for #\(ch.geohash)")
|
.accessibilityLabel("Toggle bookmark for #\(ch.geohash)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Location channels button '#'
|
// Location channels button '#'
|
||||||
Button(action: { showLocationChannelsSheet = true }) {
|
Button(action: { showLocationChannelsSheet = true }) {
|
||||||
let badgeText: String = {
|
let badgeText: String = {
|
||||||
@@ -1174,29 +1199,8 @@ struct ContentView: View {
|
|||||||
.accessibilityLabel("location channels")
|
.accessibilityLabel("location channels")
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
|
.padding(.leading, 4)
|
||||||
// Notes icon (mesh only and when location is authorized), to the right of #mesh
|
.padding(.trailing, 2)
|
||||||
if case .mesh = locationManager.selectedChannel, locationManager.permissionState == .authorized {
|
|
||||||
Button(action: {
|
|
||||||
// Kick a one-shot refresh and show the sheet immediately.
|
|
||||||
LocationChannelManager.shared.enableLocationChannels()
|
|
||||||
LocationChannelManager.shared.refreshChannels()
|
|
||||||
// If we already have a block geohash, pass it; otherwise wait in the sheet.
|
|
||||||
notesGeohash = LocationChannelManager.shared.availableChannels.first(where: { $0.level == .building })?.geohash
|
|
||||||
showLocationNotes = true
|
|
||||||
}) {
|
|
||||||
HStack(alignment: .center, spacing: 4) {
|
|
||||||
let hasNotes = ((notesCounter.count ?? 0) > 0) || (sheetNotesCount > 0)
|
|
||||||
Image(systemName: "long.text.page.and.pencil")
|
|
||||||
.font(.system(size: 12))
|
|
||||||
.foregroundColor(hasNotes ? Color(hue: 0.60, saturation: 0.85, brightness: 0.82) : Color.gray)
|
|
||||||
.padding(.top, 1)
|
|
||||||
}
|
|
||||||
.fixedSize(horizontal: true, vertical: false)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
.accessibilityLabel("Location notes for this place")
|
|
||||||
}
|
|
||||||
|
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
// People icon with count
|
// People icon with count
|
||||||
@@ -1208,6 +1212,7 @@ struct ContentView: View {
|
|||||||
.accessibilityHidden(true)
|
.accessibilityHidden(true)
|
||||||
}
|
}
|
||||||
.foregroundColor(headerCountColor)
|
.foregroundColor(headerCountColor)
|
||||||
|
.padding(.leading, 2)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
.fixedSize(horizontal: true, vertical: false)
|
.fixedSize(horizontal: true, vertical: false)
|
||||||
|
|
||||||
@@ -1277,7 +1282,6 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
LocationChannelManager.shared.endLiveRefresh()
|
LocationChannelManager.shared.endLiveRefresh()
|
||||||
sheetNotesCount = 0
|
|
||||||
}
|
}
|
||||||
.onChange(of: locationManager.availableChannels) { channels in
|
.onChange(of: locationManager.availableChannels) { channels in
|
||||||
if let current = channels.first(where: { $0.level == .building })?.geohash,
|
if let current = channels.first(where: { $0.level == .building })?.geohash,
|
||||||
@@ -1524,8 +1528,16 @@ extension ContentView {
|
|||||||
if locationManager.permissionState == .authorized {
|
if locationManager.permissionState == .authorized {
|
||||||
LocationChannelManager.shared.refreshChannels()
|
LocationChannelManager.shared.refreshChannels()
|
||||||
}
|
}
|
||||||
|
if locationManager.permissionState == .authorized {
|
||||||
if let building = LocationChannelManager.shared.availableChannels.first(where: { $0.level == .building })?.geohash {
|
if let building = LocationChannelManager.shared.availableChannels.first(where: { $0.level == .building })?.geohash {
|
||||||
LocationNotesCounter.shared.subscribe(geohash: building)
|
LocationNotesCounter.shared.subscribe(geohash: building)
|
||||||
|
} else {
|
||||||
|
// Keep existing subscription if we had one to avoid flicker
|
||||||
|
// Only cancel if we have no known geohash
|
||||||
|
if LocationNotesCounter.shared.geohash == nil {
|
||||||
|
LocationNotesCounter.shared.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LocationNotesCounter.shared.cancel()
|
LocationNotesCounter.shared.cancel()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ struct LocationChannelsSheet: View {
|
|||||||
@State private var customGeohash: String = ""
|
@State private var customGeohash: String = ""
|
||||||
@State private var customError: String? = nil
|
@State private var customError: String? = nil
|
||||||
|
|
||||||
|
private var backgroundColor: Color { colorScheme == .dark ? .black : .white }
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
VStack(alignment: .leading, spacing: 12) {
|
VStack(alignment: .leading, spacing: 12) {
|
||||||
Text("#location channels")
|
Text("#location channels")
|
||||||
.font(.system(size: 18, design: .monospaced))
|
.font(.system(size: 18, design: .monospaced))
|
||||||
Text("chat with people near you using geohash channels. only a coarse geohash is shared, never exact gps.")
|
Text("chat with people near you using geohash channels. only a coarse geohash is shared, never exact gps. your IP address is hidden by routing all traffic over tor.")
|
||||||
.font(.system(size: 12, design: .monospaced))
|
.font(.system(size: 12, design: .monospaced))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
@@ -54,19 +56,30 @@ struct LocationChannelsSheet: View {
|
|||||||
}
|
}
|
||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, 12)
|
||||||
|
.background(backgroundColor)
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .navigationBarTrailing) {
|
ToolbarItem(placement: .navigationBarTrailing) {
|
||||||
Button("close") { isPresented = false }
|
Button(action: { isPresented = false }) {
|
||||||
.font(.system(size: 14, design: .monospaced))
|
Image(systemName: "xmark")
|
||||||
|
.font(.system(size: 13, weight: .semibold, design: .monospaced))
|
||||||
|
.frame(width: 32, height: 32)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.accessibilityLabel("Close")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .automatic) {
|
ToolbarItem(placement: .automatic) {
|
||||||
Button("close") { isPresented = false }
|
Button(action: { isPresented = false }) {
|
||||||
.font(.system(size: 14, design: .monospaced))
|
Image(systemName: "xmark")
|
||||||
|
.font(.system(size: 13, weight: .semibold, design: .monospaced))
|
||||||
|
.frame(width: 20, height: 20)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
.accessibilityLabel("Close")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -77,6 +90,7 @@ struct LocationChannelsSheet: View {
|
|||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.frame(minWidth: 420, minHeight: 520)
|
.frame(minWidth: 420, minHeight: 520)
|
||||||
#endif
|
#endif
|
||||||
|
.background(backgroundColor)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
// Refresh channels when opening
|
// Refresh channels when opening
|
||||||
if manager.permissionState == LocationChannelManager.PermissionState.authorized {
|
if manager.permissionState == LocationChannelManager.PermissionState.authorized {
|
||||||
@@ -205,12 +219,11 @@ struct LocationChannelsSheet: View {
|
|||||||
|
|
||||||
// Bookmarked geohashes
|
// Bookmarked geohashes
|
||||||
if !bookmarks.bookmarks.isEmpty {
|
if !bookmarks.bookmarks.isEmpty {
|
||||||
VStack(alignment: .leading, spacing: 6) {
|
VStack(alignment: .leading, spacing: 8) {
|
||||||
Text("bookmarked")
|
Text("bookmarked")
|
||||||
.font(.system(size: 12, design: .monospaced))
|
.font(.system(size: 12, design: .monospaced))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
VStack(spacing: 6) {
|
||||||
.listRowSeparator(.hidden)
|
|
||||||
ForEach(bookmarks.bookmarks, id: \.self) { gh in
|
ForEach(bookmarks.bookmarks, id: \.self) { gh in
|
||||||
let level = levelForLength(gh.count)
|
let level = levelForLength(gh.count)
|
||||||
let channel = GeohashChannel(level: level, geohash: gh)
|
let channel = GeohashChannel(level: level, geohash: gh)
|
||||||
@@ -244,6 +257,12 @@ struct LocationChannelsSheet: View {
|
|||||||
.onAppear { bookmarks.resolveNameIfNeeded(for: gh) }
|
.onAppear { bookmarks.resolveNameIfNeeded(for: gh) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(12)
|
||||||
|
.background(Color.secondary.opacity(0.12))
|
||||||
|
.cornerRadius(8)
|
||||||
|
}
|
||||||
|
.listRowSeparator(.hidden)
|
||||||
|
}
|
||||||
|
|
||||||
// Footer action inside the list
|
// Footer action inside the list
|
||||||
if manager.permissionState == LocationChannelManager.PermissionState.authorized {
|
if manager.permissionState == LocationChannelManager.PermissionState.authorized {
|
||||||
@@ -260,9 +279,12 @@ struct LocationChannelsSheet: View {
|
|||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
|
.listRowBackground(Color.clear)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.plain)
|
.listStyle(.plain)
|
||||||
|
.scrollContentBackground(.hidden)
|
||||||
|
.background(backgroundColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func isSelected(_ channel: GeohashChannel) -> Bool {
|
private func isSelected(_ channel: GeohashChannel) -> Bool {
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct LocationNotesSheet: View {
|
|
||||||
@EnvironmentObject var viewModel: ChatViewModel
|
|
||||||
@ObservedObject private var locationManager = LocationChannelManager.shared
|
|
||||||
@Binding var notesGeohash: String?
|
|
||||||
@Environment(\.dismiss) private var dismiss
|
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
|
||||||
|
|
||||||
private var backgroundColor: Color { colorScheme == .dark ? .black : .white }
|
|
||||||
private var textColor: Color { colorScheme == .dark ? .green : Color(red: 0, green: 0.5, blue: 0) }
|
|
||||||
private var secondaryTextColor: Color { textColor.opacity(0.8) }
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
Group {
|
|
||||||
if let gh = notesGeohash ?? locationManager.availableChannels.first(where: { $0.level == .block })?.geohash {
|
|
||||||
// Found block geohash: show notes view
|
|
||||||
LocationNotesView(geohash: gh)
|
|
||||||
.environmentObject(viewModel)
|
|
||||||
} else {
|
|
||||||
// Acquire location: keep a loading overlay (Matrix) until we either get a block geohash
|
|
||||||
ZStack {
|
|
||||||
VStack(spacing: 0) {
|
|
||||||
HStack {
|
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
|
||||||
Text("notes")
|
|
||||||
.font(.system(size: 16, weight: .bold, design: .monospaced))
|
|
||||||
Text("acquiring location…")
|
|
||||||
.font(.system(size: 12, design: .monospaced))
|
|
||||||
.foregroundColor(secondaryTextColor)
|
|
||||||
}
|
|
||||||
Spacer()
|
|
||||||
Button(action: { dismiss() }) {
|
|
||||||
Image(systemName: "xmark")
|
|
||||||
.font(.system(size: 13, weight: .semibold, design: .monospaced))
|
|
||||||
.foregroundColor(textColor)
|
|
||||||
.frame(width: 32, height: 32)
|
|
||||||
}
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
.accessibilityLabel("Close")
|
|
||||||
}
|
|
||||||
.frame(height: 44)
|
|
||||||
.padding(.horizontal, 12)
|
|
||||||
.background(backgroundColor.opacity(0.95))
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
MatrixRainView()
|
|
||||||
.transition(.opacity)
|
|
||||||
}
|
|
||||||
.background(backgroundColor)
|
|
||||||
.foregroundColor(textColor)
|
|
||||||
.onAppear {
|
|
||||||
LocationChannelManager.shared.enableLocationChannels()
|
|
||||||
// Nudge a fresh fix
|
|
||||||
LocationChannelManager.shared.refreshChannels()
|
|
||||||
}
|
|
||||||
.onChange(of: locationManager.availableChannels) { channels in
|
|
||||||
if notesGeohash == nil, let block = channels.first(where: { $0.level == .block }) {
|
|
||||||
notesGeohash = block.geohash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,6 +27,10 @@ struct LocationNotesView: View {
|
|||||||
private var secondaryTextColor: Color {
|
private var secondaryTextColor: Color {
|
||||||
colorScheme == .dark ? Color.green.opacity(0.8) : Color(red: 0, green: 0.5, blue: 0).opacity(0.8)
|
colorScheme == .dark ? Color.green.opacity(0.8) : Color(red: 0, green: 0.5, blue: 0).opacity(0.8)
|
||||||
}
|
}
|
||||||
|
// Slightly darker green for hash suffix emphasis
|
||||||
|
private var darkerTextColor: Color {
|
||||||
|
colorScheme == .dark ? Color.green : Color(red: 0, green: 0.4, blue: 0)
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
@@ -55,8 +59,11 @@ struct LocationNotesView: View {
|
|||||||
let c = manager.notes.count
|
let c = manager.notes.count
|
||||||
Text("\(c) \(c == 1 ? "note" : "notes") ")
|
Text("\(c) \(c == 1 ? "note" : "notes") ")
|
||||||
.font(.system(size: 16, weight: .bold, design: .monospaced))
|
.font(.system(size: 16, weight: .bold, design: .monospaced))
|
||||||
Text("@ #\(geohash)")
|
Text("@ ")
|
||||||
.font(.system(size: 16, weight: .bold, design: .monospaced))
|
.font(.system(size: 16, weight: .bold, design: .monospaced))
|
||||||
|
Text("#\(geohash)")
|
||||||
|
.font(.system(size: 16, weight: .bold, design: .monospaced))
|
||||||
|
.foregroundColor(textColor)
|
||||||
}
|
}
|
||||||
if let buildingName = locationManager.locationNames[.building], !buildingName.isEmpty {
|
if let buildingName = locationManager.locationNames[.building], !buildingName.isEmpty {
|
||||||
Text(buildingName)
|
Text(buildingName)
|
||||||
@@ -90,10 +97,18 @@ struct LocationNotesView: View {
|
|||||||
ForEach(manager.notes) { note in
|
ForEach(manager.notes) { note in
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
Text(note.displayName)
|
// Show @name without the #abcd suffix; timestamp in brackets
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
Text("@")
|
||||||
.font(.system(size: 12, weight: .semibold, design: .monospaced))
|
.font(.system(size: 12, weight: .semibold, design: .monospaced))
|
||||||
.foregroundColor(secondaryTextColor)
|
.foregroundColor(textColor)
|
||||||
Text(timestampText(for: note.createdAt))
|
let parts = splitSuffix(from: note.displayName)
|
||||||
|
Text(parts.0)
|
||||||
|
.font(.system(size: 12, weight: .semibold, design: .monospaced))
|
||||||
|
.foregroundColor(textColor)
|
||||||
|
}
|
||||||
|
let ts = timestampText(for: note.createdAt)
|
||||||
|
Text(ts.isEmpty ? "" : "[\(ts)]")
|
||||||
.font(.system(size: 11, design: .monospaced))
|
.font(.system(size: 11, design: .monospaced))
|
||||||
.foregroundColor(secondaryTextColor.opacity(0.8))
|
.foregroundColor(secondaryTextColor.opacity(0.8))
|
||||||
}
|
}
|
||||||
@@ -174,3 +189,16 @@ struct LocationNotesView: View {
|
|||||||
return f
|
return f
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to split a trailing #abcd suffix
|
||||||
|
private func splitSuffix(from name: String) -> (String, String) {
|
||||||
|
guard name.count >= 5 else { return (name, "") }
|
||||||
|
let suffix = String(name.suffix(5))
|
||||||
|
if suffix.first == "#", suffix.dropFirst().allSatisfy({ c in
|
||||||
|
("0"..."9").contains(String(c)) || ("a"..."f").contains(String(c)) || ("A"..."F").contains(String(c))
|
||||||
|
}) {
|
||||||
|
let base = String(name.dropLast(5))
|
||||||
|
return (base, suffix)
|
||||||
|
}
|
||||||
|
return (name, "")
|
||||||
|
}
|
||||||
|
|||||||
+260
-289
@@ -1,293 +1,264 @@
|
|||||||
Relay URL,Latitude,Longitude
|
Relay URL,Latitude,Longitude
|
||||||
relay.damus.io,37.7621,-122.3971
|
relay.laantungir.net,-19.4692,-42.5315
|
||||||
nostr-pub.wellorder.net,45.5229,-122.9898
|
relay.endfiat.money,43.6532,-79.3832
|
||||||
nostr.mom,50.4779,12.3713
|
relay.zone667.com,60.1699,24.9384
|
||||||
nostr.slothy.win,37.7621,-122.3971
|
shu04.shugur.net,25.2604,55.2989
|
||||||
nostr.einundzwanzig.space,50.1155,8.6842
|
relay.bitcoinartclock.com,50.4754,12.3683
|
||||||
nos.lol,50.4779,12.3713
|
relay.nostromo.social,49.4543,11.0746
|
||||||
relay.nostr.band,60.1695,24.9354
|
nostr.liberty.fans,36.9104,-89.5875
|
||||||
no.str.cr,9.9339,-84.0849
|
roles-az-achieving-somebody.trycloudflare.com,43.6532,-79.3832
|
||||||
nostr.massmux.com,50.1155,8.6842
|
nostr-rs-relay.dev.fedibtc.com,39.0438,-77.4874
|
||||||
nostr-relay.schnitzel.world,39.0437,-77.4875
|
relay.nostr.wirednet.jp,34.706,135.493
|
||||||
relay.nostr.com.au,37.7621,-122.3971
|
nostr.einundzwanzig.space,50.1109,8.68213
|
||||||
knostr.neutrine.com,48.8534,2.3488
|
relay.21e6.cz,50.1682,14.0546
|
||||||
nostr.nodeofsven.com,47.4875,8.2965
|
|
||||||
nostr.vulpem.com,49.4542,11.0775
|
|
||||||
nostr-verif.slothy.win,37.7621,-122.3971
|
|
||||||
relay.lexingtonbitcoin.org,37.7621,-122.3971
|
|
||||||
nostr-1.nbo.angani.co,-1.2615,36.7903
|
|
||||||
relay.wellorder.net,45.5229,-122.9898
|
|
||||||
nostr.easydns.ca,43.7064,-79.3986
|
|
||||||
relay.dwadziesciajeden.pl,52.2298,21.0118
|
|
||||||
nostr.data.haus,50.4779,12.3713
|
|
||||||
nostr.einundzwanzig.space,50.1155,8.6842
|
|
||||||
nostr.mom,50.4779,12.3713
|
|
||||||
nos.lol,50.4779,12.3713
|
|
||||||
relay.nostr.band,60.1695,24.9354
|
|
||||||
nostr.massmux.com,50.1155,8.6842
|
|
||||||
nostr.vulpem.com,49.4542,11.0775
|
|
||||||
relay.damus.io,37.7621,-122.3971
|
|
||||||
nostr-pub.wellorder.net,45.5229,-122.9898
|
|
||||||
no.str.cr,9.9339,-84.0849
|
|
||||||
relay.dwadziesciajeden.pl,52.2298,21.0118
|
|
||||||
nostr.data.haus,50.4779,12.3713
|
|
||||||
relay.wellorder.net,45.5229,-122.9898
|
|
||||||
relay.nostromo.social,49.4542,11.0775
|
|
||||||
offchain.pub,34.0522,-118.2437
|
|
||||||
relay.nostr.wirednet.jp,35.9356,139.3044
|
|
||||||
relay.nostrcheck.me,37.7621,-122.3971
|
|
||||||
nostrue.com,40.8043,-74.0121
|
|
||||||
nostr-relay.schnitzel.world,39.0437,-77.4875
|
|
||||||
nproxy.kristapsk.lv,60.1695,24.9354
|
|
||||||
nostr.spaceshell.xyz,37.7621,-122.3971
|
|
||||||
nostr-dev.wellorder.net,45.5229,-122.9898
|
|
||||||
nostr-verified.wellorder.net,45.5229,-122.9898
|
|
||||||
nostr.roundrockbitcoiners.com,40.8043,-74.0121
|
|
||||||
slick.mjex.me,39.0437,-77.4875
|
|
||||||
nostr.yael.at,52.3740,4.8897
|
|
||||||
relay.primal.net,37.7621,-122.3971
|
|
||||||
nostr.oxtr.dev,50.4779,12.3713
|
|
||||||
nostr.21crypto.ch,46.5160,6.6328
|
|
||||||
nostr.liberty.fans,38.8003,-90.6265
|
|
||||||
nostr-02.dorafactory.org,1.2897,103.8501
|
|
||||||
relay.hodl.ar,-32.9468,-60.6393
|
|
||||||
nostr.middling.mydns.jp,35.8089,140.1185
|
|
||||||
nostr.namek.link,37.7621,-122.3971
|
|
||||||
nostrja-kari.heguro.com,37.7621,-122.3971
|
|
||||||
nostr.hifish.org,47.3667,8.5500
|
|
||||||
nostr.rikmeijer.nl,50.4779,12.3713
|
|
||||||
black.nostrcity.club,41.8119,-87.6873
|
|
||||||
nostr.hekster.org,37.3924,-121.9623
|
|
||||||
relay.wavlake.com,41.2619,-95.8608
|
|
||||||
nostr.sagaciousd.com,49.2497,-123.1193
|
|
||||||
nostr.fbxl.net,43.7064,-79.3986
|
|
||||||
ithurtswhenip.ee,50.7990,-1.0913
|
|
||||||
relay2.nostrchat.io,49.4542,11.0775
|
|
||||||
relay1.nostrchat.io,60.1695,24.9354
|
|
||||||
nostr-01.yakihonne.com,1.3215,103.6957
|
|
||||||
nostr.sathoarder.com,48.5839,7.7455
|
|
||||||
nostr.overmind.lol,37.7621,-122.3971
|
|
||||||
relay.verified-nostr.com,37.7621,-122.3971
|
|
||||||
purplerelay.com,50.1155,8.6842
|
|
||||||
relay.orangepill.ovh,49.0127,1.9694
|
|
||||||
nostr-relay.psfoundation.info,39.0437,-77.4875
|
|
||||||
soloco.nl,37.7621,-122.3971
|
|
||||||
relay.froth.zone,60.1695,24.9354
|
|
||||||
nostr.stakey.net,52.5250,5.7181
|
|
||||||
nostr.2b9t.xyz,34.0522,-118.2437
|
|
||||||
pyramid.fiatjaf.com,50.1155,8.6842
|
|
||||||
a.nos.lol,50.4779,12.3713
|
|
||||||
relay.magiccity.live,25.8130,-80.2320
|
|
||||||
nostr.notribe.net,40.8344,-74.1377
|
|
||||||
freelay.sovbit.host,64.1355,-21.8954
|
|
||||||
relay.credenso.cafe,43.4254,-80.5112
|
|
||||||
nostr.huszonegy.world,47.4984,19.0404
|
|
||||||
multiplexer.huszonegy.world,47.4984,19.0404
|
|
||||||
bucket.coracle.social,37.7621,-122.3971
|
|
||||||
nostr.kungfu-g.rip,33.7865,-84.4454
|
|
||||||
relay.artx.market,43.7064,-79.3986
|
|
||||||
relay.notoshi.win,13.3622,100.9835
|
|
||||||
vitor.nostr1.com,40.7143,-74.0060
|
|
||||||
nostr-02.yakihonne.com,1.3215,103.6957
|
|
||||||
nostr-03.dorafactory.org,1.2897,103.8501
|
|
||||||
n.ok0.org,-36.8485,174.7635
|
|
||||||
nostr.0x7e.xyz,47.5056,8.7241
|
|
||||||
relay.nostr.net,50.4779,12.3713
|
|
||||||
strfry.openhoofd.nl,51.5717,3.7042
|
|
||||||
relay.fountain.fm,39.0997,-94.5786
|
|
||||||
relay.usefusion.ai,38.7135,-78.1594
|
|
||||||
relay.varke.eu,52.6958,6.1944
|
|
||||||
nostr.satstralia.com,64.1355,-21.8954
|
|
||||||
relay.13room.space,37.7621,-122.3971
|
|
||||||
nostr.myshosholoza.co.za,52.3710,4.9042
|
|
||||||
nostr.carroarmato0.be,50.8517,3.6089
|
|
||||||
nostr.dbtc.link,37.7621,-122.3971
|
|
||||||
orangepiller.org,60.1695,24.9354
|
|
||||||
adre.su,59.9386,30.3141
|
|
||||||
relay.sincensura.org,37.7621,-122.3971
|
|
||||||
relay.freeplace.nl,52.3740,4.8897
|
|
||||||
bostr.bitcointxoko.com,64.1355,-21.8954
|
|
||||||
nostr.plantroon.com,50.1025,8.6299
|
|
||||||
srtrelay.c-stellar.net,37.7621,-122.3971
|
|
||||||
nostr.jfischer.org,49.4453,11.0222
|
|
||||||
nostr.novacisko.cz,52.2298,21.0118
|
|
||||||
relay.lumina.rocks,49.4453,11.0222
|
|
||||||
nostr.tavux.tech,50.9519,1.8563
|
|
||||||
relay.nostrhub.fr,50.1155,8.6842
|
|
||||||
relay.agorist.space,52.3740,4.8897
|
|
||||||
chorus.pjv.me,45.5229,-122.9898
|
|
||||||
relay.cosmicbolt.net,37.3924,-121.9623
|
|
||||||
santo.iguanatech.net,40.8344,-74.1377
|
|
||||||
relay.tagayasu.xyz,45.4112,-75.6981
|
|
||||||
relay.mostro.network,40.8344,-74.1377
|
|
||||||
relay.zone667.com,60.1695,24.9354
|
|
||||||
relay5.bitransfer.org,37.7621,-122.3971
|
|
||||||
relay.illuminodes.com,47.6062,-122.3321
|
|
||||||
relay2.angor.io,50.1155,8.6842
|
|
||||||
relay.satsdays.com,1.2897,103.8501
|
|
||||||
relay.angor.io,50.1155,8.6842
|
|
||||||
orangesync.tech,50.9333,6.9500
|
|
||||||
nostr-relay.cbrx.io,37.7621,-122.3971
|
|
||||||
relay.21e6.cz,50.0880,14.4208
|
|
||||||
nostr.chaima.info,50.1155,8.6842
|
|
||||||
relay.satlantis.io,32.8546,-79.9748
|
|
||||||
relay.digitalezukunft.cyou,45.5088,-73.5878
|
|
||||||
relay.tapestry.ninja,40.8043,-74.0121
|
|
||||||
relay.minibolt.info,37.7621,-122.3971
|
|
||||||
nostr.bilthon.dev,25.8130,-80.2320
|
|
||||||
nostr.makibisskey.work,37.7621,-122.3971
|
|
||||||
relay.mattybs.lol,37.7621,-122.3971
|
|
||||||
noxir.kpherox.dev,34.8436,135.5084
|
|
||||||
sendit.nosflare.com,37.7621,-122.3971
|
|
||||||
relay.coinos.io,37.7621,-122.3971
|
|
||||||
relay.nostraddress.com,37.7621,-122.3971
|
|
||||||
wot.nostr.party,36.1659,-86.7844
|
|
||||||
nostrelites.org,41.8500,-87.6500
|
|
||||||
relay.nostriot.com,43.7064,-79.3986
|
|
||||||
prl.plus,55.7522,37.6156
|
|
||||||
zap.watch,45.5088,-73.5878
|
|
||||||
wot.codingarena.top,50.4779,12.3713
|
|
||||||
nostr.azzamo.net,52.2284,21.0522
|
|
||||||
wot.sudocarlos.com,43.7064,-79.3986
|
|
||||||
relay.lnfi.network,45.6241,8.7851
|
|
||||||
wot.nostr.net,37.7621,-122.3971
|
|
||||||
relay.nostrdice.com,-33.8678,151.2073
|
|
||||||
wot.sebastix.social,51.3700,6.1681
|
|
||||||
wheat.happytavern.co,37.7621,-122.3971
|
|
||||||
relay.sigit.io,50.4779,12.3713
|
|
||||||
strfry.bonsai.com,37.8716,-122.2728
|
|
||||||
travis-shears-nostr-relay-v2.fly.dev,41.8119,-87.6873
|
|
||||||
satsage.xyz,37.3924,-121.9623
|
|
||||||
relay.degmods.com,50.4779,12.3713
|
|
||||||
nostr.community.ath.cx,45.5088,-73.5878
|
|
||||||
nostr.coincrowd.fund,39.0437,-77.4875
|
|
||||||
strfry.shock.network,41.8847,-88.2040
|
|
||||||
cyberspace.nostr1.com,40.7143,-74.0060
|
|
||||||
relay02.lnfi.network,39.0997,-94.5786
|
|
||||||
nostr-rs-relay.dev.fedibtc.com,39.0437,-77.4875
|
|
||||||
relay.davidebtc.me,50.1155,8.6842
|
|
||||||
wot.dtonon.com,37.7621,-122.3971
|
|
||||||
relay.goodmorningbitcoin.com,37.7621,-122.3971
|
|
||||||
articles.layer3.news,37.3394,-121.8950
|
|
||||||
bostr.syobon.net,37.7621,-122.3971
|
|
||||||
nostr.agentcampfire.com,52.3740,4.8897
|
|
||||||
nostr.thebiglake.org,32.7244,-96.6755
|
|
||||||
schnorr.me,37.7621,-122.3971
|
|
||||||
relay.wolfcoil.com,35.6090,139.7302
|
|
||||||
nostr.camalolo.com,24.1469,120.6839
|
|
||||||
nostr.tac.lol,47.4740,-122.2610
|
|
||||||
dev-relay.lnfi.network,39.0997,-94.5786
|
|
||||||
relay.bitcoinveneto.org,64.1355,-21.8954
|
|
||||||
nostr.red5d.dev,37.7621,-122.3971
|
|
||||||
relay-testnet.k8s.layer3.news,37.3394,-121.8950
|
|
||||||
promenade.fiatjaf.com,50.1155,8.6842
|
|
||||||
nostrelay.memory-art.xyz,37.7621,-122.3971
|
|
||||||
inbox.azzamo.net,52.2284,21.0522
|
|
||||||
social.proxymana.net,60.1695,24.9354
|
|
||||||
relay.netstr.io,53.3331,-6.2489
|
|
||||||
premium.primal.net,37.7621,-122.3971
|
|
||||||
nostr.lojong.info,37.7621,-122.3971
|
|
||||||
nostr-rs-relay-ishosta.phamthanh.me,37.7621,-122.3971
|
|
||||||
relay.stream.labs.h3.se,59.3294,18.0687
|
|
||||||
tollbooth.stens.dev,51.4566,7.0123
|
|
||||||
relay.chakany.systems,37.7621,-122.3971
|
|
||||||
relay.mwaters.net,50.9519,1.8563
|
|
||||||
nostr-relay.shirogaku.xyz,37.7621,-122.3971
|
|
||||||
kitchen.zap.cooking,37.7621,-122.3971
|
|
||||||
relay.arx-ccn.com,50.4779,12.3713
|
|
||||||
relay.fr13nd5.com,50.1155,8.6842
|
|
||||||
nostr.tegila.com.br,39.0437,-77.4875
|
|
||||||
relay.jeffg.fyi,43.7064,-79.3986
|
|
||||||
relay.bullishbounty.com,37.7621,-122.3971
|
|
||||||
nostr.spicyz.io,37.7621,-122.3971
|
|
||||||
relay04.lnfi.network,39.0997,-94.5786
|
relay04.lnfi.network,39.0997,-94.5786
|
||||||
vidono.apps.slidestr.net,48.8534,2.3488
|
relay.chorus.community,50.1109,8.68213
|
||||||
relay03.lnfi.network,39.0997,-94.5786
|
relay.nostr.place,32.7767,-96.797
|
||||||
communities.nos.social,40.8344,-74.1377
|
relay.vrtmrz.net,43.6532,-79.3832
|
||||||
relay.evanverma.com,40.8344,-74.1377
|
noxir.kpherox.dev,34.8587,135.509
|
||||||
nostrelay.circum.space,51.4566,7.0123
|
wot.nostr.net,43.6532,-79.3832
|
||||||
wot.brightbolt.net,47.6928,-116.7850
|
relay.cypherflow.ai,48.8566,2.35222
|
||||||
relayrs.notoshi.win,37.7621,-122.3971
|
wot.sudocarlos.com,51.5072,-0.127586
|
||||||
fenrir-s.notoshi.win,37.7621,-122.3971
|
nostr.jerrynya.fun,31.2304,121.474
|
||||||
relay.nsnip.io,60.1695,24.9354
|
nostr2.girino.org,43.6532,-79.3832
|
||||||
x.kojira.io,37.7621,-122.3971
|
nostrings-relay-dev.fly.dev,41.8781,-87.6298
|
||||||
relay.hasenpfeffr.com,39.0437,-77.4875
|
fanfares.nostr1.com,40.7128,-74.006
|
||||||
|
nostr.red5d.dev,43.6532,-79.3832
|
||||||
|
nostr.hifish.org,47.4043,8.57398
|
||||||
|
nostr.now,36.55,139.733
|
||||||
|
relay.nostr.band,60.1699,24.9384
|
||||||
|
relay.wavlake.com,41.2619,-95.8608
|
||||||
|
nostr.bilthon.dev,25.8128,-80.2377
|
||||||
|
khatru.nostrver.se,51.8933,4.42083
|
||||||
|
relay.bitcoindistrict.org,43.6532,-79.3832
|
||||||
|
nostr.makibisskey.work,43.6532,-79.3832
|
||||||
|
relay.nostraddress.com,43.6532,-79.3832
|
||||||
|
relay.jmoose.rocks,60.1699,24.9384
|
||||||
|
relay.davidebtc.me,51.5072,-0.127586
|
||||||
|
a.nos.lol,50.4754,12.3683
|
||||||
|
nostr.tadryanom.me,43.6532,-79.3832
|
||||||
|
relay.nostrdice.com,-33.8688,151.209
|
||||||
|
relay.lumina.rocks,49.0291,8.35695
|
||||||
|
relay.goodmorningbitcoin.com,43.6532,-79.3832
|
||||||
|
nostr.rtvslawenia.com,49.4543,11.0746
|
||||||
|
relay.mattybs.lol,43.6532,-79.3832
|
||||||
|
relay-dev.satlantis.io,40.8302,-74.1299
|
||||||
|
nostream.breadslice.com,43.6532,-79.3832
|
||||||
|
nostr.vulpem.com,49.4543,11.0746
|
||||||
|
nostr.rohoss.com,50.1109,8.68213
|
||||||
|
articles.layer3.news,37.3387,-121.885
|
||||||
|
nos.lol,50.4754,12.3683
|
||||||
|
relay.artx.market,43.652,-79.3633
|
||||||
|
wot.sebastix.social,51.8933,4.42083
|
||||||
|
alien.macneilmediagroup.com,43.6532,-79.3832
|
||||||
|
relay.unknown.cloud,43.6532,-79.3832
|
||||||
|
nostr.lojong.info,43.6532,-79.3832
|
||||||
|
nostr.zenon.network,43.5009,-70.4428
|
||||||
|
orangesync.tech,50.1109,8.68213
|
||||||
|
nostr.davidebtc.me,51.5072,-0.127586
|
||||||
|
internationalright-wing.org,-22.5022,-48.7114
|
||||||
|
nostr.rikmeijer.nl,50.4754,12.3683
|
||||||
|
ynostr.yael.at,60.1699,24.9384
|
||||||
|
ithurtswhenip.ee,51.223,6.78245
|
||||||
|
relay.wellorder.net,45.5201,-122.99
|
||||||
|
nostr.sathoarder.com,48.5734,7.75211
|
||||||
|
purplerelay.com,50.1109,8.68213
|
||||||
|
yabu.me,35.6092,139.73
|
||||||
|
nostr.88mph.life,43.6532,-79.3832
|
||||||
|
nostr.overmind.lol,43.6532,-79.3832
|
||||||
|
rnostr.breadslice.com,43.6532,-79.3832
|
||||||
|
zap.watch,45.5029,-73.5723
|
||||||
|
wot.basspistol.org,49.4521,11.0767
|
||||||
|
shu01.shugur.net,21.4902,39.2246
|
||||||
|
relay.electriclifestyle.com,26.2897,-80.1293
|
||||||
|
relay.mccormick.cx,52.3563,4.95714
|
||||||
|
nostr.middling.mydns.jp,35.8099,140.12
|
||||||
|
nostr.smut.cloud,43.6532,-79.3832
|
||||||
|
satsage.xyz,37.3986,-121.964
|
||||||
|
srtrelay.c-stellar.net,43.6532,-79.3832
|
||||||
|
nostr.0x7e.xyz,47.4988,8.72369
|
||||||
|
shu02.shugur.net,21.4902,39.2246
|
||||||
|
nostrelites.org,41.8781,-87.6298
|
||||||
|
relay-admin.thaliyal.com,40.8218,-74.45
|
||||||
|
wot.soundhsa.com,34.0479,-118.256
|
||||||
|
nostrcheck.me,43.6532,-79.3832
|
||||||
|
relay.nostrhub.tech,49.4543,11.0746
|
||||||
|
relay.stream.labs.h3.se,59.4016,17.9455
|
||||||
|
nostrelay.memory-art.xyz,43.6532,-79.3832
|
||||||
|
nostr.n7ekb.net,47.4941,-122.294
|
||||||
|
relay.nosto.re,51.8933,4.42083
|
||||||
|
nostr.girino.org,43.6532,-79.3832
|
||||||
|
relay.siamdev.cc,13.9178,100.424
|
||||||
|
nostr.mehdibekhtaoui.com,49.4939,-1.54813
|
||||||
|
orangepiller.org,60.1699,24.9384
|
||||||
|
nostr.plantroon.com,50.1013,8.62643
|
||||||
|
nostr-verified.wellorder.net,45.5201,-122.99
|
||||||
|
relay.primal.net,43.6532,-79.3832
|
||||||
|
relay.bitcoinveneto.org,64.1466,-21.9426
|
||||||
|
relay.hasenpfeffr.com,39.0438,-77.4874
|
||||||
|
strfry.openhoofd.nl,51.9229,4.40833
|
||||||
|
relay.aloftus.io,34.0881,-118.379
|
||||||
|
nostr.spaceshell.xyz,43.6532,-79.3832
|
||||||
|
nostr-relay-1.trustlessenterprise.com,43.6532,-79.3832
|
||||||
|
ribo.af.nostria.app,-26.2041,28.0473
|
||||||
|
nostr.tac.lol,47.4748,-122.273
|
||||||
|
relay.satlantis.io,32.8769,-80.0114
|
||||||
|
nostr.azzamo.net,52.2633,21.0283
|
||||||
|
strfry.bonsai.com,37.8715,-122.273
|
||||||
|
relay.agora.social,50.7383,15.0648
|
||||||
|
nostr-relay.amethyst.name,39.0067,-77.4291
|
||||||
|
relay.toastr.net,40.8054,-74.0241
|
||||||
|
nostr.thebiglake.org,32.71,-96.6745
|
||||||
|
nostr-relay.nextblockvending.com,47.674,-122.122
|
||||||
|
vitor.nostr1.com,40.7057,-74.0136
|
||||||
|
relay.btcforplebs.com,43.6532,-79.3832
|
||||||
|
relay.g1sms.fr,43.9432,2.07537
|
||||||
|
nostr.jfischer.org,49.0291,8.35696
|
||||||
|
nostr.mikoshi.de,52.52,13.405
|
||||||
|
relay.notoshi.win,13.7829,100.546
|
||||||
|
pyramid.fiatjaf.com,50.1109,8.68213
|
||||||
|
relay.coinos.io,43.6532,-79.3832
|
||||||
|
relay.freeplace.nl,52.3676,4.90414
|
||||||
|
nostr-relay.psfoundation.info,39.0438,-77.4874
|
||||||
|
relay.copylaradio.com,51.223,6.78245
|
||||||
|
relay.exit.pub,50.4754,12.3683
|
||||||
|
freelay.sovbit.host,64.1476,-21.9392
|
||||||
|
nostr.satstralia.com,64.1476,-21.9392
|
||||||
|
nostr.l484.com,30.2944,-97.6223
|
||||||
|
nostr.rblb.it,43.4633,11.8796
|
||||||
|
nostr.2b9t.xyz,34.0549,-118.243
|
||||||
|
nostr.dlsouza.lol,50.1109,8.68213
|
||||||
|
strfry.shock.network,41.8959,-88.2169
|
||||||
|
offchain.pub,36.1809,-115.241
|
||||||
|
nostr-01.yakihonne.com,1.32123,103.695
|
||||||
|
nostr.kungfu-g.rip,33.7946,-84.4488
|
||||||
|
relay.letsfo.com,51.098,17.0321
|
||||||
|
relay.lifpay.me,1.35208,103.82
|
||||||
|
relay.damus.io,43.6532,-79.3832
|
||||||
|
relay2.angor.io,48.1046,11.6002
|
||||||
|
relayrs.notoshi.win,43.6532,-79.3832
|
||||||
|
relay2.ngengine.org,43.6532,-79.3832
|
||||||
|
portal-relay.pareto.space,49.4543,11.0746
|
||||||
|
inbox.azzamo.net,52.2633,21.0283
|
||||||
|
nostr-dev.wellorder.net,45.5201,-122.99
|
||||||
|
nostr.stakey.net,52.3676,4.90414
|
||||||
|
relay.13room.space,43.6532,-79.3832
|
||||||
|
relay.fountain.fm,39.0997,-94.5786
|
||||||
|
black.nostrcity.club,41.8781,-87.6298
|
||||||
|
nostr-2.21crypto.ch,47.4988,8.72369
|
||||||
|
dev-nostr.bityacht.io,25.0797,121.234
|
||||||
|
santo.iguanatech.net,40.8302,-74.1299
|
||||||
|
relay.angor.io,48.1046,11.6002
|
||||||
|
relay.tagayasu.xyz,43.6715,-79.38
|
||||||
|
relay.npubhaus.com,43.6532,-79.3832
|
||||||
relay01.lnfi.network,39.0997,-94.5786
|
relay01.lnfi.network,39.0997,-94.5786
|
||||||
nostr.rtvslawenia.com,49.4542,11.0775
|
nostr.myshosholoza.co.za,52.3676,4.90414
|
||||||
relay.g1sms.fr,43.9298,2.1480
|
relay02.lnfi.network,39.0997,-94.5786
|
||||||
nostr.kalf.org,52.3740,4.8897
|
gnostr.com,40.9017,29.1616
|
||||||
nostr.rblb.it,37.7621,-122.3971
|
nostr.sagaciousd.com,49.2827,-123.121
|
||||||
nostr.4rs.nl,49.4453,11.0222
|
nostr.night7.space,50.4754,12.3683
|
||||||
relay.vrtmrz.net,37.7621,-122.3971
|
schnorr.me,43.6532,-79.3832
|
||||||
nostr.hoppe-relay.it.com,45.5946,-121.1787
|
nostr.blankfors.se,60.1699,24.9384
|
||||||
relay-rpi.edufeed.org,49.4453,11.0222
|
relay.mostro.network,40.8302,-74.1299
|
||||||
relay.copylaradio.com,50.7990,-1.0913
|
purpura.cloud,43.6532,-79.3832
|
||||||
relay.ru.ac.th,13.7540,100.5014
|
ribo.eu.nostria.app,52.3676,4.90414
|
||||||
relay.bitcoinartclock.com,50.4779,12.3713
|
vidono.apps.slidestr.net,48.8566,2.35222
|
||||||
wot.downisontheup.ca,47.6062,-122.3321
|
wheat.happytavern.co,43.6532,-79.3832
|
||||||
nostr.coincards.com,43.7064,-79.3986
|
nostr.faultables.net,43.6532,-79.3832
|
||||||
relay.etch.social,41.2619,-95.8608
|
relay5.bitransfer.org,43.6532,-79.3832
|
||||||
relay.mess.ch,47.1345,9.0964
|
relay.nostrhub.fr,48.1046,11.6002
|
||||||
relay.holzeis.me,37.7621,-122.3971
|
nostr.thaliyal.com,40.8218,-74.45
|
||||||
relay-admin.thaliyal.com,40.8220,-74.4488
|
relay.holzeis.me,43.6532,-79.3832
|
||||||
nostr.thaliyal.com,40.8220,-74.4488
|
relay.nostriot.com,41.5695,-83.9786
|
||||||
strfry.felixzieger.de,50.1025,8.6299
|
nostr.openhoofd.nl,51.9229,4.40833
|
||||||
nostr.smut.cloud,37.7621,-122.3971
|
relay.nostr.vet,52.6467,4.7395
|
||||||
r.bitcoinhold.net,37.7621,-122.3971
|
nostr.camalolo.com,24.1469,120.684
|
||||||
nostr.blankfors.se,60.1695,24.9354
|
relay.origin.land,35.6673,139.751
|
||||||
portal-relay.pareto.space,49.4453,11.0222
|
relay.chakany.systems,43.6532,-79.3832
|
||||||
relay.getsafebox.app,43.7064,-79.3986
|
relay.0xchat.com,1.35208,103.82
|
||||||
relay.anzenkodo.workers.dev,37.7621,-122.3971
|
nostr.mom,50.4754,12.3683
|
||||||
relay.nostrhub.tech,49.4453,11.0222
|
4u2ni0zjbjvni.clorecloud.net,43.6532,-79.3832
|
||||||
nostr.prl.plus,52.3740,4.8897
|
prl.plus,55.7623,37.6381
|
||||||
nostr-2.21crypto.ch,46.5160,6.6328
|
relay.moinsen.com,50.4754,12.3683
|
||||||
nostr.zenon.network,40.7143,-74.0060
|
nostr-02.czas.top,53.471,9.88208
|
||||||
nostr-relay.amethyst.name,35.7721,-78.6386
|
relay.sigit.io,50.4754,12.3683
|
||||||
relayone.geektank.ai,17.1210,-61.8433
|
relay.nostrcheck.me,43.6532,-79.3832
|
||||||
fanfares.nostr1.com,40.7143,-74.0060
|
relay03.lnfi.network,39.0997,-94.5786
|
||||||
wot.geektank.ai,17.1210,-61.8433
|
relay.sincensura.org,43.6532,-79.3832
|
||||||
relay-dev.satlantis.io,40.8344,-74.1377
|
nostr.coincards.com,53.5501,-113.469
|
||||||
relay.siamdev.cc,13.9178,100.4240
|
nostr-03.dorafactory.org,1.35208,103.82
|
||||||
relay.nosto.re,51.3700,6.1681
|
relay.credenso.cafe,43.1149,-80.7228
|
||||||
wot.soundhsa.com,39.0997,-94.5786
|
nostr.fbxl.net,48.3809,-89.2477
|
||||||
nostr.n7ekb.net,47.5707,-122.2221
|
relay.bullishbounty.com,43.6532,-79.3832
|
||||||
relayone.soundhsa.com,39.0997,-94.5786
|
nos.xmark.cc,50.6924,3.20113
|
||||||
relay.puresignal.news,37.7621,-122.3971
|
x.kojira.io,43.6532,-79.3832
|
||||||
relay.nostx.io,37.7621,-122.3971
|
wot.sovbit.host,64.1466,-21.9426
|
||||||
nostr.now,35.6090,139.7302
|
shu05.shugur.net,48.8566,2.35222
|
||||||
relay.artiostr.ch,37.7621,-122.3971
|
nostr.carroarmato0.be,50.9928,3.26317
|
||||||
relay.oldenburg.cool,50.1155,8.6842
|
relay.cosmicbolt.net,37.3986,-121.964
|
||||||
theoutpost.life,64.1355,-21.8954
|
r.bitcoinhold.net,43.6532,-79.3832
|
||||||
khatru.nostrver.se,51.3700,6.1681
|
nostr.diakod.com,43.6532,-79.3832
|
||||||
relay.wavefunc.live,37.7915,-122.4018
|
nostr-relay.cbrx.io,43.6532,-79.3832
|
||||||
nostr-relay.zimage.com,34.0522,-118.2437
|
nostr.coincrowd.fund,39.0438,-77.4874
|
||||||
relay.javi.space,43.4628,11.8807
|
cyberspace.nostr1.com,40.7128,-74.006
|
||||||
bostr.shop,42.8865,-78.8784
|
relay.barine.co,43.6532,-79.3832
|
||||||
relay.letsfo.com,52.2298,21.0118
|
relay.orangepill.ovh,49.1689,-0.358841
|
||||||
alien.macneilmediagroup.com,37.7621,-122.3971
|
no.str.cr,9.92857,-84.0528
|
||||||
rn1.sotiras.org,37.7621,-122.3971
|
nostr.casa21.space,43.6532,-79.3832
|
||||||
gnostr.com,42.6975,23.3241
|
relay.mwaters.net,50.9871,2.12554
|
||||||
relay.conduit.market,37.7621,-122.3971
|
relay.magiccity.live,25.8128,-80.2377
|
||||||
relay.hivetalk.org,37.3924,-121.9623
|
relayone.soundhsa.com,34.0479,-118.256
|
||||||
nostr.l484.com,30.2960,-97.6396
|
slick.mjex.me,39.048,-77.4817
|
||||||
relay.chorus.community,50.1155,8.6842
|
relay.utxo.farm,35.6916,139.768
|
||||||
nostr-relay.moe.gift,37.7621,-122.3971
|
theoutpost.life,64.1476,-21.9392
|
||||||
relay.nostrcal.com,37.7621,-122.3971
|
nostr.hekster.org,37.3986,-121.964
|
||||||
temp.iris.to,37.7621,-122.3971
|
strfry.felixzieger.de,50.1013,8.62643
|
||||||
librerelay.aaroniumii.com,37.7621,-122.3971
|
relay.mess.ch,47.3591,8.55292
|
||||||
nostr-relay-1.trustlessenterprise.com,37.7621,-122.3971
|
wot.codingarena.top,50.4754,12.3683
|
||||||
relay.barine.co,37.7621,-122.3971
|
nostrelay.circum.space,51.2217,6.77616
|
||||||
nostr.rohoss.com,48.1374,11.5755
|
nostr-relay.online,43.6532,-79.3832
|
||||||
|
temp.iris.to,43.6532,-79.3832
|
||||||
|
wot.dergigi.com,64.1476,-21.9392
|
||||||
|
wot.brightbolt.net,47.6735,-116.781
|
||||||
|
nostr-rs-relay-ishosta.phamthanh.me,43.6532,-79.3832
|
||||||
wot.nostr.place,30.2672,-97.7431
|
wot.nostr.place,30.2672,-97.7431
|
||||||
relay.utxo.farm,34.7331,135.8183
|
ribo.us.nostria.app,41.5868,-93.625
|
||||||
relay.bankless.at,37.7621,-122.3971
|
relay.nostr.net,50.4754,12.3683
|
||||||
relay.toastr.net,40.8043,-74.0121
|
nostr-02.dorafactory.org,1.35208,103.82
|
||||||
nostr.excentered.com,52.5244,13.4105
|
relay.tapestry.ninja,40.8054,-74.0241
|
||||||
relay.mccormick.cx,52.3740,4.8897
|
adre.su,59.9311,30.3609
|
||||||
relay.cypherflow.ai,48.8534,2.3488
|
librerelay.aaroniumii.com,43.6532,-79.3832
|
||||||
relay.laantungir.net,45.3134,-73.8725
|
nostr-pub.wellorder.net,45.5201,-122.99
|
||||||
nostr.veladan.dev,37.7621,-122.3971
|
kitchen.zap.cooking,43.6532,-79.3832
|
||||||
nostr.tadryanom.me,37.7621,-122.3971
|
nostr.21crypto.ch,47.4988,8.72369
|
||||||
nostr-relay.online,37.7621,-122.3971
|
nostr-02.yakihonne.com,1.32123,103.695
|
||||||
nostr.night7.space,50.4779,12.3713
|
relay.javi.space,43.4633,11.8796
|
||||||
dev-nostr.bityacht.io,25.0531,121.5264
|
nostr.ser1.net,12.9716,77.5946
|
||||||
|
relay-rpi.edufeed.org,49.4543,11.0746
|
||||||
|
premium.primal.net,43.6532,-79.3832
|
||||||
|
relay.degmods.com,50.4754,12.3683
|
||||||
|
relay.arx-ccn.com,50.4754,12.3683
|
||||||
|
nostr.chaima.info,51.223,6.78245
|
||||||
|
relay.illuminodes.com,47.6061,-122.333
|
||||||
|
relay.nostx.io,43.6532,-79.3832
|
||||||
|
relay.puresignal.news,43.6532,-79.3832
|
||||||
|
fenrir-s.notoshi.win,43.6532,-79.3832
|
||||||
|
relay.getsafebox.app,43.6532,-79.3832
|
||||||
|
relay.conduit.market,43.6532,-79.3832
|
||||||
|
relay.jeffg.fyi,43.6532,-79.3832
|
||||||
|
nproxy.kristapsk.lv,60.1699,24.9384
|
||||||
|
relay.olas.app,50.4754,12.3683
|
||||||
|
relay.dwadziesciajeden.pl,52.2297,21.0122
|
||||||
|
relay-testnet.k8s.layer3.news,37.3387,-121.885
|
||||||
|
nostr.pleb.one,38.6327,-90.1961
|
||||||
|
relay.digitalezukunft.cyou,45.5019,-73.5674
|
||||||
|
relay.evanverma.com,40.8302,-74.1299
|
||||||
|
wot.dtonon.com,43.6532,-79.3832
|
||||||
|
relay.seq1.net,43.6532,-79.3832
|
||||||
|
nostr.kalf.org,52.3676,4.90414
|
||||||
|
nostr.snowbla.de,60.1699,24.9384
|
||||||
|
nostr.spicyz.io,43.6532,-79.3832
|
||||||
|
nostr-relay.zimage.com,34.282,-118.439
|
||||||
|
nostr.spacecitynode.com,29.7057,-95.2706
|
||||||
|
dev-relay.lnfi.network,39.0997,-94.5786
|
||||||
|
itanostr.space,52.2931,4.79099
|
||||||
|
|||||||
|
Reference in New Issue
Block a user