damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 0f5e1dfb8181124c41a44a054d75b83108ae6281
parent a5cb10ddaa6d48deca2c7b4af095cdeb1ed61f94
Author: William Casarin <jb55@jb55.com>
Date:   Fri,  5 May 2023 16:12:03 -0700

Properly scroll DM view when keyboard is open

Less DM jank!

Changelog-Fixed: Properly scroll DM view when keyboard is open

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 4++++
Adamus/Util/KeyboardVisible.swift | 31+++++++++++++++++++++++++++++++
Mdamus/Views/DMChatView.swift | 84++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
3 files changed, 82 insertions(+), 37 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -141,6 +141,7 @@ 4C75EFB728049D990006080F /* RelayPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75EFB628049D990006080F /* RelayPool.swift */; }; 4C75EFB92804A2740006080F /* EventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75EFB82804A2740006080F /* EventView.swift */; }; 4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C75EFBA2804A34C0006080F /* ProofOfWork.swift */; }; + 4C7D09592A05BEAD00943473 /* KeyboardVisible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7D09582A05BEAD00943473 /* KeyboardVisible.swift */; }; 4C7FF7D52823313F009601DB /* Mentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7FF7D42823313F009601DB /* Mentions.swift */; }; 4C8682872814DE470026224F /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8682862814DE470026224F /* ProfileView.swift */; }; 4C8D00C829DF791C0036AF10 /* CompatibleAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C8D00C729DF791C0036AF10 /* CompatibleAttribute.swift */; }; @@ -559,6 +560,7 @@ 4C75EFB628049D990006080F /* RelayPool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayPool.swift; sourceTree = "<group>"; }; 4C75EFB82804A2740006080F /* EventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventView.swift; sourceTree = "<group>"; }; 4C75EFBA2804A34C0006080F /* ProofOfWork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProofOfWork.swift; sourceTree = "<group>"; }; + 4C7D09582A05BEAD00943473 /* KeyboardVisible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardVisible.swift; sourceTree = "<group>"; }; 4C7FF7D42823313F009601DB /* Mentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mentions.swift; sourceTree = "<group>"; }; 4C8682862814DE470026224F /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; }; 4C8D00C729DF791C0036AF10 /* CompatibleAttribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompatibleAttribute.swift; sourceTree = "<group>"; }; @@ -1069,6 +1071,7 @@ 4CDA128B29EB19C40006FA5A /* LocalNotification.swift */, 4CA5588229F33F5B00DC6A45 /* StringCodable.swift */, 50B5685229F97CB400A23243 /* CredentialHandler.swift */, + 4C7D09582A05BEAD00943473 /* KeyboardVisible.swift */, ); path = Util; sourceTree = "<group>"; @@ -1654,6 +1657,7 @@ 4CF0ABE12981A83900D66079 /* MutelistView.swift in Sources */, 4CB883A82975FC1800DC99E7 /* Zaps.swift in Sources */, 4C75EFB128049D510006080F /* NostrResponse.swift in Sources */, + 4C7D09592A05BEAD00943473 /* KeyboardVisible.swift in Sources */, 4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */, 4CC7AAEB297F0AEC00430951 /* BuilderEventView.swift in Sources */, 31D2E847295218AF006D67F8 /* Shimmer.swift in Sources */, diff --git a/damus/Util/KeyboardVisible.swift b/damus/Util/KeyboardVisible.swift @@ -0,0 +1,31 @@ +// +// KeyboardVisible.swift +// damus +// +// Created by William Casarin on 2023-05-05. +// + +import Foundation +import Combine +import UIKit + + +/// Publisher to read keyboard changes. +protocol KeyboardReadable { + var keyboardPublisher: AnyPublisher<Bool, Never> { get } +} + +extension KeyboardReadable { + var keyboardPublisher: AnyPublisher<Bool, Never> { + Publishers.Merge( + NotificationCenter.default + .publisher(for: UIResponder.keyboardWillShowNotification) + .map { _ in true }, + + NotificationCenter.default + .publisher(for: UIResponder.keyboardWillHideNotification) + .map { _ in false } + ) + .eraseToAnyPublisher() + } +} diff --git a/damus/Views/DMChatView.swift b/damus/Views/DMChatView.swift @@ -6,8 +6,9 @@ // import SwiftUI +import Combine -struct DMChatView: View { +struct DMChatView: View, KeyboardReadable { let damus_state: DamusState @ObservedObject var dms: DirectMessageModel @State var showPrivateKeyWarning: Bool = false @@ -24,17 +25,37 @@ struct DMChatView: View { DMView(event: dms.events[ind], damus_state: damus_state) .contextMenu{MenuItems(event: ev, keypair: damus_state.keypair, target_pubkey: ev.pubkey, bookmarks: damus_state.bookmarks, muted_threads: damus_state.muted_threads)} } - EndBlock(height: 80) + EndBlock(height: 1) } .padding(.horizontal) + } + .dismissKeyboardOnTap() .onAppear { - scroller.scrollTo("endblock") + scroll_to_end(scroller) }.onChange(of: dms.events.count) { _ in - withAnimation { - scroller.scrollTo("endblock") + scroll_to_end(scroller, animated: true) + } + + Footer + .onReceive(keyboardPublisher) { visible in + guard visible else { + return + } + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + scroll_to_end(scroller, animated: true) + } } + } + } + + func scroll_to_end(_ scroller: ScrollViewProxy, animated: Bool = false) { + if animated { + withAnimation { + scroller.scrollTo("endblock") } + } else { + scroller.scrollTo("endblock") } } @@ -87,37 +108,32 @@ struct DMChatView: View { } var Footer: some View { - ZStack { - BackgroundColor() - - HStack(spacing: 0) { - InputField - - if !dms.draft.isEmpty { - Button( - role: .none, - action: { - showPrivateKeyWarning = contentContainsPrivateKey(dms.draft) - - if !showPrivateKeyWarning { - send_message() - } + + HStack(spacing: 0) { + InputField + + if !dms.draft.isEmpty { + Button( + role: .none, + action: { + showPrivateKeyWarning = contentContainsPrivateKey(dms.draft) + + if !showPrivateKeyWarning { + send_message() } - ) { - Label("", systemImage: "arrow.right.circle") - .font(.title) } + ) { + Label("", systemImage: "arrow.right.circle") + .font(.title) } } + } + + /* + Text(dms.draft).opacity(0).padding(.all, 8) .fixedSize(horizontal: false, vertical: true) .frame(minHeight: 70, maxHeight: 150, alignment: .bottom) - - Text(dms.draft).opacity(0).padding(.all, 8) - .fixedSize(horizontal: false, vertical: true) - .frame(minHeight: 70, maxHeight: 150, alignment: .bottom) - } - .fixedSize(horizontal: false, vertical: true) - .frame(minHeight: 70, maxHeight: 150, alignment: .bottom) + */ } func send_message() { @@ -143,13 +159,6 @@ struct DMChatView: View { var body: some View { ZStack { Messages - .dismissKeyboardOnTap() - - VStack { - Spacer() - - Footer - } Text("Send a message to start the conversation...", comment: "Text prompt for user to send a message to the other user.") .lineLimit(nil) @@ -238,3 +247,4 @@ extension View { .background(content()) } } +