import SwiftUI import KordophoneKit struct ConversationView : View { var conversation: Conversation var messages: [Message] var sendAction: (String) -> Void @State private var inputText = "" @ViewBuilder private var transcript: some View { ScrollViewReader { proxy in ScrollView { LazyVStack { ForEach(messages) { message in if message.sentByMe { Spacer() } MessageViewWrapper(message: message) .id(message) if !message.sentByMe { Spacer() } } } } .onChange(of: messages) { newValue in proxy.scrollTo(newValue.last, anchor: .bottom) } } } @ViewBuilder private var inputView: some View { TextField.init(text: $inputText) { Text("Message") } .padding() .onSubmit { if inputText.count > 0 { sendAction(inputText) inputText = "" } } } var body: some View { VStack(spacing: 0) { transcript inputView } .navigationTitle(conversation.effectiveDisplayName) } } struct ConversationViewWrapper : View { var conversation: Conversation @State private var messages = [Message]() @EnvironmentObject private var connection: Connection @StateObject private var updater = IntervalUpdater(5) private func refresh() { Task { self.messages = await connection.messages(in: conversation) ?? .init() } } var body: some View { ConversationView(conversation: conversation, messages: messages) { sent in Task { await connection.send(text: sent, in: conversation) } refresh() } .onChange(of: conversation, perform: { newValue in refresh() }) .onAppear { refresh() } .onChange(of: updater.seed) { newValue in refresh() } } }