mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Highlight selected emoji in picker, correct add more button in menu, 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
This commit is contained in:
@@ -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)
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
@@ -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 { }
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -38,6 +43,7 @@ struct TimelineReactionsView: View {
|
||||
context.send(viewAction: .reactionSummary(itemID: itemID, key: key))
|
||||
}
|
||||
.reactionLayoutItem(.reaction)
|
||||
.environment(\.layoutDirection, layoutDirection)
|
||||
}
|
||||
Button {
|
||||
collapsed.toggle()
|
||||
@@ -46,6 +52,7 @@ struct TimelineReactionsView: View {
|
||||
.transaction { $0.animation = nil }
|
||||
}
|
||||
.reactionLayoutItem(.expandCollapse)
|
||||
.environment(\.layoutDirection, layoutDirection)
|
||||
Button {
|
||||
context.send(viewAction: .displayEmojiPicker(itemID: itemID))
|
||||
} label: {
|
||||
@@ -53,6 +60,7 @@ struct TimelineReactionsView: View {
|
||||
}
|
||||
.reactionLayoutItem(.addMore)
|
||||
}
|
||||
.environment(\.layoutDirection, reactionsLayoutDirection)
|
||||
.animation(.easeInOut(duration: 0.1), value: reactions)
|
||||
.padding(.leading, 4)
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user