Фикс клавиатуры, скругления input, iOS 26 layout, доставка сообщений и синхронизация
This commit is contained in:
@@ -50,8 +50,15 @@ struct ChatRowView: View {
|
||||
|
||||
// MARK: - Avatar
|
||||
|
||||
private extension ChatRowView {
|
||||
var avatarSection: some View {
|
||||
/// Observation-isolated: reads `AvatarRepository.avatarVersion` in its own
|
||||
/// scope so only the avatar re-renders when opponent avatar changes — not the
|
||||
/// entire ChatRowView (title, message preview, badge, etc.).
|
||||
private struct ChatRowAvatar: View {
|
||||
let dialog: Dialog
|
||||
|
||||
var body: some View {
|
||||
// Establish @Observable tracking — re-renders this view on avatar save/remove.
|
||||
let _ = AvatarRepository.shared.avatarVersion
|
||||
AvatarView(
|
||||
initials: dialog.initials,
|
||||
colorIndex: dialog.avatarColorIndex,
|
||||
@@ -63,6 +70,12 @@ private extension ChatRowView {
|
||||
}
|
||||
}
|
||||
|
||||
private extension ChatRowView {
|
||||
var avatarSection: some View {
|
||||
ChatRowAvatar(dialog: dialog)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Content Section
|
||||
// Figma "Contents": flex-col, h-full, items-start, justify-center, pb-px
|
||||
// └─ "Title and Trailing Accessories": flex-1, gap-6, items-center
|
||||
@@ -209,22 +222,24 @@ private extension ChatRowView {
|
||||
|
||||
@ViewBuilder
|
||||
var deliveryIcon: some View {
|
||||
switch dialog.lastMessageDelivered {
|
||||
case .waiting:
|
||||
// Timer isolated to sub-view — only .waiting rows create a timer.
|
||||
DeliveryWaitingIcon(sentTimestamp: dialog.lastMessageTimestamp)
|
||||
case .delivered:
|
||||
SingleCheckmarkShape()
|
||||
.fill(RosettaColors.Adaptive.textSecondary)
|
||||
.frame(width: 14, height: 10.3)
|
||||
case .read:
|
||||
if dialog.lastMessageDelivered == .delivered && dialog.lastMessageRead {
|
||||
DoubleCheckmarkShape()
|
||||
.fill(RosettaColors.figmaBlue)
|
||||
.frame(width: 17, height: 9.3)
|
||||
case .error:
|
||||
Image(systemName: "exclamationmark.circle.fill")
|
||||
.font(.system(size: 14))
|
||||
.foregroundStyle(RosettaColors.error)
|
||||
} else {
|
||||
switch dialog.lastMessageDelivered {
|
||||
case .waiting:
|
||||
// Timer isolated to sub-view — only .waiting rows create a timer.
|
||||
DeliveryWaitingIcon(sentTimestamp: dialog.lastMessageTimestamp)
|
||||
case .delivered:
|
||||
SingleCheckmarkShape()
|
||||
.fill(RosettaColors.Adaptive.textSecondary)
|
||||
.frame(width: 14, height: 10.3)
|
||||
case .error:
|
||||
Image(systemName: "exclamationmark.circle.fill")
|
||||
.font(.system(size: 14))
|
||||
.foregroundStyle(RosettaColors.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +356,8 @@ private extension ChatRowView {
|
||||
unreadCount: 3, isOnline: true, lastSeen: 0,
|
||||
verified: 1, iHaveSent: true,
|
||||
isPinned: false, isMuted: false,
|
||||
lastMessageFromMe: true, lastMessageDelivered: .read
|
||||
lastMessageFromMe: true, lastMessageDelivered: .delivered,
|
||||
lastMessageRead: true
|
||||
)
|
||||
|
||||
VStack(spacing: 0) {
|
||||
|
||||
Reference in New Issue
Block a user