mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Add subviews for message and image
This commit is contained in:
parent
65c7e5c661
commit
8005a24caa
8 changed files with 198 additions and 24 deletions
|
@ -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 {}
|
|
@ -17,5 +17,5 @@
|
|||
import Foundation
|
||||
|
||||
struct TemplateRoomChatViewModelInput {
|
||||
let messageInput: String
|
||||
var messageInput: String
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue