From fbd49534053da7e11dad852abf1c5a428e5f5670 Mon Sep 17 00:00:00 2001 From: Valentin Perignon Date: Fri, 7 Jul 2023 10:33:55 +0200 Subject: [PATCH 1/2] fix(ComposeMessageView): scroll follows editor's height --- Mail/Helpers/RichTextEditor.swift | 12 ++++++------ .../New Message/ComposeMessageBodyView.swift | 6 +++--- Mail/Views/New Message/ComposeMessageView.swift | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Mail/Helpers/RichTextEditor.swift b/Mail/Helpers/RichTextEditor.swift index 6cc23662d..337dffb70 100644 --- a/Mail/Helpers/RichTextEditor.swift +++ b/Mail/Helpers/RichTextEditor.swift @@ -28,7 +28,7 @@ import WebKit struct RichTextEditor: UIViewRepresentable { typealias UIViewType = MailEditorView - @ObservedObject var model: RichTextEditorModel + @Binding var model: RichTextEditorModel @Binding var body: String @Binding var isShowingCamera: Bool @Binding var isShowingFileSelection: Bool @@ -37,12 +37,12 @@ struct RichTextEditor: UIViewRepresentable { let blockRemoteContent: Bool var alert: ObservedObject.Wrapper - init(model: RichTextEditorModel, body: Binding, + init(model: Binding, body: Binding, alert: ObservedObject.Wrapper, isShowingCamera: Binding, isShowingFileSelection: Binding, isShowingPhotoLibrary: Binding, becomeFirstResponder: Binding, blockRemoteContent: Bool) { - _model = ObservedObject(wrappedValue: model) + _model = model _body = body self.alert = alert _isShowingCamera = isShowingCamera @@ -146,9 +146,9 @@ extension SQTextEditorView { } } -class RichTextEditorModel: ObservableObject { - @Published var cursorPosition: CGFloat = 0 - @Published var height: CGFloat = 0 +struct RichTextEditorModel { + var cursorPosition: CGFloat = 0 + var height: CGFloat = 0 } class MailEditorView: SQTextEditorView { diff --git a/Mail/Views/New Message/ComposeMessageBodyView.swift b/Mail/Views/New Message/ComposeMessageBodyView.swift index d88632811..6acb4b25e 100644 --- a/Mail/Views/New Message/ComposeMessageBodyView.swift +++ b/Mail/Views/New Message/ComposeMessageBodyView.swift @@ -26,10 +26,9 @@ struct ComposeMessageBodyView: View { @State private var isShowingFileSelection = false @State private var isShowingPhotoLibrary = false - @StateObject private var editorModel = RichTextEditorModel() - @ObservedRealmObject var draft: Draft + @Binding var editorModel: RichTextEditorModel @Binding var isLoadingContent: Bool @Binding var editorFocus: Bool @@ -48,7 +47,7 @@ struct ComposeMessageBodyView: View { AttachmentsHeaderView(attachmentsManager: attachmentsManager) RichTextEditor( - model: editorModel, + model: $editorModel, body: $draft.body, alert: $alert, isShowingCamera: $isShowingCamera, @@ -87,6 +86,7 @@ struct ComposeMessageBodyView_Previews: PreviewProvider { @Environment(\.dismiss) var dismiss ComposeMessageBodyView(draft: Draft(), + editorModel: .constant(RichTextEditorModel()), isLoadingContent: .constant(false), editorFocus: .constant(false), attachmentsManager: AttachmentsManager( diff --git a/Mail/Views/New Message/ComposeMessageView.swift b/Mail/Views/New Message/ComposeMessageView.swift index 3c3d34423..21b147cfb 100644 --- a/Mail/Views/New Message/ComposeMessageView.swift +++ b/Mail/Views/New Message/ComposeMessageView.swift @@ -68,6 +68,9 @@ struct ComposeMessageView: View { @State private var autocompletionType: ComposeViewFieldType? @State private var editorFocus = false + @State private var editorModel = RichTextEditorModel() + @State private var scrollView: UIScrollView? + @StateObject private var attachmentsManager: AttachmentsManager @StateObject private var alert = NewMessageAlert() @@ -144,6 +147,7 @@ struct ComposeMessageView: View { if autocompletionType == nil && !isLoadingContent { ComposeMessageBodyView( draft: draft, + editorModel: $editorModel, isLoadingContent: $isLoadingContent, editorFocus: $editorFocus, attachmentsManager: attachmentsManager, @@ -184,8 +188,20 @@ struct ComposeMessageView: View { } } .introspectScrollView { scrollView in + guard self.scrollView != scrollView else { return } + self.scrollView = scrollView scrollView.keyboardDismissMode = .interactive } + .onChange(of: editorModel.height) { _ in + guard let scrollView else { return } + + let fullSize = scrollView.contentSize.height + let realPosition = (fullSize - editorModel.height) + editorModel.cursorPosition + + guard realPosition >= 0 else { return } + let rect = CGRect(x: 0, y: realPosition, width: 1, height: 1) + scrollView.scrollRectToVisible(rect, animated: true) + } .navigationTitle(MailResourcesStrings.Localizable.buttonNewMessage) .navigationBarTitleDisplayMode(.inline) .toolbar { From 213b715b44487ce677d7f750564992c1530eb84f Mon Sep 17 00:00:00 2001 From: Valentin Perignon Date: Fri, 7 Jul 2023 10:34:45 +0200 Subject: [PATCH 2/2] feat(MessageComposeView): Scroll to top when autocompletion is enabled --- Mail/Views/New Message/ComposeMessageView.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Mail/Views/New Message/ComposeMessageView.swift b/Mail/Views/New Message/ComposeMessageView.swift index 21b147cfb..09391df38 100644 --- a/Mail/Views/New Message/ComposeMessageView.swift +++ b/Mail/Views/New Message/ComposeMessageView.swift @@ -202,6 +202,12 @@ struct ComposeMessageView: View { let rect = CGRect(x: 0, y: realPosition, width: 1, height: 1) scrollView.scrollRectToVisible(rect, animated: true) } + .onChange(of: autocompletionType) { newValue in + guard newValue != nil else { return } + + let rectTop = CGRect(x: 0, y: 0, width: 1, height: 1) + scrollView?.scrollRectToVisible(rectTop, animated: true) + } .navigationTitle(MailResourcesStrings.Localizable.buttonNewMessage) .navigationBarTitleDisplayMode(.inline) .toolbar {