Доставка сообщений при потере сети, кэш фото при отправке, FPS клавиатуры, свайп фото, badge tab bar, release notes, sync unread fix

This commit is contained in:
2026-03-20 16:51:57 +05:00
parent 44652e0d97
commit e75c6bac12
20 changed files with 427 additions and 323 deletions

View File

@@ -377,6 +377,9 @@ private struct ToolbarTitleView: View {
.foregroundStyle(RosettaColors.Adaptive.text)
.contentTransition(.numericText())
.animation(.easeInOut(duration: 0.25), value: state)
.onTapGesture {
NotificationCenter.default.post(name: .chatListScrollToTop, object: nil)
}
} else {
ToolbarStatusLabel(title: "Connecting...")
}
@@ -589,7 +592,10 @@ private struct ChatListDialogContent: View {
// MARK: - Dialog List
private static let topAnchorId = "chatlist_top"
private func dialogList(pinned: [Dialog], unpinned: [Dialog], requestsCount: Int) -> some View {
ScrollViewReader { scrollProxy in
List {
if viewModel.isLoading {
ForEach(0..<8, id: \.self) { _ in
@@ -630,6 +636,17 @@ private struct ChatListDialogContent: View {
.scrollContentBackground(.hidden)
.scrollDismissesKeyboard(.immediately)
.scrollIndicators(.hidden)
// Scroll-to-top: tap "Chats" in toolbar
.onReceive(NotificationCenter.default.publisher(for: .chatListScrollToTop)) { _ in
// Scroll to first dialog ID (pinned or unpinned)
let firstId = pinned.first?.id ?? unpinned.first?.id
if let firstId {
withAnimation(.easeOut(duration: 0.3)) {
scrollProxy.scrollTo(firstId, anchor: .top)
}
}
}
} // ScrollViewReader
}
private func chatRow(_ dialog: Dialog, isFirst: Bool = false) -> some View {