Swift

Eventos de bate-papo

Anteriormente, você criou uma conversa na CLI da Vonage e adicionou os dois usuários a essa conversa. As conversas são o meio pelo qual os usuários se comunicarão. Você pode saber mais sobre conversas na Documentação da Conversation API. Eventos de bate-papo, ou VGConversationEvent Os objetos são enviados por meio da conversa que você criou; portanto, para receber eventos de chat, primeiro você precisará entrar na conversa. Para implementar isso, atualize o ChatViewModel classe.

Adicione o getMemberIDIfNeeded função:

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

Isso verificará se o memberID, que é gerado quando você entra em uma conversa, ainda não foi definido. Caso contrário, ele chama getMemberID. Criar 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)
        }
    }
}

Essa função tenta, em primeiro lugar, obter o ID de membro desse usuário com getConversationMember, se não der certo, ele entrará na conversa com joinConversation que retorna o ID do membro.

Agora que se tem a certeza de que esse usuário faz parte da conversa, você pode obter os eventos da conversa usando o cliente. Crie uma função chamada 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 recebe um ID de conversa e VGGetConversationEventsParameters. Os parâmetros permitem que você personalize a forma como os eventos são exibidos. Essa função retorna uma resposta paginada. Para saber mais sobre paginação, você pode ler o guia de paginação. Para exibir os eventos, crie uma função auxiliar que transforme os objetos de evento em uma string de exibição:

@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)
        }
    }
}

Os três eventos utilizados neste tutorial são memberJoined, memberLeft, e messageText. No caso de messageText a função utiliza o memberID propriedade para determinar se a mensagem foi enviada pelo usuário atualmente conectado. Isso permitirá que a interface do usuário fixe as mensagens enviadas pelo usuário à direita e as mensagens recebidas à esquerda.

O VGChatClientDelegate

O aplicativo também precisa reagir aos eventos que ocorrem em uma conversa após o carregamento inicial; portanto, você precisa implementar o VGChatClientDelegate didReceiveConversationEvent evento.

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) {}
}

Quando um novo evento é recebido, ele é anexado à events que é publicado automaticamente, de modo que a interface do usuário seja atualizada.

Atualização da interface do usuário

Agora que o ChatViewModel é possível recuperar e monitorar novos eventos de conversa; atualize o código da visualização para exibi-los:

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()
            }
        }
    }
}

Agora no List, a instrução `switch` foi atualizada para chamar generateDisplayText para os três tipos diferentes de eventos de conversação que o tutorial utiliza. Há também um ProgressView pois quando o ChatViewModel está carregando. Quando a visualização for carregada, onAppear é chamada, que, por sua vez, chama as funções que você criou no ChatViewModel.

Compilar e executar

Imprensa Cmd + R para compilar e executar novamente. Após fazer login, você verá que a Alice entrou na conversa:

Chat interface with connection events