commit ce6b27509c6f7860ccaa02e8835cf08b7b25c6b2
parent e15e04f32fcdfe1bb055b47b2dc015ea7ba9d12d
Author: triesap <tyson@radroots.org>
Date: Thu, 11 Jun 2026 16:38:12 -0700
ios: align app shell with field runtime
Diffstat:
14 files changed, 132 insertions(+), 214 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -9,7 +9,6 @@
*.ipa
*.dSYM*
*.hmap
-project.yml
# SwiftPM
.build
diff --git a/Makefile b/Makefile
@@ -1,6 +1,9 @@
FFI_ROOT := RadrootsFFI
-.PHONY: all clean distclean sync-source build generate package install print-config
+.PHONY: all clean distclean sync-source build generate package install print-config project xcodegen
all clean distclean sync-source build generate package install print-config:
$(MAKE) -C $(FFI_ROOT) $@
+
+project xcodegen:
+ xcodegen generate --spec project.yml
diff --git a/Radroots.xcodeproj/project.pbxproj b/Radroots.xcodeproj/project.pbxproj
@@ -242,6 +242,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 2513910CE2A2ED545A78A163 /* Build configuration list for PBXNativeTarget "Radroots" */;
buildPhases = (
+ 1687531B35A5B613B89DA261 /* Generate git SHA xcconfig */,
78F7810CC77628CB591F8CD2 /* Sources */,
0FB0BFB846269AC353E4AD0E /* Resources */,
1384F9BE8BB29250A1B4A26A /* Frameworks */,
@@ -266,9 +267,10 @@
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
+ TargetAttributes = {
+ };
};
buildConfigurationList = D17883D6A48F29A2A4DFE795 /* Build configuration list for PBXProject "Radroots" */;
- compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -281,6 +283,7 @@
DA033E4B08F702473D7DDDE3 /* XCLocalSwiftPackageReference "RadrootsKit" */,
);
preferredProjectObjectVersion = 77;
+ productRefGroup = 6240123423927396E47D6B3E /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
@@ -301,6 +304,28 @@
};
/* End PBXResourcesBuildPhase section */
+/* Begin PBXShellScriptBuildPhase section */
+ 1687531B35A5B613B89DA261 /* Generate git SHA xcconfig */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "Generate git SHA xcconfig";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "GIT_SHA=$(git rev-parse --short HEAD || echo \"unknown\")\necho \"GIT_SHA = $GIT_SHA\" > \"$SRCROOT/Radroots/radroots.git.xcconfig\"\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
/* Begin PBXSourcesBuildPhase section */
78F7810CC77628CB591F8CD2 /* Sources */ = {
isa = PBXSourcesBuildPhase;
diff --git a/Radroots/Views/SettingsView.swift b/Radroots/Views/SettingsView.swift
@@ -35,7 +35,7 @@ struct SettingsView: View {
if let rhi = TradeSettings.rhiPubkeyOptional {
CopyRow(title: "RHI Pubkey", value: rhi)
} else {
- Text("Set RR_TRADE_RHI_PUBKEY to enable trade flows.")
+ Text("Listing publish and fetch use the shared field runtime.")
.foregroundStyle(.secondary)
}
}
@@ -66,7 +66,10 @@ struct SettingsView: View {
guard let rt = radroots.runtime else { return }
exportError = nil
do {
- let hex = try rt.keysExportSecretHex()
+ guard let hex = try rt.accountsExportSelectedSecretHex() else {
+ exportError = "No selected account has an exportable secret."
+ return
+ }
UIPasteboard.general.string = hex
} catch {
exportError = String(describing: error)
diff --git a/Radroots/Views/SetupView.swift b/Radroots/Views/SetupView.swift
@@ -193,7 +193,7 @@ private struct SetupKeyView: View {
Spacer()
- Text("Your private key is stored securely in the iOS Keychain.")
+ Text("Your account is managed by the shared field runtime.")
.font(.footnote)
.foregroundStyle(.secondary)
.multilineTextAlignment(.center)
diff --git a/Radroots/Views/TradeListingCreateView.swift b/Radroots/Views/TradeListingCreateView.swift
@@ -260,7 +260,7 @@ private struct ListingDraftState {
func toTradeListingDraft() -> TradeListingDraft {
let trimmedLabel = binLabel.trimmingCharacters(in: .whitespacesAndNewlines)
- TradeListingDraft(
+ return TradeListingDraft(
listingId: nil,
farmPubkey: farmPubkey,
farmDTag: farmDTag,
diff --git a/Radroots/Views/TradeListingDetailView.swift b/Radroots/Views/TradeListingDetailView.swift
@@ -7,7 +7,6 @@ final class TradeListingDetailViewModel: ObservableObject {
@Published var messages: [TradeListingMessageSummary] = []
@Published var isLoading = false
@Published var errorMessage: String?
- @Published var orderId: String?
init(listing: TradeListingSummary) {
self.listing = listing
@@ -19,14 +18,12 @@ final class TradeListingDetailViewModel: ObservableObject {
errorMessage = nil
let listingAddr = listing.listingAddr
- let orderId = self.orderId
let result: Result<[TradeListingMessageSummary], Error> = await Task.detached { @Sendable in
do {
return .success(
try rt.tradeListingFetchMessages(
listingAddr: listingAddr,
- orderId: orderId,
limit: 80,
sinceUnix: nil
)
@@ -51,9 +48,6 @@ struct TradeListingDetailView: View {
@EnvironmentObject private var app: AppState
let listing: TradeListingSummary
@StateObject private var vm: TradeListingDetailViewModel
- @State private var showOrderSheet = false
- @State private var showValidationAlert = false
- @State private var validationMessage = ""
init(listing: TradeListingSummary) {
self.listing = listing
@@ -85,26 +79,14 @@ struct TradeListingDetailView: View {
}
Section {
- SectionWideButton("Validate Listing", enabled: canUseTrade) {
- sendValidationRequest()
- }
-
- SectionWideButton("Request Order", enabled: canUseTrade, isProminent: true) {
- showOrderSheet = true
- }
-
- if let orderId = vm.orderId {
- LabeledContent("Order ID", value: orderId)
- .font(.footnote)
- .foregroundStyle(.secondary)
- }
+ CopyRow(title: "Listing ID", value: listing.listingId)
+ CopyRow(title: "Event ID", value: listing.eventId)
+ CopyRow(title: "Seller", value: listing.sellerPubkey)
} header: {
- Text("Actions")
+ Text("Event")
} footer: {
- if !canUseTrade {
- Text(tradeDisabledMessage)
- .foregroundStyle(.secondary)
- }
+ Text("Order and validation request flows are retired in this field runtime pass.")
+ .foregroundStyle(.secondary)
}
Section("Activity") {
@@ -118,7 +100,7 @@ struct TradeListingDetailView: View {
ContentUnavailableView(
"No Activity Yet",
systemImage: "bubble.left.and.text.bubble.right",
- description: Text("Validation and order updates appear here.")
+ description: Text("The current field runtime exposes listing publish and fetch first.")
)
.listRowBackground(Color.clear)
} else {
@@ -144,19 +126,6 @@ struct TradeListingDetailView: View {
}
.task { await vm.refresh(app: app) }
.refreshable { await vm.refresh(app: app) }
- .sheet(isPresented: $showOrderSheet) {
- NavigationStack {
- TradeOrderRequestView(listing: listing) { result in
- vm.orderId = result.orderId
- Task { await vm.refresh(app: app) }
- }
- }
- }
- .alert("Validation Request", isPresented: $showValidationAlert) {
- Button("OK", role: .cancel) { }
- } message: {
- Text(validationMessage)
- }
}
private var priceLine: String {
@@ -172,50 +141,6 @@ struct TradeListingDetailView: View {
return base
}
- private var canUseTrade: Bool {
- app.relayConnectedCount > 0 && TradeSettings.rhiPubkeyOptional != nil
- }
-
- private var tradeDisabledMessage: String {
- if app.relayConnectedCount == 0 {
- return "Connect to relays to use trade flows."
- }
- return "Set RR_TRADE_RHI_PUBKEY to enable trade requests."
- }
-
- private func sendValidationRequest() {
- guard let rt = app.radroots.runtime else { return }
- guard let rhiPubkey = TradeSettings.rhiPubkeyOptional else {
- validationMessage = "Set RR_TRADE_RHI_PUBKEY to enable validation."
- showValidationAlert = true
- return
- }
-
- Task { @MainActor in
- let result: Result<String, Error> = await Task.detached { @Sendable in
- do {
- return .success(
- try rt.tradeListingSendValidationRequest(
- listingEventId: listing.eventId,
- sellerPubkey: listing.sellerPubkey,
- listingId: listing.listingId,
- recipientPubkey: rhiPubkey
- )
- )
- } catch {
- return .failure(error)
- }
- }.value
-
- switch result {
- case .success(let id):
- validationMessage = "Validation request sent: \(id)"
- case .failure(let error):
- validationMessage = "Validation failed: \(error)"
- }
- showValidationAlert = true
- }
- }
}
private struct TradeListingMessageRow: View {
diff --git a/RadrootsFFI/Config/ffi-build.env b/RadrootsFFI/Config/ffi-build.env
@@ -1,3 +1,3 @@
# Optional overrides for local development.
# SOURCE_MODE=local
-# LOCAL_FFI_MANIFEST=/absolute/path/to/app-ffi-swift/Cargo.toml
+# LOCAL_FFI_MANIFEST=/absolute/path/to/field_lib/crates/field_ffi_swift/Cargo.toml
diff --git a/RadrootsFFI/Makefile b/RadrootsFFI/Makefile
@@ -5,10 +5,13 @@ SHELL := /bin/bash
-include Config/ffi-build.env
SOURCE_MODE ?= git
-RADROOTS_CRATES_GIT_URL ?= https://github.com/radrootslabs/crates.git
-RADROOTS_CRATES_GIT_REV ?= 766c63c07ac7497d75a71aaab010fbc08ee934bc
-RADROOTS_APP_FFI_CRATE_VERSION ?= 0.1.0
+RADROOTS_FIELD_LIB_GIT_URL ?= git@github.com:radrootslabs/field_lib.git
+RADROOTS_FIELD_LIB_GIT_REV ?= a73f486d1dca78bfb1b1c655c2404317a7ea1e5e
+RADROOTS_FIELD_FFI_CRATE_VERSION ?= 0.1.0-alpha.1
+FFI_FEATURES ?= radroots_field_core/rt,radroots_field_core/nostr-client
LOCAL_FFI_MANIFEST ?=
+IPHONEOS_DEPLOYMENT_TARGET ?= 18.0
+RUSTUP_TOOLCHAIN ?= 1.92.0-aarch64-apple-darwin
IOS_ROOT := $(abspath $(CURDIR)/..)
KIT_ROOT := $(IOS_ROOT)/RadrootsKit
@@ -22,17 +25,18 @@ OUT_DIR := $(BUILD_ROOT)/out
GENERATED_DIR := $(OUT_DIR)/generated
HEADERS_DIR := $(OUT_DIR)/headers
-CRATE_NAME := radroots-app-ffi-swift
+CRATE_NAME := radroots_field_ffi_swift
FFI_OUTPUT_NAME := RadrootsFFI
-LIB_STEM := libradroots_app_ffi_swift
+LIB_STEM := libradroots_field_ffi_swift
-GIT_CRATES_DIR := $(SOURCE_ROOT)/radroots-crates
-CRATE_ARCHIVE := $(SOURCE_ROOT)/$(CRATE_NAME)-$(RADROOTS_APP_FFI_CRATE_VERSION).crate
-CRATE_EXTRACT_DIR := $(SOURCE_ROOT)/$(CRATE_NAME)-$(RADROOTS_APP_FFI_CRATE_VERSION)
+GIT_FIELD_LIB_DIR := $(SOURCE_ROOT)/field-lib
+CRATE_ARCHIVE := $(SOURCE_ROOT)/$(CRATE_NAME)-$(RADROOTS_FIELD_FFI_CRATE_VERSION).crate
+CRATE_EXTRACT_DIR := $(SOURCE_ROOT)/$(CRATE_NAME)-$(RADROOTS_FIELD_FFI_CRATE_VERSION)
+CARGO_FEATURE_FLAGS := $(if $(strip $(FFI_FEATURES)),--features $(FFI_FEATURES),)
ifeq ($(SOURCE_MODE),git)
-FFI_MANIFEST := $(GIT_CRATES_DIR)/app-ffi-swift/Cargo.toml
-UNIFFI_CONFIG := $(GIT_CRATES_DIR)/app-ffi-swift/uniffi.toml
+FFI_MANIFEST := $(GIT_FIELD_LIB_DIR)/crates/field_ffi_swift/Cargo.toml
+UNIFFI_CONFIG := $(GIT_FIELD_LIB_DIR)/crates/field_ffi_swift/uniffi.toml
SOURCE_TARGET := sync-source-git
else ifeq ($(SOURCE_MODE),crates)
FFI_MANIFEST := $(CRATE_EXTRACT_DIR)/Cargo.toml
@@ -48,7 +52,9 @@ endif
FFI_CRATE_DIR := $(dir $(FFI_MANIFEST))
-CARGO := CARGO_TARGET_DIR=$(TARGET_DIR) cargo
+RUSTC_BIN := $(shell rustup which --toolchain $(RUSTUP_TOOLCHAIN) rustc)
+CARGO_BIN := rustup run $(RUSTUP_TOOLCHAIN) cargo
+CARGO := IPHONEOS_DEPLOYMENT_TARGET=$(IPHONEOS_DEPLOYMENT_TARGET) RUSTC=$(RUSTC_BIN) CARGO_TARGET_DIR=$(TARGET_DIR) $(CARGO_BIN)
LIB_DEVICE := $(TARGET_DIR)/aarch64-apple-ios/release/$(LIB_STEM).a
LIB_SIMULATOR := $(TARGET_DIR)/aarch64-apple-ios-sim/release/$(LIB_STEM).a
@@ -68,6 +74,9 @@ print-config:
@echo "UNIFFI_CONFIG=$(UNIFFI_CONFIG)"
@echo "ARTIFACTS_DIR=$(ARTIFACTS_DIR)"
@echo "GENERATED_SWIFT_DIR=$(GENERATED_SWIFT_DIR)"
+ @echo "IPHONEOS_DEPLOYMENT_TARGET=$(IPHONEOS_DEPLOYMENT_TARGET)"
+ @echo "RUSTUP_TOOLCHAIN=$(RUSTUP_TOOLCHAIN)"
+ @echo "RUSTC_BIN=$(RUSTC_BIN)"
clean:
rm -rf $(TARGET_DIR) $(OUT_DIR) $(ARTIFACTS_DIR)/$(FFI_OUTPUT_NAME).xcframework
@@ -82,17 +91,17 @@ sync-source: $(SOURCE_TARGET)
sync-source-git:
mkdir -p $(SOURCE_ROOT)
- if [ ! -d $(GIT_CRATES_DIR)/.git ]; then \
- git clone --filter=blob:none $(RADROOTS_CRATES_GIT_URL) $(GIT_CRATES_DIR); \
+ if [ ! -d $(GIT_FIELD_LIB_DIR)/.git ]; then \
+ git clone --filter=blob:none $(RADROOTS_FIELD_LIB_GIT_URL) $(GIT_FIELD_LIB_DIR); \
fi
- git -C $(GIT_CRATES_DIR) fetch --tags --force origin
- git -C $(GIT_CRATES_DIR) checkout --detach $(RADROOTS_CRATES_GIT_REV)
+ git -C $(GIT_FIELD_LIB_DIR) fetch --tags --force origin
+ git -C $(GIT_FIELD_LIB_DIR) checkout --detach $(RADROOTS_FIELD_LIB_GIT_REV)
test -f $(FFI_MANIFEST)
sync-source-crates:
mkdir -p $(SOURCE_ROOT)
rm -rf $(CRATE_EXTRACT_DIR)
- curl -fLsS https://crates.io/api/v1/crates/$(CRATE_NAME)/$(RADROOTS_APP_FFI_CRATE_VERSION)/download -o $(CRATE_ARCHIVE)
+ curl -fLsS https://crates.io/api/v1/crates/$(CRATE_NAME)/$(RADROOTS_FIELD_FFI_CRATE_VERSION)/download -o $(CRATE_ARCHIVE)
tar -xzf $(CRATE_ARCHIVE) -C $(SOURCE_ROOT)
test -f $(FFI_MANIFEST)
@@ -105,17 +114,17 @@ sync-source-local:
test -f $(UNIFFI_CONFIG)
ensure-toolchain:
- rustup target add aarch64-apple-ios aarch64-apple-ios-sim
+ rustup target add --toolchain $(RUSTUP_TOOLCHAIN) aarch64-apple-ios aarch64-apple-ios-sim
build: ensure-toolchain
mkdir -p $(TARGET_DIR) $(OUT_DIR)
- $(CARGO) build --manifest-path $(FFI_MANIFEST) --release --target aarch64-apple-ios
- $(CARGO) build --manifest-path $(FFI_MANIFEST) --release --target aarch64-apple-ios-sim
- $(CARGO) build --manifest-path $(FFI_MANIFEST) --release
+ $(CARGO) build --manifest-path $(FFI_MANIFEST) $(CARGO_FEATURE_FLAGS) --release --target aarch64-apple-ios
+ $(CARGO) build --manifest-path $(FFI_MANIFEST) $(CARGO_FEATURE_FLAGS) --release --target aarch64-apple-ios-sim
+ $(CARGO) build --manifest-path $(FFI_MANIFEST) $(CARGO_FEATURE_FLAGS) --release
generate:
mkdir -p $(GENERATED_DIR) $(HEADERS_DIR)
- cd $(FFI_CRATE_DIR) && CARGO_TARGET_DIR=$(TARGET_DIR) cargo run --manifest-path Cargo.toml --bin uniffi-bindgen -- \
+ cd $(FFI_CRATE_DIR) && $(CARGO) run --manifest-path Cargo.toml $(CARGO_FEATURE_FLAGS) --bin uniffi-bindgen -- \
generate --library $(LIB_HOST) \
--language swift \
--out-dir $(GENERATED_DIR) \
diff --git a/RadrootsFFI/source.lock b/RadrootsFFI/source.lock
@@ -1,4 +1,5 @@
SOURCE_MODE=git
-RADROOTS_CRATES_GIT_URL=https://github.com/radrootslabs/crates.git
-RADROOTS_CRATES_GIT_REV=766c63c07ac7497d75a71aaab010fbc08ee934bc
-RADROOTS_APP_FFI_CRATE_VERSION=0.1.0
+RADROOTS_FIELD_LIB_GIT_URL=git@github.com:radrootslabs/field_lib.git
+RADROOTS_FIELD_LIB_GIT_REV=a73f486d1dca78bfb1b1c655c2404317a7ea1e5e
+RADROOTS_FIELD_FFI_CRATE_VERSION=0.1.0-alpha.1
+FFI_FEATURES=radroots_field_core/rt,radroots_field_core/nostr-client
diff --git a/RadrootsKit/Sources/RadrootsKit/AppState.swift b/RadrootsKit/Sources/RadrootsKit/AppState.swift
@@ -54,9 +54,9 @@ public final class AppState: ObservableObject {
do {
try radroots.start()
if let rt = radroots.runtime {
- keys.loadFromKeychainIfPresent(runtime: rt)
+ keys.loadFromRuntime(runtime: rt)
connectIfPossible()
- if rt.keysIsLoaded() {
+ if rt.accountsHasSelectedSigningIdentity() {
startPollingStatus()
}
}
@@ -71,8 +71,9 @@ public final class AppState: ObservableObject {
public func refresh() {
guard let rt = radroots.runtime else { return }
infoJSONString = rt.infoJson()
- hasKey = rt.keysIsLoaded()
- npub = rt.keysNpub()
+ hasKey = rt.accountsHasSelectedSigningIdentity()
+ npub = rt.accountsSelectedNpub()
+ keys.refresh(runtime: rt)
updateStatus()
}
@@ -83,7 +84,7 @@ public final class AppState: ObservableObject {
}
private func connectIfPossible() {
- guard let rt = radroots.runtime, rt.keysIsLoaded() else { return }
+ guard let rt = radroots.runtime, rt.accountsHasSelectedSigningIdentity() else { return }
do {
let relays = try RelaySettings.relays()
try rt.nostrSetDefaultRelays(relays: relays)
diff --git a/RadrootsKit/Sources/RadrootsKit/RadrootsKeys.swift b/RadrootsKit/Sources/RadrootsKit/RadrootsKeys.swift
@@ -1,5 +1,4 @@
import Foundation
-import Security
@MainActor
public final class RadrootsKeys: ObservableObject {
@@ -8,105 +7,22 @@ public final class RadrootsKeys: ObservableObject {
public init() {}
- public func loadFromKeychainIfPresent(runtime: RadrootsRuntime) {
- if let account = Keychain.activeAccount() ?? Keychain.accounts().first {
- if let data = Keychain.load(service: Keychain.service, account: account),
- let hex = String(data: data, encoding: .utf8) {
- try? runtime.keysLoadHex32(hex: hex)
- }
- }
- self.hasKey = runtime.keysIsLoaded()
- self.npub = runtime.keysNpub()
+ public func loadFromRuntime(runtime: RadrootsRuntime) {
+ refresh(runtime: runtime)
}
public func generateAndPersist(runtime: RadrootsRuntime) throws {
- _ = try runtime.keysGenerateInMemory()
- try persistCurrentKey(runtime: runtime, accountOverride: nil)
+ _ = try runtime.accountsGenerate(label: "iOS", makeSelected: true)
+ refresh(runtime: runtime)
}
public func importSecretHex(hex: String, runtime: RadrootsRuntime) throws {
- try runtime.keysLoadHex32(hex: hex)
- try persistCurrentKey(runtime: runtime, accountOverride: nil)
+ _ = try runtime.accountsImportSecret(secretKey: hex, label: "iOS", makeSelected: true)
+ refresh(runtime: runtime)
}
- private func persistCurrentKey(runtime: RadrootsRuntime, accountOverride: String?) throws {
- let hex = try runtime.keysExportSecretHex()
- let account = accountOverride ?? runtime.keysNpub() ?? "profile-\(Int(Date().timeIntervalSince1970))"
- Keychain.save(service: Keychain.service, account: account, data: Data(hex.utf8))
- Keychain.setActiveAccount(account)
- self.hasKey = runtime.keysIsLoaded()
- self.npub = runtime.keysNpub()
- }
-}
-
-private enum Keychain {
- static let service = "com.radroots.keys"
- static let activeService = "com.radroots.keys.active"
- static let activeAccountKey = "active"
-
- static func accounts() -> [String] {
- let query: [String: Any] = [
- kSecClass as String: kSecClassGenericPassword,
- kSecAttrService as String: service,
- kSecMatchLimit as String: kSecMatchLimitAll,
- kSecReturnAttributes as String: true
- ]
- var result: CFTypeRef?
- let status = SecItemCopyMatching(query as CFDictionary, &result)
- guard status == errSecSuccess, let items = result as? [[String: Any]] else { return [] }
- return items.compactMap { $0[kSecAttrAccount as String] as? String }
- }
-
- static func activeAccount() -> String? {
- let query: [String: Any] = [
- kSecClass as String: kSecClassGenericPassword,
- kSecAttrService as String: activeService,
- kSecAttrAccount as String: activeAccountKey,
- kSecMatchLimit as String: kSecMatchLimitOne,
- kSecReturnData as String: true
- ]
- var item: CFTypeRef?
- let status = SecItemCopyMatching(query as CFDictionary, &item)
- guard status == errSecSuccess, let data = item as? Data else { return nil }
- return String(data: data, encoding: .utf8)
- }
-
- static func setActiveAccount(_ account: String) {
- let data = Data(account.utf8)
- let base: [String: Any] = [
- kSecClass as String: kSecClassGenericPassword,
- kSecAttrService as String: activeService,
- kSecAttrAccount as String: activeAccountKey
- ]
- SecItemDelete(base as CFDictionary)
- var query = base
- query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
- query[kSecValueData as String] = data
- SecItemAdd(query as CFDictionary, nil)
- }
-
- static func load(service: String, account: String) -> Data? {
- let query: [String: Any] = [
- kSecClass as String: kSecClassGenericPassword,
- kSecAttrService as String: service,
- kSecAttrAccount as String: account,
- kSecMatchLimit as String: kSecMatchLimitOne,
- kSecReturnData as String: true
- ]
- var item: CFTypeRef?
- let status = SecItemCopyMatching(query as CFDictionary, &item)
- guard status == errSecSuccess, let data = item as? Data else { return nil }
- return data
- }
-
- static func save(service: String, account: String, data: Data) {
- let query: [String: Any] = [
- kSecClass as String: kSecClassGenericPassword,
- kSecAttrService as String: service,
- kSecAttrAccount as String: account,
- kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
- kSecValueData as String: data
- ]
- SecItemAdd(query as CFDictionary, nil)
+ public func refresh(runtime: RadrootsRuntime) {
+ self.hasKey = runtime.accountsHasSelectedSigningIdentity()
+ self.npub = runtime.accountsSelectedNpub()
}
}
diff --git a/RadrootsKit/Sources/RadrootsKit/TradeListing.swift b/RadrootsKit/Sources/RadrootsKit/TradeListing.swift
@@ -36,14 +36,12 @@ public extension Radroots {
func tradeListingFetchMessages(
listingAddr: String,
- orderId: String? = nil,
limit: UInt16,
sinceUnix: UInt64? = nil
) throws -> [TradeListingMessageSummary] {
let rt = try requireRuntime()
return try rt.tradeListingFetchMessages(
listingAddr: listingAddr,
- orderId: orderId,
limit: limit,
sinceUnix: sinceUnix
)
diff --git a/project.yml b/project.yml
@@ -0,0 +1,38 @@
+name: Radroots
+
+options:
+ deploymentTarget:
+ iOS: "18.0"
+
+configs:
+ Debug: debug
+ Release: release
+
+packages:
+ RadrootsKit:
+ path: RadrootsKit
+
+targets:
+ Radroots:
+ type: application
+ platform: iOS
+ deploymentTarget: "18.0"
+ sources:
+ - path: Radroots
+ excludes:
+ - Info.plist
+ settings:
+ base:
+ SWIFT_VERSION: 6.0
+ INFOPLIST_FILE: Radroots/Info.plist
+ configFiles:
+ Debug: Radroots/Config/Debug.xcconfig
+ Release: Radroots/Config/Release.xcconfig
+ dependencies:
+ - package: RadrootsKit
+ preBuildScripts:
+ - name: Generate git SHA xcconfig
+ basedOnDependencyAnalysis: false
+ script: |
+ GIT_SHA=$(git rev-parse --short HEAD || echo "unknown")
+ echo "GIT_SHA = $GIT_SHA" > "$SRCROOT/Radroots/radroots.git.xcconfig"