Files
letro-ios/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineItemPlainStylerView.swift
Mauro c008e8de92 Avatars and Usernames color change (#1610)
* avatars and username color change

* force a replacement for the notification placeholders

* updated also the plain style

* Update project.yml

Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com>

* changelog

* UI tests updated

---------

Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com>
2023-09-01 09:28:28 +00:00

153 lines
5.8 KiB
Swift

//
// Copyright 2022 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
struct TimelineItemPlainStylerView<Content: View>: View {
@EnvironmentObject private var context: RoomScreenViewModel.Context
@Environment(\.timelineGroupStyle) private var timelineGroupStyle
let timelineItem: EventBasedTimelineItemProtocol
@ViewBuilder let content: () -> Content
@State private var showItemActionMenu = false
var body: some View {
VStack(alignment: .trailing) {
VStack(alignment: .leading, spacing: 4) {
header
VStack(alignment: .leading, spacing: 4) {
HStack(alignment: .firstTextBaseline) {
contentWithReply
Spacer()
}
supplementaryViews
}
}
TimelineItemStatusView(timelineItem: timelineItem)
.environmentObject(context)
}
}
@ViewBuilder
var contentWithReply: some View {
VStack(alignment: .leading) {
if let messageTimelineItem = timelineItem as? EventBasedMessageTimelineItemProtocol,
let replyDetails = messageTimelineItem.replyDetails {
HStack(spacing: 4.0) {
Rectangle()
.foregroundColor(.global.melon)
.frame(width: 4.0)
TimelineReplyView(placement: .timeline, timelineItemReplyDetails: replyDetails)
}
}
content()
}
.onTapGesture(count: 2) {
context.send(viewAction: .displayEmojiPicker(itemID: timelineItem.id))
}
.onTapGesture {
context.send(viewAction: .itemTapped(itemID: timelineItem.id))
}
// We need a tap gesture before this long one so that it doesn't
// steal away the gestures from the scroll view
.longPressWithFeedback {
context.send(viewAction: .timelineItemMenu(itemID: timelineItem.id))
}
.swipeRightAction {
Image(systemName: "arrowshape.turn.up.left")
} shouldStartAction: {
context.viewState.timelineItemMenuActionProvider?(timelineItem.id)?.canReply ?? false
} action: {
context.send(viewAction: .timelineItemMenuAction(itemID: timelineItem.id, action: .reply))
}
.contextMenu {
TimelineItemMacContextMenu(item: timelineItem,
actionProvider: context.viewState.timelineItemMenuActionProvider) { action in
context.send(viewAction: .timelineItemMenuAction(itemID: timelineItem.id, action: action))
}
}
}
@ViewBuilder
private var header: some View {
if shouldShowSenderDetails {
HStack {
HStack {
TimelineSenderAvatarView(timelineItem: timelineItem)
Text(timelineItem.sender.displayName ?? timelineItem.sender.id)
.font(.subheadline)
.foregroundColor(.compound.avatarColor(for: timelineItem.sender.id).foreground)
.fontWeight(.semibold)
.lineLimit(1)
}
.onTapGesture {
context.send(viewAction: .tappedOnUser(userID: timelineItem.sender.id))
}
Spacer()
Text(timelineItem.timestamp)
.foregroundColor(.compound.textSecondary)
.font(.compound.bodyXS)
}
.padding(.top, 16)
}
}
@ViewBuilder
private var supplementaryViews: some View {
VStack {
if timelineItem.properties.isEdited {
Text(L10n.commonEditedSuffix)
.font(.compound.bodySM)
.foregroundColor(.compound.textSecondary)
}
if !timelineItem.properties.reactions.isEmpty {
TimelineReactionsView(itemID: timelineItem.id,
reactions: timelineItem.properties.reactions,
collapsed: context.reactionsCollapsedBinding(for: timelineItem.id))
// Workaround to stop the message long press stealing the touch from the reaction buttons
.onTapGesture { }
}
}
}
private var shouldShowSenderDetails: Bool {
timelineGroupStyle.shouldShowSenderDetails
}
}
struct TimelineItemPlainStylerView_Previews: PreviewProvider {
static let viewModel = RoomScreenViewModel.mock
static var previews: some View {
VStack(alignment: .leading, spacing: 0) {
ForEach(1..<MockRoomTimelineController().timelineItems.count, id: \.self) { index in
let item = MockRoomTimelineController().timelineItems[index]
RoomTimelineItemView(viewState: .init(item: item, groupStyle: .single))
.padding(TimelineStyle.plain.rowInsets) // Insets added in the table view cells
}
}
.environment(\.timelineStyle, .plain)
.previewLayout(.sizeThatFits)
.environmentObject(viewModel.context)
}
}