import Combine import Foundation import SwiftUI struct ConversationScreen: View { @Environment(\.router) var router @StateObject var chatWrapper: WrapperChat @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: chatWrapper.chatTitle), rightButton: .init( image: Image(systemName: "gear"), action: { router.showScreen(.push) { _ in ConversationSettingsScreen() .environmentObject(chatWrapper) .navigationBarHidden(true) } } ) ) if chatWrapper.mamRequestInProgress { ProgressView() .progressViewStyle(.circular) .tint(.Material.Shape.separator) .padding(.top, 8) } // Msg list if !chatWrapper.messages.isEmpty { ScrollViewReader { proxy in ScrollView { LazyVStack(spacing: 0) { ForEach(chatWrapper.messages) { message in ConversationMessageRow(message: message) .id(message.id) .flip() .onAppear { if message.id == chatWrapper.messages.first?.id { firstIsVisible = true autoScroll = true } if message.id == chatWrapper.messages.last?.id { chatWrapper.requestMAM() } } .onDisappear { if message.id == chatWrapper.messages.first?.id { firstIsVisible = false autoScroll = false } } } } } .flip() .scrollDismissesKeyboard(.immediately) .onChange(of: autoScroll) { new in print(proxy) if new, !firstIsVisible { withAnimation { proxy.scrollTo(chatWrapper.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) } } } } } .safeAreaInset(edge: .bottom, spacing: 0) { ConversationTextInput(autoScroll: $autoScroll) .environmentObject(chatWrapper) } .onLoad { if chatWrapper.messages.isEmpty { chatWrapper.requestMAM() } } } }