mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-29 14:47:52 +00:00
simplify timestamp logic; remove shape
This commit is contained in:
@@ -719,39 +719,21 @@ struct ChatView: View {
|
||||
|
||||
struct TimeSeparation {
|
||||
let isTimestampShown: Bool
|
||||
let isDateShown: Bool // TODO: Implement UI to show date
|
||||
let isGapLarge: Bool
|
||||
|
||||
init(for chatItem: ChatItem, at index: Int?) {
|
||||
let im = ItemsModel.shared
|
||||
if let index, index > 0 && !im.reversedChatItems.isEmpty {
|
||||
let nextItem = im.reversedChatItems[index - 1]
|
||||
isTimestampShown = nextItem.chatDir != chatItem.chatDir ||
|
||||
Self.componentsToMinute(nextItem.meta.createdAt) != Self.componentsToMinute(chatItem.meta.createdAt)
|
||||
isDateShown =
|
||||
Self.componentsToDate(nextItem.meta.createdAt) != Self.componentsToDate(chatItem.meta.createdAt)
|
||||
isGapLarge = nextItem.chatDir != chatItem.chatDir ||
|
||||
nextItem.meta.createdAt.timeIntervalSince(chatItem.meta.createdAt) > 30
|
||||
isTimestampShown = isGapLarge ||
|
||||
formatTimestampText(chatItem.meta.createdAt) != formatTimestampText(nextItem.meta.createdAt)
|
||||
} else {
|
||||
isTimestampShown = true
|
||||
isDateShown = false
|
||||
isGapLarge = true
|
||||
}
|
||||
}
|
||||
|
||||
private static func componentsToMinute(_ date: Date) -> DateComponents {
|
||||
Calendar.current.dateComponents(
|
||||
[.year, .month, .day, .hour, .minute],
|
||||
from: date
|
||||
)
|
||||
}
|
||||
|
||||
private static func componentsToDate(_ date: Date) -> DateComponents {
|
||||
Calendar.current.dateComponents(
|
||||
[.year, .month, .day],
|
||||
from: date
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
@@ -934,7 +916,7 @@ struct ChatView: View {
|
||||
allowMenu: $allowMenu
|
||||
)
|
||||
.environment(\.showTimestamp, timeSeparation.isTimestampShown)
|
||||
.modifier(ChatItemClipped(ci, showsTail: timeSeparation.isGapLarge))
|
||||
.modifier(ChatItemClipped(ci))
|
||||
.contextMenu { menu(ci, range, live: composeState.liveMessage != nil) }
|
||||
.accessibilityLabel("")
|
||||
if ci.content.msgContent != nil && (ci.meta.itemDeleted == nil || revealed) && ci.reactions.count > 0 {
|
||||
|
||||
@@ -9,65 +9,54 @@
|
||||
import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
/// Modifier, which provides clipping mask for ``ChatItemWithMenu`` view
|
||||
/// Modifier, which provides clipping mask for ``ChatItemWithMenu`` view
|
||||
/// and it's previews: (drag interaction, context menu, etc.)
|
||||
/// Supports [Dynamic Type](https://developer.apple.com/documentation/uikit/uifont/scaling_fonts_automatically)
|
||||
/// by retaining pill shape, even when ``ChatItem``'s height is less that twice its corner radius
|
||||
struct ChatItemClipped: ViewModifier {
|
||||
|
||||
enum TailEdge {
|
||||
case leading
|
||||
case trailing
|
||||
}
|
||||
|
||||
struct ClipShape: Shape {
|
||||
let maxCornerRadius: Double
|
||||
var tailEdge: TailEdge?
|
||||
|
||||
func path(in rect: CGRect) -> Path {
|
||||
.roundedRectangle(
|
||||
in: rect,
|
||||
radius: maxCornerRadius,
|
||||
bottomLeading: tailEdge == .leading ? 0 : nil,
|
||||
bottomTrailing: tailEdge == .trailing ? 0 : nil
|
||||
Path(
|
||||
roundedRect: rect,
|
||||
cornerRadius: min((rect.height / 2), maxCornerRadius),
|
||||
style: .circular
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
clipShape = ClipShape(
|
||||
maxCornerRadius: 18
|
||||
)
|
||||
}
|
||||
|
||||
init(_ chatItem: ChatItem, showsTail: Bool) {
|
||||
|
||||
init(_ chatItem: ChatItem) {
|
||||
clipShape = ClipShape(
|
||||
maxCornerRadius: {
|
||||
switch chatItem.content {
|
||||
case
|
||||
.sndMsgContent,
|
||||
case
|
||||
.sndMsgContent,
|
||||
.rcvMsgContent,
|
||||
.rcvDecryptionError,
|
||||
.rcvGroupInvitation,
|
||||
.sndGroupInvitation,
|
||||
.sndDeleted,
|
||||
.sndDeleted,
|
||||
.rcvDeleted,
|
||||
.rcvIntegrityError,
|
||||
.sndModerated,
|
||||
.rcvModerated,
|
||||
.sndModerated,
|
||||
.rcvModerated,
|
||||
.rcvBlocked,
|
||||
.invalidJSON: 18
|
||||
default: 8
|
||||
}
|
||||
}(),
|
||||
tailEdge: showsTail
|
||||
? chatItem.chatDir.sent ? .trailing : .leading
|
||||
: nil
|
||||
}()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private let clipShape: ClipShape
|
||||
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.contentShape(.dragPreview, clipShape)
|
||||
@@ -75,50 +64,3 @@ struct ChatItemClipped: ViewModifier {
|
||||
.clipShape(clipShape)
|
||||
}
|
||||
}
|
||||
|
||||
extension Path {
|
||||
static func roundedRectangle(
|
||||
in rect: CGRect,
|
||||
radius: CGFloat,
|
||||
topLeading: CGFloat? = nil,
|
||||
bottomLeading: CGFloat? = nil,
|
||||
bottomTrailing: CGFloat? = nil,
|
||||
topTrailing: CGFloat? = nil
|
||||
) -> Path {
|
||||
let maxRadius = min(rect.width, rect.height) / 2
|
||||
let tl = min(maxRadius, topLeading ?? radius)
|
||||
let bl = min(maxRadius, bottomLeading ?? radius)
|
||||
let bt = min(maxRadius, bottomTrailing ?? radius)
|
||||
let tt = min(maxRadius, topLeading ?? radius)
|
||||
var path = Path()
|
||||
path.addArc(
|
||||
center: CGPoint(x: tl, y: tl),
|
||||
radius: tl,
|
||||
startAngle: .degrees(270),
|
||||
endAngle: .degrees(180),
|
||||
clockwise: true
|
||||
)
|
||||
path.addArc(
|
||||
center: CGPoint(x: bl, y: rect.height - bl),
|
||||
radius: bl,
|
||||
startAngle: .degrees(180),
|
||||
endAngle: .degrees(90),
|
||||
clockwise: true
|
||||
)
|
||||
path.addArc(
|
||||
center: CGPoint(x: rect.width - bt, y: rect.height - bt),
|
||||
radius: bt,
|
||||
startAngle: .degrees(90),
|
||||
endAngle: .degrees(0),
|
||||
clockwise: true
|
||||
)
|
||||
path.addArc(
|
||||
center: CGPoint(x: rect.width - tt, y: tt),
|
||||
radius: tt,
|
||||
startAngle: .degrees(0),
|
||||
endAngle: .degrees(270),
|
||||
clockwise: true
|
||||
)
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2762,7 +2762,7 @@ let msgTimeFormat = Date.FormatStyle.dateTime.hour().minute()
|
||||
let msgDateFormat = Date.FormatStyle.dateTime.day(.twoDigits).month(.twoDigits)
|
||||
|
||||
public func formatTimestampText(_ date: Date) -> Text {
|
||||
return Text(date, format: recent(date) ? msgTimeFormat : msgDateFormat)
|
||||
Text(verbatim: date.formatted(recent(date) ? msgTimeFormat : msgDateFormat))
|
||||
}
|
||||
|
||||
private func recent(_ date: Date) -> Bool {
|
||||
|
||||
Reference in New Issue
Block a user