Add subviews for message and image

This commit is contained in:
David Langley 2021-09-13 09:26:21 +01:00
parent 65c7e5c661
commit 8005a24caa
8 changed files with 198 additions and 24 deletions

View file

@ -0,0 +1,49 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import UIKit
struct TemplateRoomChatBubble {
var id: String
var senderAvatar: AvatarInputProtocol
var senderDisplayName: String?
var items: [TemplateRoomChatBubbleItem]
}
extension TemplateRoomChatBubble: Identifiable { }
enum TemplateRoomChatBubbleItem {
var id: Self { self }
case message(TemplateRoomChatBubbleMessageItem)
case image(TemplateRoomChatBubbleImageItem)
}
extension TemplateRoomChatBubbleItem: Hashable, Identifiable {}
struct TemplateRoomChatBubbleMessageItem {
var id: String
var body: String
}
extension TemplateRoomChatBubbleMessageItem: Hashable {}
struct TemplateRoomChatBubbleImageItem {
var id: String
var image: UIImage
}
extension TemplateRoomChatBubbleImageItem: Hashable {}

View file

@ -17,5 +17,5 @@
import Foundation
struct TemplateRoomChatViewModelInput {
let messageInput: String
var messageInput: String
}

View file

@ -19,12 +19,13 @@ import Combine
@available(iOS 14.0, *)
class MockTemplateRoomChatService: TemplateRoomChatServiceProtocol {
static let alice = TemplateRoomChatMember(id: "@alice:matrix.org", avatarUrl: "!aaabaa:matrix.org", displayName: "Alice")
static let mathew = TemplateRoomChatMember(id: "@mathew:matrix.org", avatarUrl: "!bbabb:matrix.org", displayName: "Mathew")
static let mockMessages = [
TemplateRoomChatMessage(id: "!aaabaa:matrix.org", body: "Shall I put it live?", sender: "@alice:matrix.org"),
TemplateRoomChatMessage(id: "!bbbabb:matrix.org", body: "Yea go for it! ...and then let's head to the pub", sender: "@patrice:matrix.org"),
TemplateRoomChatMessage(id: "!aaabaa:matrix.org", body: "Deal.", sender: "@alice:matrix.org"),
TemplateRoomChatMessage(id: "!aaabaa:matrix.org", body: "Ok, Done. 🍻", sender: "@alice:matrix.org"),
TemplateRoomChatMessage(id: "!11111:matrix.org", body: "Shall I put it live?", sender: alice),
TemplateRoomChatMessage(id: "!22222:matrix.org", body: "Yea go for it! ...and then let's head to the pub", sender: mathew),
TemplateRoomChatMessage(id: "!33333:matrix.org", body: "Deal.", sender: alice),
TemplateRoomChatMessage(id: "!44444:matrix.org", body: "Ok, Done. 🍻", sender: alice),
]
var chatMessagesSubject: CurrentValueSubject<[TemplateRoomChatMessage], Never>

View file

@ -31,15 +31,25 @@ struct TemplateRoomChat: View {
var body: some View {
VStack {
LazyVStack {
}.frame(maxHeight: .infinity)
if viewModel.viewState.bubbles.isEmpty {
VStack{
Text("No messages")
}
.frame(maxHeight: .infinity)
} else {
LazyVStack {
ForEach(viewModel.viewState.bubbles) { bubble in
TemplateRoomChatBubbleView(bubble: bubble)
}
}
.frame(maxHeight: .infinity, alignment: .top)
}
HStack {
TextField(VectorL10n.roomMessageShortPlaceholder, text: $viewModel.input.messageInput)
.textFieldStyle(BorderedInputFieldStyle())
Button(action: {
}, label: {
Image(uiImage: Asset.Images.sendIcon.image)
})

View file

@ -0,0 +1,49 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
@available(iOS 14.0, *)
struct TemplateRoomChatBubbleItemView: View {
// MARK: - Properties
// MARK: Private
@Environment(\.theme) private var theme: ThemeSwiftUI
// MARK: Public
let bubbleItem: TemplateRoomChatBubbleItem
var body: some View {
switch bubbleItem {
case .message(let messageItem):
TemplateRoomChatBubbleMessage(messageItem: messageItem)
case .image(let imageItem):
TemplateRoomChatBubbleImage(imageItem: imageItem)
}
}
}
// MARK: - Previews
@available(iOS 14.0, *)
struct TemplateRoomChatBubbleItemView_Previews: PreviewProvider {
static var previews: some View {
EmptyView()
}
}

View file

@ -0,0 +1,44 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import SwiftUI
@available(iOS 14.0, *)
struct TemplateRoomChatBubbleMessage: View {
// MARK: - Properties
// MARK: Private
@Environment(\.theme) private var theme: ThemeSwiftUI
// MARK: Public
let messageItem: TemplateRoomChatBubbleMessageItem
var body: some View {
Text(messageItem.body)
}
}
// MARK: - Previews
@available(iOS 14.0, *)
struct TemplateRoomChatBubbleMessage_Previews: PreviewProvider {
static var previews: some View {
EmptyView()
}
}

View file

@ -31,9 +31,9 @@ struct TemplateRoomChatBubbleView: View {
var body: some View {
HStack{
AvatarImage(avatarData: bubble.avatar, size: .xSmall)
VStack{
Text(bubble.displayName ?? "")
AvatarImage(avatarData: bubble.senderAvatar, size: .xSmall)
VStack(alignment: .leading){
Text(bubble.senderDisplayName ?? "")
ForEach(bubble.items) { item in
TemplateRoomChatBubbleItemView(bubbleItem: item)
}
@ -52,7 +52,14 @@ struct TemplateRoomChatBubbleView: View {
@available(iOS 14.0, *)
struct TemplateRoomChatBubbleView_Previews: PreviewProvider {
static let bubble = TemplateRoomChatBubble(
id: "111",
senderAvatar: MockAvatarInput.example,
senderDisplayName: "Alice",
items: [.message(TemplateRoomChatBubbleMessageItem(id: "222", body: "Hello world! 🌎"))]
)
static var previews: some View {
EmptyView()
TemplateRoomChatBubbleView(bubble: bubble)
.addDependency(MockAvatarService.example)
}
}

View file

@ -55,20 +55,34 @@ class TemplateRoomChatViewModel: ObservableObject, TemplateRoomChatViewModelProt
private static func makeBubbles(messages: [TemplateRoomChatMessage]) -> [TemplateRoomChatBubble] {
var bubbleOrder = [String]()
var bubbleMap = [String:TemplateRoomChatBubble]()
messages.enumerated().forEach { i, message in
let currentMessage = messages[i]
if i > 0 {
let lastMessage = messages[i-1]
} else {
TemplateRoomChatBubble(
id: message.,
avatar: <#T##AvatarInputProtocol#>,
displayName: <#T##String?#>,
items: <#T##[TemplateRoomChatBubbleItem]#>
if i > 0,
messages[i-1].sender.id == message.sender.id,
var existingBubble = bubbleMap[messages[i-1].id] {
let messageItem = TemplateRoomChatBubbleMessageItem(
id: message.id,
body: message.body
)
existingBubble.items.append(.message(messageItem))
bubbleMap[existingBubble.id] = existingBubble
} else {
let messageItem = TemplateRoomChatBubbleMessageItem(
id: message.id,
body: message.body
)
let bubble = TemplateRoomChatBubble(
id: message.id,
senderAvatar: message.sender.avatarData,
senderDisplayName: message.sender.displayName,
items: [.message(messageItem)]
)
bubbleOrder.append(bubble.id)
bubbleMap[bubble.id] = bubble
}
}
return bubbleOrder.compactMap({ bubbleMap[$0] })
}
// MARK: - Public