commit cc77c9c37607b041facc0bca13d1b6b9f6231325
parent 29565094868a88a103526a7275bb816bb63c6f62
Author: triesap <tyson@radroots.org>
Date: Fri, 19 Jun 2026 16:56:43 -0700
api: drop retired trade mobile consumers
- remove Swift wrappers for retired trade validation, order, and message APIs.
- simplify listing detail around the active listing read model.
- delete the retired order request view from the app target.
- lock FFI generation to the reduced field_lib trade surface.
Diffstat:
6 files changed, 2 insertions(+), 287 deletions(-)
diff --git a/Radroots.xcodeproj/project.pbxproj b/Radroots.xcodeproj/project.pbxproj
@@ -63,7 +63,6 @@
EB7C19F62D7DAB9C044D53AA /* PostDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3C0EFACAD213A69C12D5064 /* PostDetailView.swift */; };
F32EFF00A8A852F76657FEE1 /* PostCreateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA8AAF0C0F1723860A8481E0 /* PostCreateView.swift */; };
F3E40E5A76B4EA19AC7603D2 /* RadrootsKit in Frameworks */ = {isa = PBXBuildFile; productRef = 2DAD90EBF8EB00ACDD7611CD /* RadrootsKit */; };
- FD9B01F8F5DD1F05A64FD556 /* TradeOrderRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 466BFA2F60BE3113EDD1BA3B /* TradeOrderRequestView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -82,7 +81,6 @@
3B4E53FD4C4AADF63855888A /* FieldTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldTelemetry.swift; sourceTree = "<group>"; };
3E6187FA7C4786EC662718B2 /* FieldExternalActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldExternalActions.swift; sourceTree = "<group>"; };
41A4289F43625DD65E6C4B25 /* CopyRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyRow.swift; sourceTree = "<group>"; };
- 466BFA2F60BE3113EDD1BA3B /* TradeOrderRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TradeOrderRequestView.swift; sourceTree = "<group>"; };
481E7791F4F6CF82FA3117C1 /* FieldIdentityImportFailureUITestProbe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldIdentityImportFailureUITestProbe.swift; sourceTree = "<group>"; };
491D57E540BAB04F24619737 /* FieldFileAccessUITestProbe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldFileAccessUITestProbe.swift; sourceTree = "<group>"; };
4BC4B7D0BB4C6D8E4B0AA4AD /* radroots.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = radroots.xcconfig; sourceTree = "<group>"; };
@@ -296,7 +294,6 @@
16A7641E5C643B4B36CFEDA8 /* SetupView.swift */,
947ADA6D32E42ED2B40A5351 /* TradeListingCreateView.swift */,
26BAE32CD1D46033DDA1A5BB /* TradeListingDetailView.swift */,
- 466BFA2F60BE3113EDD1BA3B /* TradeOrderRequestView.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -492,7 +489,6 @@
D5C58A98C950D45AD027962A /* TradeListing.swift in Sources */,
505A5731ACDBBB0296134340 /* TradeListingCreateView.swift in Sources */,
4B44B723FF06ECC363A486BA /* TradeListingDetailView.swift in Sources */,
- FD9B01F8F5DD1F05A64FD556 /* TradeOrderRequestView.swift in Sources */,
35D8223F5E169DDB4E3E87C0 /* TradeSettings.swift in Sources */,
B971351ABE8E79A472B4DC7D /* View+Nav.swift in Sources */,
);
diff --git a/Radroots/Runtime/TradeListing.swift b/Radroots/Runtime/TradeListing.swift
@@ -10,46 +10,8 @@ public extension FieldRuntimeService {
try await run { try $0.tradeListingsFetch(limit: limit, sinceUnix: sinceUnix) }
}
- func tradeListingSendValidationRequest(
- listingEventId: String,
- sellerPubkey: String,
- listingId: String,
- recipientPubkey: String
- ) async throws -> NostrEventId {
- let id = try await run {
- try $0.tradeListingSendValidationRequest(
- listingEventId: listingEventId,
- sellerPubkey: sellerPubkey,
- listingId: listingId,
- recipientPubkey: recipientPubkey
- )
- }
- return NostrEventId(id)
- }
-
- func tradeListingSendOrderRequest(draft: TradeOrderDraft) async throws -> TradeOrderSendResult {
- try await run { try $0.tradeListingSendOrderRequest(draft: draft) }
- }
-
- func tradeListingFetchMessages(
- listingAddr: String,
- limit: UInt16,
- sinceUnix: UInt64? = nil
- ) async throws -> [TradeListingMessageSummary] {
- try await run {
- try $0.tradeListingFetchMessages(
- listingAddr: listingAddr,
- limit: limit,
- sinceUnix: sinceUnix
- )
- }
- }
}
extension TradeListingSummary: Identifiable {
public var id: String { eventId }
}
-
-extension TradeListingMessageSummary: Identifiable {
- public var id: String { eventId }
-}
diff --git a/Radroots/Views/TradeListingDetailView.swift b/Radroots/Views/TradeListingDetailView.swift
@@ -1,46 +1,10 @@
import SwiftUI
-@MainActor
-final class TradeListingDetailViewModel: ObservableObject {
- let listing: TradeListingSummary
- @Published var messages: [TradeListingMessageSummary] = []
- @Published var isLoading = false
- @Published var errorMessage: String?
-
- init(listing: TradeListingSummary) {
- self.listing = listing
- }
-
- func refresh(app: AppState) async {
- guard let service = app.runtimeService else { return }
- isLoading = true
- errorMessage = nil
-
- let listingAddr = listing.listingAddr
-
- do {
- let items = try await service.tradeListingFetchMessages(
- listingAddr: listingAddr,
- limit: 80,
- sinceUnix: nil
- )
- messages = items
- isLoading = false
- } catch {
- errorMessage = error.fieldRuntimeMessage
- isLoading = false
- }
- }
-}
-
struct TradeListingDetailView: View {
- @EnvironmentObject private var app: AppState
let listing: TradeListingSummary
- @StateObject private var vm: TradeListingDetailViewModel
init(listing: TradeListingSummary) {
self.listing = listing
- _vm = StateObject(wrappedValue: TradeListingDetailViewModel(listing: listing))
}
var body: some View {
@@ -73,48 +37,10 @@ struct TradeListingDetailView: View {
CopyRow(title: "Seller", value: listing.sellerPubkey)
} header: {
Text("Event")
- } footer: {
- Text("Order and validation request flows are retired in this field runtime pass.")
- .foregroundStyle(.secondary)
- }
-
- Section("Activity") {
- if let error = vm.errorMessage {
- Text(error)
- .foregroundStyle(.red)
- .font(.footnote)
- }
-
- if vm.messages.isEmpty {
- ContentUnavailableView(
- "No Activity Yet",
- systemImage: "bubble.left.and.text.bubble.right",
- description: Text("The current field runtime exposes listing publish and fetch first.")
- )
- .listRowBackground(Color.clear)
- } else {
- ForEach(vm.messages) { message in
- TradeListingMessageRow(message: message)
- }
- }
}
}
.listStyle(.insetGrouped)
.inlineNavigationTitle(listing.title)
- .toolbar {
- ToolbarItem(placement: .topBarTrailing) {
- if vm.isLoading { ProgressView() }
- }
- ToolbarItem(placement: .topBarTrailing) {
- Button {
- Task { await vm.refresh(app: app) }
- } label: {
- Image(systemName: "arrow.clockwise")
- }
- }
- }
- .task { await vm.refresh(app: app) }
- .refreshable { await vm.refresh(app: app) }
}
private var priceLine: String {
@@ -131,32 +57,3 @@ struct TradeListingDetailView: View {
}
}
-
-private struct TradeListingMessageRow: View {
- let message: TradeListingMessageSummary
-
- var body: some View {
- VStack(alignment: .leading, spacing: 6) {
- Text(message.summary)
- .font(.subheadline.weight(.semibold))
- .foregroundStyle(.primary)
- HStack {
- Text(message.messageType.replacingOccurrences(of: "_", with: " ").capitalized)
- .font(.caption)
- .foregroundStyle(.secondary)
- Spacer()
- Text(relativeTime(message.publishedAt))
- .font(.caption)
- .foregroundStyle(.secondary)
- }
- }
- .padding(.vertical, 4)
- }
-
- private func relativeTime(_ unix: UInt64) -> String {
- let d = Date(timeIntervalSince1970: TimeInterval(unix))
- let f = RelativeDateTimeFormatter()
- f.unitsStyle = .abbreviated
- return f.localizedString(for: d, relativeTo: Date())
- }
-}
diff --git a/Radroots/Views/TradeOrderRequestView.swift b/Radroots/Views/TradeOrderRequestView.swift
@@ -1,140 +0,0 @@
-import SwiftUI
-import Foundation
-
-struct TradeOrderRequestView: View {
- @EnvironmentObject private var app: AppState
- @Environment(\.dismiss) private var dismiss
- let listing: TradeListingSummary
- private let onComplete: (TradeOrderSendResult) -> Void
-
- @State private var binCount: String
- @State private var notes: String = ""
- @State private var isSending = false
- @State private var errorMessage: String?
- @FocusState private var focused: Bool
-
- init(listing: TradeListingSummary, onComplete: @escaping (TradeOrderSendResult) -> Void) {
- self.listing = listing
- self.onComplete = onComplete
- _binCount = State(initialValue: "1")
- }
-
- var body: some View {
- Form {
- Section("Order") {
- TextField("Bin count", text: $binCount)
- .keyboardType(.numberPad)
- .focused($focused)
- LabeledContent("Bin size", value: binLine)
- LabeledContent("Unit price", value: unitPriceLine)
- if let total = totalPriceLine {
- LabeledContent("Estimated total", value: total)
- }
- }
-
- Section("Notes") {
- TextEditor(text: $notes)
- .frame(minHeight: 100)
- }
-
- Section {
- SectionWideButton("Send Order Request", enabled: canSend, isProminent: true) {
- sendOrder()
- }
- } footer: {
- if let errorMessage {
- Text(errorMessage).foregroundStyle(.red)
- } else if TradeSettings.rhiPubkeyOptional == nil {
- Text("Set RADROOTS_FIELD_IOS_TRADE_RHI_PUBKEY to enable order requests.")
- .foregroundStyle(.secondary)
- }
- }
- }
- .scrollDismissesKeyboard(.interactively)
- .inlineNavigationTitle("Order Request")
- .toolbar {
- ToolbarItem(placement: .topBarTrailing) {
- if isSending { ProgressView() }
- }
- ToolbarItemGroup(placement: .keyboard) {
- Spacer()
- Button("Done") { focused = false }
- }
- }
- .onAppear { focused = true }
- }
-
- private var unitPriceLine: String {
- "\(listing.unitPriceAmount) \(listing.unitPriceCurrency) / \(listing.unitPriceUnit)"
- }
-
- private var binLine: String {
- let label = listing.binDisplayLabel?.trimmingCharacters(in: .whitespacesAndNewlines)
- let base = "\(listing.binDisplayAmount) \(listing.binDisplayUnit)"
- if let label, !label.isEmpty {
- return "\(base) \(label)"
- }
- return base
- }
-
- private var canSend: Bool {
- app.relayConnectedCount > 0 &&
- !isSending &&
- TradeSettings.rhiPubkeyOptional != nil &&
- parsedBinCount != nil
- }
-
- private var totalPriceLine: String? {
- guard let countValue = parsedBinCount,
- let unitPrice = Decimal(string: listing.unitPriceAmount),
- let binAmount = Decimal(string: listing.binDisplayAmount) else {
- return nil
- }
- let count = Decimal(Int(countValue))
- let total = count * unitPrice * binAmount
- return "\(total) \(listing.unitPriceCurrency)"
- }
-
- private func sendOrder() {
- guard let service = app.runtimeService else { return }
- guard let rhiPubkey = TradeSettings.rhiPubkeyOptional else {
- errorMessage = "Missing RHI pubkey."
- return
- }
- errorMessage = nil
- isSending = true
-
- let trimmedNotes = notes.trimmingCharacters(in: .whitespacesAndNewlines)
- guard let countValue = parsedBinCount else {
- errorMessage = "Bin count must be a whole number."
- isSending = false
- return
- }
- let trimmedCount = String(countValue)
- let draft = TradeOrderDraft(
- listingAddr: listing.listingAddr,
- sellerPubkey: listing.sellerPubkey,
- binId: listing.primaryBinId,
- binCount: trimmedCount,
- notes: trimmedNotes.isEmpty ? nil : trimmedNotes,
- orderId: nil,
- recipientPubkey: rhiPubkey
- )
-
- Task { @MainActor in
- do {
- let out = try await service.tradeListingSendOrderRequest(draft: draft)
- isSending = false
- onComplete(out)
- dismiss()
- } catch {
- isSending = false
- errorMessage = error.fieldRuntimeMessage
- }
- }
- }
-
- private var parsedBinCount: UInt32? {
- UInt32(binCount.trimmingCharacters(in: .whitespacesAndNewlines))
- }
-}
diff --git a/RadrootsFFI/Makefile b/RadrootsFFI/Makefile
@@ -6,7 +6,7 @@ SHELL := /bin/bash
SOURCE_MODE ?= git
RADROOTS_FIELD_LIB_GIT_URL ?= git@github.com:radrootslabs/field_lib.git
-RADROOTS_FIELD_LIB_GIT_REV ?= 826c68898139e5119c6388fece76df6b853f6458
+RADROOTS_FIELD_LIB_GIT_REV ?= 39ab08d749561f74693408b70098443dddd881f8
RADROOTS_FIELD_FFI_CRATE_VERSION ?= 0.1.0-alpha.1
FFI_FEATURES ?= radroots_field_core/rt,radroots_field_core/nostr-client
LOCAL_FFI_MANIFEST ?=
diff --git a/RadrootsFFI/source.lock b/RadrootsFFI/source.lock
@@ -1,5 +1,5 @@
SOURCE_MODE=git
RADROOTS_FIELD_LIB_GIT_URL=git@github.com:radrootslabs/field_lib.git
-RADROOTS_FIELD_LIB_GIT_REV=826c68898139e5119c6388fece76df6b853f6458
+RADROOTS_FIELD_LIB_GIT_REV=39ab08d749561f74693408b70098443dddd881f8
RADROOTS_FIELD_FFI_CRATE_VERSION=0.1.0-alpha.1
FFI_FEATURES=radroots_field_core/rt,radroots_field_core/nostr-client