From 70d015e5cef19506e7ed969a62283103e0a3ff02 Mon Sep 17 00:00:00 2001 From: N-Pex Date: Fri, 4 Dec 2020 10:44:46 +0100 Subject: [PATCH] Handle soft keyboard better --- package-lock.json | 15 ++++++ package.json | 1 + src/components/Chat.vue | 104 ++++++++++++++++++++++++++++------------ src/main.js | 3 ++ 4 files changed, 93 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 749797d..e9632f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "roboto-fontface": "*", "v-emoji-picker": "^2.3.1", "vue": "^2.6.11", + "vue-resize": "^0.5.0", "vue-router": "^3.2.0", "vuetify": "^2.2.11", "vuex": "^3.5.1" @@ -13499,6 +13500,14 @@ "vue-class-component": "*" } }, + "node_modules/vue-resize": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.5.0.tgz", + "integrity": "sha512-k5gOOwTIGSoWZb133Gx3IfSeiiAmve5GyWI7+pU8CvbNntpSAlrCYwZ26GB63NpxcLPK94+m0BDl5TxuZUI+Hw==", + "peerDependencies": { + "vue": "^2.6.11" + } + }, "node_modules/vue-router": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz", @@ -25652,6 +25661,12 @@ "integrity": "sha512-xYA8MkZynPBGd/w5QFJ2d/NM0z/YeegMqYTphy7NJQXbZcuU6FC6AOdUAcy4SXP+YnkerC6AfH+ldg7PDk9ESQ==", "requires": {} }, + "vue-resize": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.5.0.tgz", + "integrity": "sha512-k5gOOwTIGSoWZb133Gx3IfSeiiAmve5GyWI7+pU8CvbNntpSAlrCYwZ26GB63NpxcLPK94+m0BDl5TxuZUI+Hw==", + "requires": {} + }, "vue-router": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz", diff --git a/package.json b/package.json index 1a23876..1259a51 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "roboto-fontface": "*", "v-emoji-picker": "^2.3.1", "vue": "^2.6.11", + "vue-resize": "^0.5.0", "vue-router": "^3.2.0", "vuetify": "^2.2.11", "vuex": "^3.5.1" diff --git a/src/components/Chat.vue b/src/components/Chat.vue index c508f9f..b3b22b4 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -7,17 +7,26 @@ v-on:sscroll="onScroll" >
-
-
+
@@ -196,7 +211,13 @@ export default { currentSendError: null, showEmojiPicker: false, selectedEvent: null, - showContextMenu: false + showContextMenu: false, + /** + * Current chat container size. We need to keep track of this so that if and when + * a soft keyboard is shown/hidden we can restore the scroll position correctly. + * If we don't, the keyboard will simply overflow the message we are answering to etc. + */ + chatContainerSize: 0, }; }, @@ -205,6 +226,8 @@ export default { this.scrollPosition = new ScrollPosition(container); this.$matrix.on("Room.timeline", this.onEvent); this.$matrix.on("RoomMember.typing", this.onUserTyping); + this.chatContainerSize = this.$refs.chatContainerResizer.$el.clientHeight; + console.log("resize initial height: ", this.chatContainerSize); }, destroyed() { @@ -258,13 +281,13 @@ export default { methods: { touchX(event) { - if(event.type.indexOf('mouse') !== -1){ + if (event.type.indexOf("mouse") !== -1) { return event.clientX; } return event.touches[0].clientX; }, touchY(event) { - if(event.type.indexOf('mouse') !== -1){ + if (event.type.indexOf("mouse") !== -1) { return event.clientY; } return event.touches[0].clientY; @@ -291,17 +314,38 @@ export default { this.touchCurrentX = this.touchX(e); this.touchCurrentY = this.touchY(e); var tapTolerance = 4; - var touchMoved = Math.abs(this.touchStartX - this.touchCurrentX) > tapTolerance || - Math.abs(this.touchStartY - this.touchCurrentY) > tapTolerance; - if(touchMoved){ + var touchMoved = + Math.abs(this.touchStartX - this.touchCurrentX) > tapTolerance || + Math.abs(this.touchStartY - this.touchCurrentY) > tapTolerance; + if (touchMoved) { this.touchTimer && clearTimeout(this.touchTimer); } }, + + /** + * Triggered when out "long tap" timer hits. + */ touchTimerElapsed() { - console.log('timer'); this.showContextMenu = true; }, + /** + * If chat container is shrunk (probably because soft keyboard is shown) adjust + * the scroll position so that e.g. if we were looking at the last message when + * moving focus to the input field, we would still see the last message. Otherwise + * if would be hidden behind the keyboard. + */ + handleChatContainerResize({ width, height }) { + console.log("resized", width, height); + const delta = height - this.chatContainerSize; + this.chatContainerSize = height; + console.log("resized delta " + delta); + const container = this.$refs.chatContainer; + if (delta < 0) { + container.scrollTop -= delta; + } + }, + componentForEvent(event) { switch (event.getType()) { case "m.room.member": @@ -312,7 +356,7 @@ export default { } else if (event.getContent().membership == "invite") { return ContactInvited; } - break; + break; case "m.room.message": if (event.getSender() != this.$matrix.currentUserId) { @@ -372,7 +416,7 @@ export default { // If we are at bottom, scroll to see new events... const container = this.$refs.chatContainer; - var scrollToSeeNew = (event.getSender() == this.$matrix.currentUserId); // When we sent, scroll + var scrollToSeeNew = event.getSender() == this.$matrix.currentUserId; // When we sent, scroll if ( container.scrollHeight - container.scrollTop.toFixed(0) == container.clientHeight @@ -542,25 +586,25 @@ export default { if (this.selectedEvent) { const event = this.selectedEvent; this.selectedEvent = null; - this.sendQuickReaction({reaction:e.data, event: event}); + this.sendQuickReaction({ reaction: e.data, event: event }); } }, sendQuickReaction(e) { util - .sendQuickReaction( - this.$matrix.matrixClient, - this.roomId, - e.reaction, - e.event - ) - .then(() => { - console.log("Quick reaction message"); - }) - .catch((err) => { - console.log("Failed to send quick reaction:", err); - }); - } + .sendQuickReaction( + this.$matrix.matrixClient, + this.roomId, + e.reaction, + e.event + ) + .then(() => { + console.log("Quick reaction message"); + }) + .catch((err) => { + console.log("Failed to send quick reaction:", err); + }); + }, }, }; diff --git a/src/main.js b/src/main.js index ac23b9f..fd4097f 100644 --- a/src/main.js +++ b/src/main.js @@ -7,9 +7,12 @@ import matrix from './services/matrix.service' import 'roboto-fontface/css/roboto/roboto-fontface.css' import 'material-design-icons-iconfont/dist/material-design-icons.css' import VEmojiPicker from 'v-emoji-picker'; +import VueResize from 'vue-resize'; +import 'vue-resize/dist/vue-resize.css'; Vue.config.productionTip = false +Vue.use(VueResize); Vue.use(VEmojiPicker); Vue.use(matrix, {store: store});