Improve scrolling behaviour and add name colors

This commit is contained in:
David Langley 2021-09-16 23:48:59 +01:00
parent 2e952a6298
commit 50684fda0b
7 changed files with 72 additions and 15 deletions

View file

@ -0,0 +1,27 @@
//
// 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 Foundation
import SwiftUI
@available(iOS 14.0, *)
extension ThemeSwiftUI {
func displayNameColor(for userId: String) -> Color {
let senderNameColorIndex = Int(userId.vc_hashCode % Int32(colors.namesAndAvatars.count))
return colors.namesAndAvatars[senderNameColorIndex]
}
}

View file

@ -35,7 +35,6 @@ class TemplateRoomChatService: TemplateRoomChatServiceProtocol {
private let eventFormatter: EventFormatter
private var roomState: MXRoomState?
private var roomListenerReference: Any?
private var usernameColorGenerator: UserNameColorGenerator()
// MARK: Public
private(set) var chatMessagesSubject: CurrentValueSubject<[TemplateRoomChatMessage], Never>
@ -47,7 +46,6 @@ class TemplateRoomChatService: TemplateRoomChatServiceProtocol {
// MARK: - Setup
init(room: MXRoom) {
)
self.room = room
self.eventFormatter = EventFormatter(matrixSession: room.mxSession)
self.chatMessagesSubject = CurrentValueSubject([])

View file

@ -37,13 +37,27 @@ struct TemplateRoomChat: View {
}
.frame(maxHeight: .infinity)
} else {
ScrollView{
LazyVStack {
ForEach(viewModel.viewState.bubbles) { bubble in
TemplateRoomChatBubbleView(bubble: bubble)
ScrollViewReader { reader in
ScrollView{
LazyVStack {
ForEach(viewModel.viewState.bubbles) { bubble in
TemplateRoomChatBubbleView(bubble: bubble)
.id(bubble.id)
}
}
.onAppear {
// Start at the bottom
reader.scrollTo(viewModel.viewState.bubbles.last?.id, anchor: .bottom)
}
.onChange(of: itemCount) { _ in
// When new items are added animate to the new items
withAnimation {
reader.scrollTo(viewModel.viewState.bubbles.last?.id, anchor: .bottom)
}
}
// When the scroll content takes less than the screen space align at the top
.frame(maxHeight: .infinity, alignment: .top)
}
.frame(maxHeight: .infinity, alignment: .top)
}
.frame(maxHeight: .infinity)
}
@ -59,6 +73,7 @@ struct TemplateRoomChat: View {
})
}
}
// When displaying/hiding the send button slide it on/off from the right side
.animation(.easeOut(duration: 0.25))
.transition(.move(edge: .trailing))
.padding(.horizontal)
@ -78,6 +93,14 @@ struct TemplateRoomChat: View {
}
}
}
private var itemCount: Int {
return viewModel.viewState
.bubbles
.map(\.items)
.map(\.count)
.reduce(0, +)
}
}
// MARK: - Previews

View file

@ -32,6 +32,7 @@ struct TemplateRoomChatBubbleMessage: View {
var body: some View {
Text(messageContent.body)
.foregroundColor(theme.colors.primaryContent)
.font(theme.fonts.body)
}
}

View file

@ -34,12 +34,12 @@ struct TemplateRoomChatBubbleView: View {
AvatarImage(avatarData: bubble.sender.avatarData, size: .xSmall)
VStack(alignment: .leading){
Text(bubble.sender.displayName ?? "")
.foregroundColor(theme.colors.primaryContent)
.foregroundColor(theme.displayNameColor(for: bubble.sender.id))
.font(theme.fonts.bodySB)
ForEach(bubble.items) { item in
TemplateRoomChatBubbleContentView(bubbleItem: item)
}
}
Spacer()
}
//add to a style

View file

@ -43,14 +43,16 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
init(templateRoomChatService: TemplateRoomChatServiceProtocol) {
self.templateRoomChatService = templateRoomChatService
super.init(initialViewState: Self.defaultState(templateRoomChatService: templateRoomChatService))
templateRoomChatService.chatMessagesSubject
setupMessageObserving()
}
private func setupMessageObserving() {
let messageActionPublisher = templateRoomChatService
.chatMessagesSubject
.map(Self.makeBubbles(messages:))
.map(TemplateRoomChatStateAction.updateBubbles)
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] action in
self?.dispatch(action:action)
})
.store(in: &cancellables)
.eraseToAnyPublisher()
dispatch(actionPublisher: messageActionPublisher)
}
private static func defaultState(templateRoomChatService: TemplateRoomChatServiceProtocol) -> TemplateRoomChatViewState {
@ -65,6 +67,7 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
var bubbleMap = [String:TemplateRoomChatBubble]()
messages.enumerated().forEach { i, message in
// New message content
let messageItem = TemplateRoomChatBubbleItem(
id: message.id,
timestamp: message.timestamp,
@ -77,6 +80,8 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
let interveningTime = lastBubble.items.last?.timestamp.timeIntervalSince(message.timestamp),
abs(interveningTime) < Constants.maxTimeBeforeNewBubble
{
// if the last bubble's last message was within
// the last 5 minutes append
let item = TemplateRoomChatBubbleItem(
id: message.id,
timestamp: message.timestamp,
@ -85,6 +90,7 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
lastBubble.items.append(item)
bubbleMap[lastBubble.id] = lastBubble
} else {
// else create a new bubble and add the message as the first item
let bubble = TemplateRoomChatBubble(
id: message.id,
sender: message.sender,

View file

@ -36,6 +36,8 @@ targets:
- path: ../Riot/Generated/Images.swift
- path: ../Riot/Managers/Theme/ThemeIdentifier.swift
- path: ../Riot/Managers/Locale/LocaleProviderType.swift
- path: ../Riot/Categories/String.swift
- path: ../Riot/Categories/Character.swift
- path: ../Riot/Assets/en.lproj/Vector.strings
buildPhase: resources
- path: ../Riot/Assets/Images.xcassets