Swift

チャットイベント

先にVonage CLIで会話を作成し、その会話に2人のユーザーを追加しました。会話はユーザが通信する方法です。会話についての詳細は Conversation API ドキュメント.チャットイベント VGConversationEvent オブジェクトは、あなたが作成した会話を使って送信されるので、チャットイベントを取得するには、まず会話に参加する必要があります。これを実装するには ChatViewModel クラスである。

を追加する。 getMemberIDIfNeeded 関数である:

@MainActor
final class ChatViewModel: NSObject, ObservableObject {
    ...
    
    func getMemberIDIfNeeded() async {
        guard memberID == nil else { return }
        await getMemberID()
    }   
}

これは memberID会話に参加するときに生成される「会話に参加する」がまだ設定されていない場合は、「会話に参加する」を呼び出します。設定されていない場合は getMemberID.作成する getMemberID:

@MainActor
final class ChatViewModel: NSObject, ObservableObject {
    ...
    
    private func getMemberID() async {
        let member = try? await client.getConversationMember(conversationID, memberId: "me")
        memberID = member?.id
        
        if memberID == nil {
            memberID = try? await client.joinConversation(conversationID)
        }
    }
}

この関数は、まずこのユーザーのメンバーIDを getConversationMemberもし失敗すれば、次のように会話に加わる。 joinConversation これはメンバーIDを返す。

これで、そのユーザーが会話のメンバーであることが保証されたので、クライアントを使用して会話イベントを取得することができます。という関数を作成します。 getConversationEvents:

@MainActor
final class ChatViewModel: NSObject, ObservableObject {
    ...
    func getConversationEvents() async {
        let params = VGGetConversationEventsParameters(order: .asc, pageSize: 100)
        let eventsPage = try? await client.getConversationEvents(conversationID, parameters: params)
        self.events = eventsPage?.events ?? []
    }
}

getConversationEvents 会話IDと VGGetConversationEventsParameters.パラメータにより、イベントの返し方をカスタマイズすることができます。この関数は、ページ分割されたレスポンスを返します。ページ分割についての詳細は ページネーションガイド.イベントを表示するには、イベント・オブジェクトを表示文字列に変換するヘルパー関数を作成する:

@MainActor
final class ChatViewModel: NSObject, ObservableObject {
    ...
    func generateDisplayText(_ event: VGPersistentConversationEvent) -> (body: String, isUser: Bool) {
        var from = "System"
        
        switch event.kind {
        case .memberJoined:
            let memberJoinedEvent = event as! VGMemberJoinedEvent
            from = memberJoinedEvent.body.user.name
            return ("\(from) joined", false)
        case .memberLeft:
            let memberLeftEvent = event as! VGMemberLeftEvent
            from = memberLeftEvent.body.user.name
            return ("\(from) left", false)
        case .messageText:
            let messageTextEvent = event as! VGMessageTextEvent
            var isUser = false
            
            if let userInfo = messageTextEvent.from as? VGEmbeddedInfo {
                isUser = userInfo.memberId == memberID
                from = isUser ? "" : "\(userInfo.user.name): "
            }
            
            return ("\(from) \(messageTextEvent.body.text)", isUser)
        default:
            return ("", false)
        }
    }
}

このチュートリアルで使用する3つのイベントは次のとおりです。 memberJoined, memberLeftそして messageText.の場合 messageText この関数は memberID プロパティを使用して、現在のログイン・ユーザーによって送信されたメッセージかどうかを判断します。これにより、UIはユーザが送信したメッセージを右に、受信したメッセージを左に固定することができます。

について VGChatClientDelegate

アプリケーションは、最初にロードした後、会話のイベントに反応する必要があります。 VGChatClientDelegate didReceiveConversationEvent イベントを開催する。

extension ChatViewModel: VGChatClientDelegate {
    nonisolated func chatClient(_ client: VGChatClient, didReceiveConversationEvent event: VGConversationEvent) {
        Task { @MainActor in
            self.events.append(event as! VGPersistentConversationEvent)
        }
    }
    
    nonisolated func client(_ client: VGBaseClient, didReceiveSessionErrorWith reason: VGSessionErrorReason) {}
}

新しいイベントが受信されると、それは events これは自動的にパブリッシュされるので、UIは更新される。

UIの更新

今は ChatViewModel は、新しい会話イベントを取得してリッスンし、それらを表示するためにビューコードを更新することができます:

struct ChatView: View {
    @StateObject var chatViewModel: ChatViewModel
    @State private var message: String = ""
    
    var body: some View {
        VStack {
            if chatViewModel.events.isEmpty {
                ProgressView()
            } else {
                VStack {
                    List {
                        ForEach(chatViewModel.events, id: \.id) { event in
                            switch event.kind {
                            case .memberJoined, .memberLeft:
                                let displayText = chatViewModel.generateDisplayText(event)
                                Text(displayText.body)
                                    .frame(maxWidth: .infinity, alignment: .center)
                            case.messageText:
                                let displayText = chatViewModel.generateDisplayText(event)
                                Text(displayText.body)
                                    .frame(maxWidth: .infinity, alignment: displayText.isUser ? .trailing : .leading)
                            default:
                                EmptyView()
                            }
                        }.listRowSeparator(.hidden)
                    }.listStyle(.plain)
                    
                    Spacer()
                    
                    HStack {
                        TextField("Message", text: $message)
                        Button("Send") {
                            Task {
                                
                            }
                        }.buttonStyle(.bordered)
                    }.padding(8)
                }
            }
        }.onAppear {
            Task {
                await chatViewModel.getMemberIDIfNeeded()
                await chatViewModel.getConversationEvents()
            }
        }
    }
}

現在は Listを呼び出すように更新された。 generateDisplayText チュートリアルで使用する3つの異なるタイプの会話イベントです。また ProgressView となったときのために ChatViewModel がロードされている。ビューがロードされると onAppear で作成した関数が呼び出されます。 ChatViewModel.

ビルド&ラン

プレス Cmd + R をビルドして再度実行してください。ログインすると、アリスが会話に参加していることがわかります:

Chat interface with connection events