mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Reactions - Design review tweaks (#1417)
* Design review tweaks - truncate reactions as per spec - add haptic feedback on reacting - Remove all collapse/expand animations on reactions - tweak reaction and summary padding - Fix alignment of time on reaction summary view - Made sure reaction summary button in horizontal scroller is on screen on appear - update screenshots * Update TimelineReactionsView.swift * Remove dark add more button and check long rtl reactions * Set colour of templated add more button * Fix padding and only inset from the bubble on the leading side as per designs - Fix padding - Only inset from the bubble on the leading side as per designs * Update screenshots * Fix line length warning.
This commit is contained in:
@@ -21,8 +21,6 @@ struct TimelineItemPlainStylerView<Content: View>: View {
|
||||
@EnvironmentObject private var context: RoomScreenViewModel.Context
|
||||
@Environment(\.timelineGroupStyle) private var timelineGroupStyle
|
||||
|
||||
private let feedbackGenerator = UIImpactFeedbackGenerator(style: .heavy)
|
||||
|
||||
let timelineItem: EventBasedTimelineItemProtocol
|
||||
@ViewBuilder let content: () -> Content
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ struct ReactionsSummaryView: View {
|
||||
private var reactionButtons: some View {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
ScrollViewReader { scrollView in
|
||||
HStack {
|
||||
HStack(spacing: 8) {
|
||||
ForEach(reactions, id: \.self) { reaction in
|
||||
ReactionSummaryButton(reaction: reaction, highlighted: selectedReactionKey == reaction.key) { key in
|
||||
selectedReactionKey = key
|
||||
@@ -50,7 +50,9 @@ struct ReactionsSummaryView: View {
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.onAppear {
|
||||
scrollView.scrollTo(selectedReactionKey, anchor: .leading)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
||||
scrollView.scrollTo(selectedReactionKey)
|
||||
}
|
||||
}
|
||||
.onChange(of: selectedReactionKey) { _ in
|
||||
scrollView.scrollTo(selectedReactionKey)
|
||||
@@ -91,7 +93,7 @@ private struct ReactionSummaryButton: View {
|
||||
|
||||
var label: some View {
|
||||
HStack(spacing: 4) {
|
||||
Text(reaction.key)
|
||||
Text(reaction.displayKey)
|
||||
.font(.compound.headingSM)
|
||||
if reaction.count > 1 {
|
||||
Text(String(reaction.count))
|
||||
@@ -99,8 +101,8 @@ private struct ReactionSummaryButton: View {
|
||||
.foregroundColor(highlighted ? Color.compound.textOnSolidPrimary : Color.compound.textSecondary)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 6)
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 8)
|
||||
.padding(.horizontal, 12)
|
||||
.background(highlighted ? Color.compound.bgActionPrimaryRest : .clear, in: Capsule())
|
||||
.accessibilityElement(children: .combine)
|
||||
}
|
||||
@@ -124,19 +126,20 @@ private struct ReactionSummarySenderView: View {
|
||||
imageProvider: imageProvider)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
Text(displayName)
|
||||
.font(.compound.bodyMDSemibold)
|
||||
HStack {
|
||||
Text(displayName)
|
||||
.font(.compound.bodyMDSemibold)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Text(sender.timestamp.formattedMinimal())
|
||||
.font(.compound.bodyXS)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
}
|
||||
Text(sender.senderID)
|
||||
.font(.compound.bodySM)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Text(sender.timestamp.formattedMinimal())
|
||||
.font(.compound.bodyXS)
|
||||
.foregroundColor(.compound.textSecondary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
}
|
||||
|
||||
+16
-14
@@ -17,11 +17,9 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TimelineReactionsView: View {
|
||||
/// We use a coordinate space for measuring the reactions within their container.
|
||||
/// For some reason when using .local the origin of reactions always shown as (0, 0)
|
||||
private static let flowCoordinateSpace = "flowCoordinateSpace"
|
||||
private static let horizontalSpacing: CGFloat = 4
|
||||
private static let verticalSpacing: CGFloat = 4
|
||||
private let feedbackGenerator = UIImpactFeedbackGenerator(style: .heavy)
|
||||
@EnvironmentObject private var context: RoomScreenViewModel.Context
|
||||
@Environment(\.layoutDirection) private var layoutDirection: LayoutDirection
|
||||
@Namespace private var animation
|
||||
@@ -34,6 +32,7 @@ struct TimelineReactionsView: View {
|
||||
CollapsibleReactionLayout(itemSpacing: 4, rowSpacing: 4, collapsed: collapsed, rowsBeforeCollapsible: 2) {
|
||||
ForEach(reactions, id: \.self) { reaction in
|
||||
TimelineReactionButton(reaction: reaction) { key in
|
||||
feedbackGenerator.impactOccurred()
|
||||
context.send(viewAction: .toggleReaction(key: key, itemID: itemID))
|
||||
} showReactionSummary: { key in
|
||||
context.send(viewAction: .reactionSummary(itemID: itemID, key: key))
|
||||
@@ -44,18 +43,18 @@ struct TimelineReactionsView: View {
|
||||
collapsed.toggle()
|
||||
} label: {
|
||||
TimelineCollapseButtonLabel(collapsed: collapsed)
|
||||
.transaction { $0.animation = nil }
|
||||
}
|
||||
.reactionLayoutItem(.expandCollapse)
|
||||
.animation(.easeOut, value: collapsed)
|
||||
Button {
|
||||
context.send(viewAction: .displayEmojiPicker(itemID: itemID))
|
||||
} label: {
|
||||
TimelineReactionAddMoreButtonLabel()
|
||||
}
|
||||
.animation(.easeOut, value: collapsed)
|
||||
.reactionLayoutItem(.addMore)
|
||||
}
|
||||
.coordinateSpace(name: Self.flowCoordinateSpace)
|
||||
.animation(.easeInOut(duration: 0.1), value: reactions)
|
||||
.padding(.leading, 4)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +91,7 @@ struct TimelineCollapseButtonLabel: View {
|
||||
TimelineReactionButtonLabel {
|
||||
Text(collapsed ? L10n.screenRoomReactionsShowMore : L10n.screenRoomReactionsShowLess)
|
||||
.padding(.vertical, 6)
|
||||
.padding(.horizontal, 8)
|
||||
.layoutPriority(1)
|
||||
.drawingGroup()
|
||||
.padding(.horizontal, 12)
|
||||
.font(.compound.bodyMD)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
}
|
||||
@@ -119,7 +116,7 @@ struct TimelineReactionButton: View {
|
||||
var label: some View {
|
||||
TimelineReactionButtonLabel(isHighlighted: reaction.isHighlighted) {
|
||||
HStack(spacing: 4) {
|
||||
Text(reaction.key)
|
||||
Text(reaction.displayKey)
|
||||
.font(.compound.bodyMD)
|
||||
if reaction.count > 1 {
|
||||
Text(String(reaction.count))
|
||||
@@ -128,7 +125,7 @@ struct TimelineReactionButton: View {
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 6)
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.horizontal, 12)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +146,7 @@ struct TimelineReactionAddMoreButtonLabel: View {
|
||||
// matches the height of the text based buttons.
|
||||
.padding(.horizontal, 10)
|
||||
.frame(maxHeight: .infinity, alignment: .center)
|
||||
.foregroundColor(.compound.iconSecondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,11 +157,15 @@ struct TimelineReactionViewPreviewsContainer: View {
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
TimelineReactionsView(itemID: .init(timelineID: "1"), reactions: Array(AggregatedReaction.mockReactions.prefix(3)), collapsed: .constant(true))
|
||||
TimelineReactionsView(itemID: .init(timelineID: "1"), reactions: [
|
||||
AggregatedReaction.mockReactionWithLongText,
|
||||
AggregatedReaction.mockReactionWithLongTextRTL
|
||||
], collapsed: .constant(true))
|
||||
TimelineReactionsView(itemID: .init(timelineID: "2"), reactions: Array(AggregatedReaction.mockReactions.prefix(3)), collapsed: .constant(true))
|
||||
Divider()
|
||||
TimelineReactionsView(itemID: .init(timelineID: "2"), reactions: AggregatedReaction.mockReactions, collapsed: $collapseState1)
|
||||
TimelineReactionsView(itemID: .init(timelineID: "3"), reactions: AggregatedReaction.mockReactions, collapsed: $collapseState1)
|
||||
Divider()
|
||||
TimelineReactionsView(itemID: .init(timelineID: "3"), reactions: AggregatedReaction.mockReactions, collapsed: $collapseState2)
|
||||
TimelineReactionsView(itemID: .init(timelineID: "4"), reactions: AggregatedReaction.mockReactions, collapsed: $collapseState2)
|
||||
.environment(\.layoutDirection, .rightToLeft)
|
||||
}
|
||||
.background(Color.red)
|
||||
|
||||
@@ -124,6 +124,7 @@ public struct TimelineItemMenu: View {
|
||||
|
||||
let item: EventBasedTimelineItemProtocol
|
||||
let actions: TimelineItemMenuActions
|
||||
private let feedbackGenerator = UIImpactFeedbackGenerator(style: .heavy)
|
||||
|
||||
public var body: some View {
|
||||
VStack {
|
||||
@@ -218,6 +219,7 @@ public struct TimelineItemMenu: View {
|
||||
|
||||
private func reactionButton(for emoji: String) -> some View {
|
||||
Button {
|
||||
feedbackGenerator.impactOccurred()
|
||||
dismiss()
|
||||
context.send(viewAction: .toggleReaction(key: emoji, itemID: item.id))
|
||||
} label: {
|
||||
|
||||
Reference in New Issue
Block a user