Add useful view for note-not-found state in quoted notes
Changelog-Added: Added a view for quotes notes that could not be loaded, including actionable items Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
@@ -15,7 +15,8 @@ struct EventLoaderView<Content: View>: View {
|
||||
let event_id: NoteId
|
||||
let relayHints: [RelayURL]
|
||||
@State var event: NostrEvent?
|
||||
@State var subscription_uuid: String = UUID().description
|
||||
@State private var eventNotFound: Bool = false
|
||||
@State private var isReloading: Bool = false
|
||||
let content: (NostrEvent) -> Content
|
||||
|
||||
/// Creates an event loader view.
|
||||
@@ -34,6 +35,17 @@ struct EventLoaderView<Content: View>: View {
|
||||
_event = State(initialValue: event)
|
||||
}
|
||||
|
||||
/// Loads the event from nostrdb or the network using relay hints or the default relay pool.
|
||||
///
|
||||
/// This method attempts to fetch the event via `nostrNetwork.reader.lookup`, which first checks
|
||||
/// nostrdb for a cached copy, then queries the network if not found locally. Network queries use
|
||||
/// either the specified relay hints (if provided) or the user's relay pool (if no hints are provided).
|
||||
/// On success, sets `event` and clears `eventNotFound`. On failure, sets `eventNotFound` to true.
|
||||
///
|
||||
/// Side effects:
|
||||
/// - Updates `event` with the fetched event on success
|
||||
/// - Updates `eventNotFound` flag based on the result
|
||||
/// - Logs debug information when relay hints are used
|
||||
func load() async {
|
||||
let targetRelays = relayHints.isEmpty ? nil : relayHints
|
||||
#if DEBUG
|
||||
@@ -42,7 +54,14 @@ struct EventLoaderView<Content: View>: View {
|
||||
}
|
||||
#endif
|
||||
let lender = try? await damus_state.nostrNetwork.reader.lookup(noteId: self.event_id, to: targetRelays)
|
||||
lender?.justUseACopy({ event = $0 })
|
||||
if let foundEvent = lender?.justGetACopy() {
|
||||
event = foundEvent
|
||||
eventNotFound = false
|
||||
}
|
||||
else {
|
||||
// Handle nil case: event was not found
|
||||
eventNotFound = true
|
||||
}
|
||||
#if DEBUG
|
||||
if let targetRelays, !targetRelays.isEmpty {
|
||||
print("[relay-hints] EventLoaderView: Event \(event_id.hex().prefix(8))... loaded: \(event != nil)")
|
||||
@@ -50,10 +69,27 @@ struct EventLoaderView<Content: View>: View {
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Retries loading the event and displays loading state during the operation.
|
||||
///
|
||||
/// This method sets the `isReloading` flag to true, calls `load()`, and resets
|
||||
/// the flag when complete. It is typically triggered by user action (e.g., "Try Again" button).
|
||||
///
|
||||
/// Side effects:
|
||||
/// - Updates `isReloading` to true during the operation
|
||||
/// - Delegates to `load()`, which updates `event` and `eventNotFound`
|
||||
/// - Resets `isReloading` to false after completion
|
||||
func retry() async {
|
||||
isReloading = true
|
||||
await load()
|
||||
isReloading = false
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
VStack {
|
||||
if let event {
|
||||
self.content(event)
|
||||
} else if eventNotFound {
|
||||
not_found
|
||||
} else {
|
||||
ProgressView().padding()
|
||||
}
|
||||
@@ -65,6 +101,47 @@ struct EventLoaderView<Content: View>: View {
|
||||
await self.load()
|
||||
}
|
||||
}
|
||||
|
||||
var not_found: some View {
|
||||
VStack(spacing: 0) {
|
||||
LoadableNostrEventView.SomethingWrong(
|
||||
imageSystemName: "questionmark.app",
|
||||
heading: NSLocalizedString("Note not found", comment: "Heading for the event loader view in a not found error state."),
|
||||
description: NSLocalizedString("This note may have been deleted, or it might not be available on the relays you're connected to.", comment: "Text for the event loader view when it is unable to find the note the user is looking for"),
|
||||
advice: NSLocalizedString("Try checking your internet connection, expanding your relay list, or contacting the person who quoted this note.", comment: "Tips on what to do if a quoted note cannot be found.")
|
||||
)
|
||||
|
||||
Button(action: {
|
||||
Task {
|
||||
await retry()
|
||||
}
|
||||
}) {
|
||||
HStack {
|
||||
if !isReloading {
|
||||
Image(systemName: "arrow.clockwise")
|
||||
Text("Try Again", comment: "Button label to retry loading a note that was not found")
|
||||
}
|
||||
else {
|
||||
ProgressView()
|
||||
Text("Retrying…", comment: "Button label for the retry-in-progress state when loading a note")
|
||||
}
|
||||
}
|
||||
.font(.headline)
|
||||
.foregroundColor(.white)
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 12)
|
||||
.background(Color.secondary)
|
||||
.cornerRadius(10)
|
||||
}
|
||||
.disabled(isReloading)
|
||||
.opacity(isReloading ? 0.6 : 1.0)
|
||||
.padding(.bottom, 20)
|
||||
}
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.stroke(Color.secondary.opacity(0.3), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user