mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 06:25:20 +00:00
Location notes: restore timestamps in notes list; remove loading state from manager and sheet (no spinner/animation)
This commit is contained in:
@@ -21,12 +21,8 @@ final class LocationNotesManager: ObservableObject {
|
||||
}
|
||||
|
||||
@Published private(set) var notes: [Note] = [] // reverse-chron sorted
|
||||
@Published private(set) var isLoading: Bool = true
|
||||
@Published private(set) var geohash: String
|
||||
private var subscriptionID: String?
|
||||
private var loadingWorkItem: DispatchWorkItem?
|
||||
private var loadingStartedAt: Date?
|
||||
private var loadingMinDuration: TimeInterval = 0
|
||||
|
||||
init(geohash: String) {
|
||||
self.geohash = geohash.lowercased()
|
||||
@@ -46,11 +42,6 @@ final class LocationNotesManager: ObservableObject {
|
||||
}
|
||||
|
||||
private func subscribe() {
|
||||
// Begin loading: always display Matrix for a randomized 1–3 seconds
|
||||
isLoading = true
|
||||
loadingStartedAt = Date()
|
||||
loadingMinDuration = Double.random(in: 1.0...3.0)
|
||||
loadingWorkItem?.cancel()
|
||||
let subID = "locnotes-\(geohash)-\(UUID().uuidString.prefix(8))"
|
||||
subscriptionID = subID
|
||||
// For persistent notes, allow relays to return recent history without an aggressive time cutoff
|
||||
@@ -67,24 +58,7 @@ final class LocationNotesManager: ObservableObject {
|
||||
let note = Note(id: event.id, pubkey: event.pubkey, content: event.content, createdAt: ts, nickname: nick)
|
||||
self.notes.append(note)
|
||||
self.notes.sort { $0.createdAt > $1.createdAt }
|
||||
// Respect minimum loader time
|
||||
if self.isLoading {
|
||||
let elapsed = Date().timeIntervalSince(self.loadingStartedAt ?? Date())
|
||||
if elapsed >= self.loadingMinDuration {
|
||||
self.isLoading = false
|
||||
} else {
|
||||
self.loadingWorkItem?.cancel()
|
||||
let remaining = self.loadingMinDuration - elapsed
|
||||
let wi = DispatchWorkItem { [weak self] in self?.isLoading = false }
|
||||
self.loadingWorkItem = wi
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + remaining, execute: wi)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure we hide after the minimum loader duration even if no events arrive
|
||||
let wi = DispatchWorkItem { [weak self] in self?.isLoading = false }
|
||||
loadingWorkItem = wi
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + loadingMinDuration, execute: wi)
|
||||
}
|
||||
|
||||
/// Send a location note for the current geohash using the per-geohash identity.
|
||||
@@ -105,18 +79,6 @@ final class LocationNotesManager: ObservableObject {
|
||||
// Optimistic local-echo
|
||||
let echo = Note(id: event.id, pubkey: id.publicKeyHex, content: trimmed, createdAt: Date(), nickname: nickname)
|
||||
self.notes.insert(echo, at: 0)
|
||||
if self.isLoading {
|
||||
let elapsed = Date().timeIntervalSince(self.loadingStartedAt ?? Date())
|
||||
if elapsed >= self.loadingMinDuration {
|
||||
self.isLoading = false
|
||||
} else {
|
||||
self.loadingWorkItem?.cancel()
|
||||
let remaining = self.loadingMinDuration - elapsed
|
||||
let wi = DispatchWorkItem { [weak self] in self?.isLoading = false }
|
||||
self.loadingWorkItem = wi
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + remaining, execute: wi)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
SecureLogger.error("LocationNotesManager: failed to send note: \(error)", category: .session)
|
||||
}
|
||||
@@ -128,7 +90,5 @@ final class LocationNotesManager: ObservableObject {
|
||||
NostrRelayManager.shared.unsubscribe(id: sub)
|
||||
subscriptionID = nil
|
||||
}
|
||||
loadingWorkItem?.cancel()
|
||||
loadingWorkItem = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1235,41 +1235,35 @@ struct ContentView: View {
|
||||
LocationNotesView(geohash: gh)
|
||||
.environmentObject(viewModel)
|
||||
} else {
|
||||
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: { showLocationNotes = false }) {
|
||||
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))
|
||||
VStack(spacing: 12) {
|
||||
HStack {
|
||||
Text("notes")
|
||||
.font(.system(size: 16, weight: .bold, design: .monospaced))
|
||||
Spacer()
|
||||
Button(action: { showLocationNotes = false }) {
|
||||
Image(systemName: "xmark")
|
||||
.font(.system(size: 13, weight: .semibold, design: .monospaced))
|
||||
.foregroundColor(textColor)
|
||||
.frame(width: 32, height: 32)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityLabel("Close")
|
||||
}
|
||||
// Simple system spinner while waiting for geohash
|
||||
ProgressView()
|
||||
.progressViewStyle(.circular)
|
||||
.frame(height: 44)
|
||||
.padding(.horizontal, 12)
|
||||
.background(backgroundColor.opacity(0.95))
|
||||
Text("location unavailable")
|
||||
.font(.system(size: 14, design: .monospaced))
|
||||
.foregroundColor(secondaryTextColor)
|
||||
Button("enable location") {
|
||||
LocationChannelManager.shared.enableLocationChannels()
|
||||
LocationChannelManager.shared.refreshChannels()
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
Spacer()
|
||||
}
|
||||
.background(backgroundColor)
|
||||
.foregroundColor(textColor)
|
||||
.onAppear {
|
||||
LocationChannelManager.shared.enableLocationChannels()
|
||||
LocationChannelManager.shared.refreshChannels()
|
||||
}
|
||||
.onChange(of: locationManager.availableChannels) { channels in
|
||||
if notesGeohash == nil, let block = channels.first(where: { $0.level == .block }) {
|
||||
notesGeohash = block.geohash
|
||||
|
||||
@@ -72,6 +72,9 @@ struct LocationNotesView: View {
|
||||
Text(note.displayName)
|
||||
.font(.system(size: 12, weight: .semibold, design: .monospaced))
|
||||
.foregroundColor(secondaryTextColor)
|
||||
Text(note.createdAt, style: .time)
|
||||
.font(.system(size: 11, design: .monospaced))
|
||||
.foregroundColor(secondaryTextColor.opacity(0.8))
|
||||
}
|
||||
Text(note.content)
|
||||
.font(.system(size: 14, design: .monospaced))
|
||||
|
||||
Reference in New Issue
Block a user