import Combine import Foundation import Martin import SwiftUI struct ConversationScreen: View { @Environment(\.router) var router @StateObject var messagesStore: MessagesStore @StateObject var attachments: AttachmentsStore @State private var autoScroll = true @State private var firstIsVisible = true var body: some View { ZStack { // Background color Color.Material.Background.light .ignoresSafeArea() // Content VStack(spacing: 0) { // Header SharedNavigationBar( leftButton: .init( image: Image(systemName: "chevron.left"), action: { router.dismissScreen() } ), centerText: .init(text: centerText(), action: { router.showScreen(.fullScreenCover) { _ in ConversationSettingsScreen() } }) ) // Msg list let messages = messagesStore.messages if !messages.isEmpty { ScrollViewReader { proxy in ScrollView { LazyVStack(spacing: 0) { ForEach(messages) { message in ConversationMessageRow(message: message) .id(message.id) .flip() .onAppear { if message.id == messages.first?.id { firstIsVisible = true autoScroll = true } messagesStore.scrolledMessage(message.id) } .onDisappear { if message.id == messages.first?.id { firstIsVisible = false autoScroll = false } } } } } .flip() .scrollDismissesKeyboard(.immediately) .onChange(of: autoScroll) { new in if new, !firstIsVisible { withAnimation { proxy.scrollTo(messages.first?.id, anchor: .top) } } } } } else { Spacer() } } .onTapGesture { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } // Jump to last button if !autoScroll { VStack { Spacer() HStack { Spacer() Button { autoScroll = true } label: { ZStack { Circle() .fill(Color.Material.Shape.white) Image(systemName: "arrow.down") .foregroundColor(.Material.Elements.active) } .frame(width: 40, height: 40) .shadow(color: .black.opacity(0.2), radius: 4) .padding(.trailing, 8) .padding(.bottom, 8) } } } } } .environmentObject(messagesStore) .environmentObject(attachments) .safeAreaInset(edge: .bottom, spacing: 0) { ConversationTextInput(autoScroll: $autoScroll) .environmentObject(messagesStore) .environmentObject(attachments) } } private func centerText() -> String { let name = messagesStore.roster.name ?? JID(messagesStore.roster.contactBareJid).localPart if let name = name { return name } else { return L10n.Conversation.title } } }