field_ios

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

PostCreateView.swift (3617B)


      1 import SwiftUI
      2 
      3 struct PostCreateView: View {
      4     @EnvironmentObject private var app: AppState
      5     @State private var text: String = ""
      6     @State private var isPosting = false
      7     @State private var resultMessage: String?
      8     @State private var showResult = false
      9     @FocusState private var focused: Bool
     10 
     11     private var isConnected: Bool { app.relayConnectedCount > 0 }
     12     private var canPost: Bool {
     13         isConnected && !isPosting && !text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
     14     }
     15 
     16     var body: some View {
     17         Form {
     18             Section {
     19                 ZStack(alignment: .topLeading) {
     20                     TextEditor(text: $text)
     21                         .frame(minHeight: 160)
     22                         .focused($focused)
     23                         .submitLabel(.send)
     24                     if text.isEmpty {
     25                         Text("What's happening?")
     26                             .foregroundStyle(.secondary)
     27                             .padding(.top, 8)
     28                             .padding(.leading, 5)
     29                             .allowsHitTesting(false)
     30                     }
     31                 }
     32                 HStack {
     33                     Text("\(text.count)")
     34                         .font(.footnote)
     35                         .foregroundStyle(.secondary)
     36                     Spacer()
     37                     Button {
     38                         post()
     39                     } label: {
     40                         if isPosting {
     41                             ProgressView()
     42                         } else {
     43                             Text("Post")
     44                                 .fontWeight(.semibold)
     45                         }
     46                     }
     47                     .buttonStyle(.borderedProminent)
     48                     .disabled(!canPost)
     49                 }
     50             } footer: {
     51                 VStack(alignment: .leading, spacing: 4) {
     52                     if !isConnected {
     53                         Text("No relays connected. Configure and connect to post.")
     54                             .foregroundStyle(.red)
     55                     }
     56                     if let e = app.relayLastError {
     57                         Text(e).foregroundStyle(.secondary)
     58                     }
     59                 }
     60             }
     61         }
     62         .listStyle(.insetGrouped)
     63         .inlineNavigationTitle("Compose")
     64         .toolbar {
     65             ToolbarItemGroup(placement: .keyboard) {
     66                 Spacer()
     67                 Button("Done") { focused = false }
     68             }
     69         }
     70         .alert("Post Result", isPresented: $showResult) {
     71             Button("OK", role: .cancel) { }
     72         } message: {
     73             Text(resultMessage ?? "")
     74         }
     75         .onAppear { focused = true }
     76     }
     77 
     78     private func post() {
     79         guard let service = app.runtimeService else { return }
     80         let content = text.trimmingCharacters(in: .whitespacesAndNewlines)
     81         guard !content.isEmpty else { return }
     82         isPosting = true
     83         resultMessage = nil
     84         Task {
     85             do {
     86                 let id = try await service.nostrPostTextNote(content: content)
     87                 await MainActor.run {
     88                     resultMessage = "Posted kind:1 event: \(id.rawValue)"
     89                     showResult = true
     90                     text = ""
     91                     isPosting = false
     92                     app.refresh()
     93                 }
     94             } catch {
     95                 await MainActor.run {
     96                     resultMessage = "Failed to post: \(error.fieldRuntimeMessage)"
     97                     showResult = true
     98                     isPosting = false
     99                 }
    100             }
    101         }
    102     }
    103 }