diff --git a/Example/AblyChatExample/ContentView.swift b/Example/AblyChatExample/ContentView.swift index a713209d..dd29aa3f 100644 --- a/Example/AblyChatExample/ContentView.swift +++ b/Example/AblyChatExample/ContentView.swift @@ -10,6 +10,7 @@ struct ContentView: View { @State private var title = "Room: " @State private var messages = [Message]() + @State private var reactions = "" @State private var newMessage = "" private func room() async -> Room { @@ -18,7 +19,12 @@ struct ContentView: View { var body: some View { VStack { - Text(title).font(.headline) + Text(title) + .font(.headline) + .padding(5) + Text(reactions) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(5) List(messages, id: \.timeserial) { message in MessageBasicView(message: message) .flip() @@ -49,14 +55,22 @@ struct ContentView: View { .padding(.bottom, 10) .padding(.horizontal, 12) .task { - let room = await room() - title = "Room: \(room.roomID)" - for await message in await room.messages.subscribe(bufferingPolicy: .unbounded) { + title = await "Room: \(room().roomID)" + } + .task { + for await message in await room().messages.subscribe(bufferingPolicy: .unbounded) { withAnimation { messages.insert(message, at: 0) } } } + .task { + for await reaction in await room().reactions.subscribe(bufferingPolicy: .unbounded) { + withAnimation { + reactions.append(reaction.type == "like" ? "👍" : "🤷") + } + } + } } } @@ -86,7 +100,6 @@ struct MessageBasicView: View { Spacer() } } - .padding(.leading, 5) .listRowSeparator(.hidden) } } diff --git a/Example/AblyChatExample/Mocks/Mocks.swift b/Example/AblyChatExample/Mocks/Mocks.swift index 8b897b06..4ca80acd 100644 --- a/Example/AblyChatExample/Mocks/Mocks.swift +++ b/Example/AblyChatExample/Mocks/Mocks.swift @@ -55,7 +55,7 @@ actor MockRoom: Room { } nonisolated var reactions: any RoomReactions { - fatalError("Not yet implemented") + MockRoomReactions(clientID: "AblyTest", roomID: roomID) } nonisolated var typing: any Typing { @@ -141,3 +141,58 @@ struct MockMessageSubscription: Sendable, AsyncSequence, AsyncIteratorProtocol { self } } + +actor MockRoomReactions: RoomReactions { + let clientID: String + let roomID: String + let channel: RealtimeChannel + + init(clientID: String, roomID: String) { + self.clientID = clientID + self.roomID = roomID + self.channel = MockRealtimeChannel() + } + + func send(params: RoomReactionParams) async throws { + _ = Reaction(type: "like", + metadata: [:], + headers: [:], + createdAt: Date(), + clientID: clientID, + isSelf: true) + } + + func subscribe(bufferingPolicy: BufferingPolicy) -> Subscription { + .init(mockAsyncSequence: MockReactionSubscription(clientID: clientID, roomID: roomID)) + } + + func subscribeToDiscontinuities() async -> Subscription { + fatalError("Not yet implemented") + } +} + +struct MockReactionSubscription: Sendable, AsyncSequence, AsyncIteratorProtocol { + typealias Element = Reaction + + let clientID: String + let roomID: String + + public init(clientID: String, roomID: String) { + self.clientID = clientID + self.roomID = roomID + } + + public mutating func next() async -> Element? { + try? await Task.sleep(nanoseconds: 1 * 1_000_000_000) + return Reaction(type: "like", + metadata: [:], + headers: [:], + createdAt: Date(), + clientID: self.clientID, + isSelf: false) + } + + public func makeAsyncIterator() -> Self { + self + } +}