field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | LICENSE

FieldExternalActions.swift (3789B)


      1 import Foundation
      2 import RadrootsKit
      3 
      4 public enum FieldExternalActionRecovery: String, Equatable, Sendable {
      5     case appSettings
      6 }
      7 
      8 public struct FieldExternalActionRequestRecord: Equatable, Sendable {
      9     public let kind: RadrootsExternalActionDestinationKind
     10     public let urlString: String?
     11 
     12     init(destination: RadrootsExternalActionDestination) {
     13         self.kind = destination.kind
     14         self.urlString = destination.url?.absoluteString
     15     }
     16 
     17     public var statusText: String {
     18         switch kind {
     19         case .appSettings:
     20             "Requested app settings"
     21         case .web:
     22             "Requested web link"
     23         case .nostr:
     24             "Requested Nostr profile"
     25         case .appleMaps:
     26             "Requested Apple Maps"
     27         }
     28     }
     29 }
     30 
     31 final class FieldExternalActions: Sendable {
     32     private let actions: any RadrootsExternalActions
     33 
     34     init(actions: any RadrootsExternalActions) {
     35         self.actions = actions
     36     }
     37 
     38     static func configured() -> FieldExternalActions {
     39         #if DEBUG
     40         if FieldUITestHarness.isRequested {
     41             return FieldExternalActions(actions: uiTestExternalActions())
     42         }
     43         #endif
     44         return FieldExternalActions(actions: RadrootsAppleExternalActions())
     45     }
     46 
     47     func canOpenPublicNostrProfile(npub: String) async -> Bool {
     48         guard let destination = try? publicNostrProfileDestination(npub: npub) else {
     49             return false
     50         }
     51         return await actions.canOpen(destination).canOpen
     52     }
     53 
     54     func openAppSettings() async throws -> FieldExternalActionRequestRecord {
     55         let destination = RadrootsExternalActionDestination.appSettings
     56         try await actions.open(RadrootsExternalActionRequest(destination: destination))
     57         return FieldExternalActionRequestRecord(destination: destination)
     58     }
     59 
     60     func openPublicNostrProfile(npub: String) async throws -> FieldExternalActionRequestRecord {
     61         let destination = try publicNostrProfileDestination(npub: npub)
     62         try await actions.open(RadrootsExternalActionRequest(destination: destination))
     63         return FieldExternalActionRequestRecord(destination: destination)
     64     }
     65 
     66     private func publicNostrProfileDestination(npub: String) throws -> RadrootsExternalActionDestination {
     67         try RadrootsExternalActionDestination.nostr("nostr:\(npub)")
     68     }
     69 
     70     #if DEBUG
     71     private static func uiTestExternalActions() -> FieldUITestExternalActions {
     72         FieldUITestExternalActions(
     73             defaultCanOpen: uiTestCanOpen,
     74             openOutcome: uiTestOpenOutcome
     75         )
     76     }
     77 
     78     private static var uiTestCanOpen: Bool {
     79         if FieldUITestHarness.string("RADROOTS_FIELD_IOS_UI_TEST_EXTERNAL_ACTIONS_NOSTR_CAN_OPEN") != nil {
     80             return FieldUITestHarness.bool("RADROOTS_FIELD_IOS_UI_TEST_EXTERNAL_ACTIONS_NOSTR_CAN_OPEN", default: true)
     81         }
     82         if FieldUITestHarness.string("RADROOTS_FIELD_IOS_UI_TEST_EXTERNAL_ACTIONS_CAN_OPEN") != nil {
     83             return FieldUITestHarness.bool("RADROOTS_FIELD_IOS_UI_TEST_EXTERNAL_ACTIONS_CAN_OPEN", default: true)
     84         }
     85         return true
     86     }
     87 
     88     private static var uiTestOpenOutcome: Result<Void, RadrootsExternalActionError> {
     89         let raw = FieldUITestHarness.string("RADROOTS_FIELD_IOS_UI_TEST_EXTERNAL_ACTIONS_OPEN_OUTCOME")?.lowercased()
     90         switch raw {
     91         case nil, "", "success":
     92             return .success(())
     93         case "unavailable":
     94             return .failure(.unavailable("external actions are unavailable in this UI test"))
     95         case "transient_failure":
     96             return .failure(.transientFailure("external action failed in this UI test"))
     97         default:
     98             return .failure(.blockedByPolicy("unsupported UI-test external action outcome"))
     99         }
    100     }
    101     #endif
    102 }