Skip to content

Commit

Permalink
Highlight selected emoji in picker, correct add more button in menu, …
Browse files Browse the repository at this point in the history
…fix order of count label on outgoing messages (#1430)

- Highlight selected emoji in picker
- Correct add more button in menu
- Fix the order of count/key label on outgoing messages
- Fix the size padding of emoji in reactions
  • Loading branch information
langleyd authored Aug 1, 2023
1 parent 4fc5b6f commit 686fee6
Show file tree
Hide file tree
Showing 17 changed files with 86 additions and 55 deletions.
22 changes: 11 additions & 11 deletions ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
case (.dismissMediaUploadPreview, .mediaUploadPreview(let roomID, _)):
return .room(roomID: roomID)

case (.presentEmojiPicker(let itemID), .room(let roomID)):
return .emojiPicker(roomID: roomID, itemID: itemID)
case (.dismissEmojiPicker, .emojiPicker(let roomID, _)):
case (.presentEmojiPicker(let itemID, let selectedEmoji), .room(let roomID)):
return .emojiPicker(roomID: roomID, itemID: itemID, selectedEmojis: selectedEmoji)
case (.dismissEmojiPicker, .emojiPicker(let roomID, _, _)):
return .room(roomID: roomID)

case (.presentMessageForwarding(let itemID), .room(let roomID)):
Expand Down Expand Up @@ -197,8 +197,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
case (.mediaUploadPreview, .dismissMediaUploadPreview, .room):
break

case (.room, .presentEmojiPicker, .emojiPicker(_, let itemID)):
presentEmojiPicker(for: itemID)
case (.room, .presentEmojiPicker, .emojiPicker(_, let itemID, let selectedEmoji)):
presentEmojiPicker(for: itemID, selectedEmoji: selectedEmoji)
case (.emojiPicker, .dismissEmojiPicker, .room):
break

Expand Down Expand Up @@ -303,8 +303,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
stateMachine.tryEvent(.presentMediaUploadPicker(source: source))
case .presentMediaUploadPreviewScreen(let url):
stateMachine.tryEvent(.presentMediaUploadPreview(fileURL: url))
case .presentEmojiPicker(let itemID):
stateMachine.tryEvent(.presentEmojiPicker(itemID: itemID))
case .presentEmojiPicker(let itemID, let selectedEmojis):
stateMachine.tryEvent(.presentEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis))
case .presentLocationPicker:
stateMachine.tryEvent(.presentMapNavigator(interactionMode: .picker))
case .presentLocationViewer(_, let geoURI, let description):
Expand Down Expand Up @@ -480,9 +480,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
}

private func presentEmojiPicker(for itemID: TimelineItemIdentifier) {
private func presentEmojiPicker(for itemID: TimelineItemIdentifier, selectedEmoji: Set<String>) {
let params = EmojiPickerScreenCoordinatorParameters(emojiProvider: emojiProvider,
itemID: itemID)
itemID: itemID, selectedEmojis: selectedEmoji)
let coordinator = EmojiPickerScreenCoordinator(parameters: params)
coordinator.callback = { [weak self] action in
switch action {
Expand Down Expand Up @@ -632,7 +632,7 @@ private extension RoomFlowCoordinator {
case roomDetails(roomID: String, isRoot: Bool)
case mediaUploadPicker(roomID: String, source: MediaPickerScreenSource)
case mediaUploadPreview(roomID: String, fileURL: URL)
case emojiPicker(roomID: String, itemID: TimelineItemIdentifier)
case emojiPicker(roomID: String, itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
case mapNavigator(roomID: String)
case roomMemberDetails(roomID: String, member: HashableRoomMemberWrapper)
case messageForwarding(roomID: String, itemID: TimelineItemIdentifier)
Expand All @@ -659,7 +659,7 @@ private extension RoomFlowCoordinator {
case presentMediaUploadPreview(fileURL: URL)
case dismissMediaUploadPreview

case presentEmojiPicker(itemID: TimelineItemIdentifier)
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
case dismissEmojiPicker

case presentMapNavigator(interactionMode: StaticLocationInteractionMode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import SwiftUI
struct EmojiPickerScreenCoordinatorParameters {
let emojiProvider: EmojiProviderProtocol
let itemID: TimelineItemIdentifier
let selectedEmojis: Set<String>
}

enum EmojiPickerScreenCoordinatorAction {
Expand Down Expand Up @@ -52,6 +53,6 @@ final class EmojiPickerScreenCoordinator: CoordinatorProtocol {
}

func toPresentable() -> AnyView {
AnyView(EmojiPickerScreen(context: viewModel.context))
AnyView(EmojiPickerScreen(context: viewModel.context, selectedEmojis: parameters.selectedEmojis))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import SwiftUI
struct EmojiPickerScreen: View {
@ObservedObject var context: EmojiPickerScreenViewModel.Context

var selectedEmojis = Set<String>()
@State var searchString = ""
@State private var isSearching = false

Expand All @@ -39,7 +40,10 @@ struct EmojiPickerScreen: View {
context.send(viewAction: .emojiTapped(emoji: emoji))
} label: {
Text(emoji.value)
.padding(9.0)
.font(.compound.headingXL)
.background(Circle()
.foregroundColor(emojiBackgroundColor(for: emoji.value)))
}
}
} header: {
Expand All @@ -65,6 +69,14 @@ struct EmojiPickerScreen: View {
}
}

private func emojiBackgroundColor(for emoji: String) -> Color {
if selectedEmojis.contains(emoji) {
return .compound.bgActionPrimaryRest
} else {
return .clear
}
}

@ToolbarContentBuilder
var toolbar: some ToolbarContent {
ToolbarItem(placement: .cancellationAction) {
Expand Down Expand Up @@ -92,12 +104,12 @@ struct EmojiPickerScreen_Previews: PreviewProvider {
static let viewModel = EmojiPickerScreenViewModel(emojiProvider: EmojiProvider())

static var previews: some View {
EmojiPickerScreen(context: viewModel.context)
EmojiPickerScreen(context: viewModel.context, selectedEmojis: ["😀", "😄"])
.previewDisplayName("Screen")

Text("Timeline view")
.sheet(isPresented: .constant(true)) {
EmojiPickerScreen(context: viewModel.context)
EmojiPickerScreen(context: viewModel.context, selectedEmojis: ["😀", "😄"])
}
.previewDisplayName("Sheet")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ enum RoomScreenCoordinatorAction {
case presentRoomDetails
case presentLocationPicker
case presentLocationViewer(body: String, geoURI: GeoURI, description: String?)
case presentEmojiPicker(itemID: TimelineItemIdentifier)
case presentEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
case presentRoomMemberDetails(member: RoomMemberProxyProtocol)
case presentMessageForwarding(itemID: TimelineItemIdentifier)
}
Expand Down Expand Up @@ -67,8 +67,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
switch action {
case .displayRoomDetails:
actionsSubject.send(.presentRoomDetails)
case .displayEmojiPicker(let itemID):
actionsSubject.send(.presentEmojiPicker(itemID: itemID))
case .displayEmojiPicker(let itemID, let selectedEmojis):
actionsSubject.send(.presentEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis))
case .displayReportContent(let itemID, let senderID):
actionsSubject.send(.presentReportContent(itemID: itemID, senderID: senderID))
case .displayCameraPicker:
Expand Down
2 changes: 1 addition & 1 deletion ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import OrderedCollections

enum RoomScreenViewModelAction {
case displayRoomDetails
case displayEmojiPicker(itemID: TimelineItemIdentifier)
case displayEmojiPicker(itemID: TimelineItemIdentifier, selectedEmojis: Set<String>)
case displayReportContent(itemID: TimelineItemIdentifier, senderID: String)
case displayCameraPicker
case displayMediaPicker
Expand Down
9 changes: 7 additions & 2 deletions ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -728,8 +728,13 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
// MARK: - Reactions

private func showEmojiPicker(for itemID: TimelineItemIdentifier) {
guard let item = state.timelineViewState.itemsDictionary[itemID.timelineID], item.isReactable else { return }
callback?(.displayEmojiPicker(itemID: itemID))
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }),
timelineItem.isReactable,
let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else {
return
}
let selectedEmojis = Set(eventTimelineItem.properties.reactions.compactMap { $0.isHighlighted ? $0.key : nil })
callback?(.displayEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis))
}

private func showReactionSummary(for itemID: TimelineItemIdentifier, selectedKey: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import SwiftUI
struct TimelineItemBubbledStylerView<Content: View>: View {
@EnvironmentObject private var context: RoomScreenViewModel.Context
@Environment(\.timelineGroupStyle) private var timelineGroupStyle
@Environment(\.layoutDirection) var layoutDirection: LayoutDirection

let timelineItem: EventBasedTimelineItemProtocol
@ViewBuilder let content: () -> Content
Expand All @@ -41,11 +40,6 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
return 8
}

var reactionsLayoutDirection: LayoutDirection {
guard timelineItem.isOutgoing else { return layoutDirection }
return layoutDirection == .leftToRight ? .rightToLeft : .leftToRight
}

var body: some View {
ZStack(alignment: .trailingFirstTextBaseline) {
VStack(alignment: alignment, spacing: -12) {
Expand Down Expand Up @@ -109,8 +103,8 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
if !timelineItem.properties.reactions.isEmpty {
TimelineReactionsView(itemID: timelineItem.id,
reactions: timelineItem.properties.reactions,
isLayoutRTL: timelineItem.isOutgoing,
collapsed: context.reactionsCollapsedBinding(for: timelineItem.id))
.environment(\.layoutDirection, reactionsLayoutDirection)
// Workaround to stop the message long press stealing the touch from the reaction buttons
.onTapGesture { }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ struct TimelineReactionsView: View {
private let feedbackGenerator = UIImpactFeedbackGenerator(style: .heavy)
@EnvironmentObject private var context: RoomScreenViewModel.Context
@Environment(\.layoutDirection) private var layoutDirection: LayoutDirection
@Namespace private var animation

let itemID: TimelineItemIdentifier
let reactions: [AggregatedReaction]
var isLayoutRTL = false
@Binding var collapsed: Bool

var reactionsLayoutDirection: LayoutDirection {
guard isLayoutRTL else { return layoutDirection }
return layoutDirection == .leftToRight ? .rightToLeft : .leftToRight
}

var body: some View {
CollapsibleReactionLayout(itemSpacing: 4, rowSpacing: 4, collapsed: collapsed, rowsBeforeCollapsible: 2) {
Expand All @@ -38,6 +43,7 @@ struct TimelineReactionsView: View {
context.send(viewAction: .reactionSummary(itemID: itemID, key: key))
}
.reactionLayoutItem(.reaction)
.environment(\.layoutDirection, layoutDirection)
}
Button {
collapsed.toggle()
Expand All @@ -46,13 +52,15 @@ struct TimelineReactionsView: View {
.transaction { $0.animation = nil }
}
.reactionLayoutItem(.expandCollapse)
.environment(\.layoutDirection, layoutDirection)
Button {
context.send(viewAction: .displayEmojiPicker(itemID: itemID))
} label: {
TimelineReactionAddMoreButtonLabel()
}
.reactionLayoutItem(.addMore)
}
.environment(\.layoutDirection, reactionsLayoutDirection)
.animation(.easeInOut(duration: 0.1), value: reactions)
.padding(.leading, 4)
}
Expand Down Expand Up @@ -86,10 +94,12 @@ struct TimelineReactionButtonLabel<Content: View>: View {

struct TimelineCollapseButtonLabel: View {
var collapsed: Bool
@ScaledMetric(relativeTo: .subheadline) private var lineHeight = 20

var body: some View {
TimelineReactionButtonLabel {
Text(collapsed ? L10n.screenRoomReactionsShowMore : L10n.screenRoomReactionsShowLess)
.frame(height: lineHeight, alignment: .center)
.padding(.vertical, 6)
.padding(.horizontal, 12)
.font(.compound.bodyMD)
Expand All @@ -102,6 +112,7 @@ struct TimelineReactionButton: View {
let reaction: AggregatedReaction
let toggleReaction: (String) -> Void
let showReactionSummary: (String) -> Void
@ScaledMetric(relativeTo: .subheadline) private var lineHeight = 20

var body: some View {
label
Expand All @@ -116,14 +127,18 @@ struct TimelineReactionButton: View {
var label: some View {
TimelineReactionButtonLabel(isHighlighted: reaction.isHighlighted) {
HStack(spacing: 4) {
// Designs have bodyMD for the key but practically this makes
// emojis too big. bodySM gives a more appropriate size when compared
// to the count text and the lineHeight/padding in the designs.
Text(reaction.displayKey)
.font(.compound.bodyMD)
.font(.compound.bodySM)
if reaction.count > 1 {
Text(String(reaction.count))
.font(.compound.bodyMD)
.foregroundColor(textColor)
}
}
.frame(height: lineHeight, alignment: .center)
.padding(.vertical, 6)
.padding(.horizontal, 12)
}
Expand Down Expand Up @@ -157,16 +172,16 @@ struct TimelineReactionViewPreviewsContainer: View {

var body: some View {
VStack {
TimelineReactionsView(itemID: .init(timelineID: "1"), reactions: [
AggregatedReaction.mockReactionWithLongText,
AggregatedReaction.mockReactionWithLongTextRTL
], collapsed: .constant(true))
TimelineReactionsView(itemID: .init(timelineID: "1"),
reactions: [AggregatedReaction.mockReactionWithLongText,
AggregatedReaction.mockReactionWithLongTextRTL],
collapsed: .constant(true))
Divider()
TimelineReactionsView(itemID: .init(timelineID: "2"), reactions: Array(AggregatedReaction.mockReactions.prefix(3)), collapsed: .constant(true))
Divider()
TimelineReactionsView(itemID: .init(timelineID: "3"), reactions: AggregatedReaction.mockReactions, collapsed: $collapseState1)
Divider()
TimelineReactionsView(itemID: .init(timelineID: "4"), reactions: AggregatedReaction.mockReactions, collapsed: $collapseState2)
.environment(\.layoutDirection, .rightToLeft)
TimelineReactionsView(itemID: .init(timelineID: "4"), reactions: AggregatedReaction.mockReactions, isLayoutRTL: true, collapsed: $collapseState2)
}
.background(Color.red)
.frame(maxWidth: 250, alignment: .leading)
Expand Down
12 changes: 8 additions & 4 deletions ElementX/Sources/Screens/RoomScreen/View/TimelineItemMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ extension RoomTimelineItemProtocol {
public struct TimelineItemMenu: View {
@EnvironmentObject private var context: RoomScreenViewModel.Context
@Environment(\.dismiss) private var dismiss
@ScaledMetric private var addMoreButtonIconSize = 24

let item: EventBasedTimelineItemProtocol
let actions: TimelineItemMenuActions
Expand Down Expand Up @@ -209,8 +210,12 @@ public struct TimelineItemMenu: View {
context.send(viewAction: .displayEmojiPicker(itemID: item.id))
}
} label: {
Image(systemName: "plus.circle")
.font(.compound.headingLG)
Image(asset: Asset.Images.timelineReactionAddMore)
.resizable()
.frame(width: addMoreButtonIconSize, height: addMoreButtonIconSize)
.frame(maxHeight: .infinity, alignment: .center)
.foregroundColor(.compound.iconSecondary)
.padding(10)
}
}
.padding(.horizontal)
Expand All @@ -224,11 +229,10 @@ public struct TimelineItemMenu: View {
context.send(viewAction: .toggleReaction(key: emoji, itemID: item.id))
} label: {
Text(emoji)
.padding(8.0)
.padding(8)
.font(.compound.headingLG)
.background(Circle()
.foregroundColor(reactionBackgroundColor(for: emoji)))

Spacer()
}
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 686fee6

Please sign in to comment.