From fd86e753fe60243c20ea04251b90432d1340c9fd Mon Sep 17 00:00:00 2001 From: N-Pex Date: Mon, 22 Feb 2021 16:34:19 +0100 Subject: [PATCH] Start on voice recording --- package-lock.json | 108 +++++++++++++++++++- package.json | 1 + src/assets/css/chat.scss | 15 +++ src/components/Chat.vue | 32 ++++++ src/components/VoiceRecorder.vue | 163 +++++++++++++++++++++++++++++++ src/main.js | 7 ++ src/plugins/utils.js | 11 +++ 7 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 src/components/VoiceRecorder.vue diff --git a/package-lock.json b/package-lock.json index 0ae335f..8d24ef5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "keanuapp-weblite", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.1.0", + "version": "0.1.1", "dependencies": { "aes-js": "^3.1.2", "axios": "^0.21.0", @@ -16,6 +16,7 @@ "json-web-key": "^0.4.0", "material-design-icons-iconfont": "^5.0.1", "matrix-js-sdk": "^9.4.1", + "mic-recorder-to-mp3": "^2.2.2", "olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz", "qrcode": "^1.4.4", "raw-loader": "^4.0.2", @@ -8121,6 +8122,14 @@ "node": ">=0.10.0" } }, + "node_modules/lamejs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lamejs/-/lamejs-1.2.0.tgz", + "integrity": "sha1-Aln4PbRmYUGntnG4yqY2nZUXfQg=", + "dependencies": { + "use-strict": "1.0.1" + } + }, "node_modules/launch-editor": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.2.1.tgz", @@ -8490,6 +8499,17 @@ "node": ">= 0.6" } }, + "node_modules/mic-recorder-to-mp3": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mic-recorder-to-mp3/-/mic-recorder-to-mp3-2.2.2.tgz", + "integrity": "sha512-xDkOaHbojW3bdKOGn9CI5dT+Mc0RrfczsX/Y1zGJp3FUB4zei5ZKFnNm7Nguc9v910wkd7T3csnCTq5EtCF3Zw==", + "dependencies": { + "lamejs": "^1.2.0" + }, + "peerDependencies": { + "webrtc-adapter": ">=4.1.1" + } + }, "node_modules/micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -11376,6 +11396,19 @@ "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" }, + "node_modules/rtcpeerconnection-shim": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz", + "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==", + "peer": true, + "dependencies": { + "sdp": "^2.6.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -11508,6 +11541,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/sdp": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz", + "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==", + "peer": true + }, "node_modules/select": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", @@ -13280,6 +13319,11 @@ "node": ">=0.10.0" } }, + "node_modules/use-strict": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/use-strict/-/use-strict-1.0.1.tgz", + "integrity": "sha1-C7gNlPSaSgUZK4Sox9NOlfGn46A=" + }, "node_modules/util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -14604,6 +14648,20 @@ "webpack": "^4.0.0" } }, + "node_modules/webrtc-adapter": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.0.tgz", + "integrity": "sha512-7Bp9OBnx642oJRkom1tNAbeJjUadAq2rh5xLL9YXPw5hVyt2h4hHr5bcoPYDs1stp/mZHSPSQA34YISdnr0DBQ==", + "peer": true, + "dependencies": { + "rtcpeerconnection-shim": "^1.2.15", + "sdp": "^2.12.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -21529,6 +21587,14 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, + "lamejs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lamejs/-/lamejs-1.2.0.tgz", + "integrity": "sha1-Aln4PbRmYUGntnG4yqY2nZUXfQg=", + "requires": { + "use-strict": "1.0.1" + } + }, "launch-editor": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.2.1.tgz", @@ -21842,6 +21908,14 @@ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", "dev": true }, + "mic-recorder-to-mp3": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mic-recorder-to-mp3/-/mic-recorder-to-mp3-2.2.2.tgz", + "integrity": "sha512-xDkOaHbojW3bdKOGn9CI5dT+Mc0RrfczsX/Y1zGJp3FUB4zei5ZKFnNm7Nguc9v910wkd7T3csnCTq5EtCF3Zw==", + "requires": { + "lamejs": "^1.2.0" + } + }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -24192,6 +24266,15 @@ "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" }, + "rtcpeerconnection-shim": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz", + "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==", + "peer": true, + "requires": { + "sdp": "^2.6.0" + } + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -24280,6 +24363,12 @@ "ajv-keywords": "^3.5.2" } }, + "sdp": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz", + "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==", + "peer": true + }, "select": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", @@ -25742,6 +25831,11 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "use-strict": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/use-strict/-/use-strict-1.0.1.tgz", + "integrity": "sha1-C7gNlPSaSgUZK4Sox9NOlfGn46A=" + }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -26785,6 +26879,16 @@ } } }, + "webrtc-adapter": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.0.tgz", + "integrity": "sha512-7Bp9OBnx642oJRkom1tNAbeJjUadAq2rh5xLL9YXPw5hVyt2h4hHr5bcoPYDs1stp/mZHSPSQA34YISdnr0DBQ==", + "peer": true, + "requires": { + "rtcpeerconnection-shim": "^1.2.15", + "sdp": "^2.12.0" + } + }, "websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", diff --git a/package.json b/package.json index 3d54144..6bdccc3 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "json-web-key": "^0.4.0", "material-design-icons-iconfont": "^5.0.1", "matrix-js-sdk": "^9.4.1", + "mic-recorder-to-mp3": "^2.2.2", "olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz", "qrcode": "^1.4.4", "raw-loader": "^4.0.2", diff --git a/src/assets/css/chat.scss b/src/assets/css/chat.scss index 0150e87..3f5323b 100644 --- a/src/assets/css/chat.scss +++ b/src/assets/css/chat.scss @@ -597,4 +597,19 @@ $admin-fg: white; width: 100%; } } +} + +.voice-recorder { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background-color: black; + &.will-cancel { + background-color: grey; + } + .recording-time { + color: white; + } } \ No newline at end of file diff --git a/src/components/Chat.vue b/src/components/Chat.vue index ef82d82..9b60cd7 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -154,6 +154,21 @@ /> + + + mic + + +
@@ -271,6 +287,7 @@ import DebugEvent from "./messages/DebugEvent.vue"; import util from "../plugins/utils"; import MessageOperations from "./messages/MessageOperations.vue"; import ChatHeader from "./ChatHeader"; +import VoiceRecorder from "./VoiceRecorder"; const READ_RECEIPT_TIMEOUT = 5000; /* How long a message must have been visible before the read marker is updated */ @@ -320,6 +337,7 @@ export default { RoomAvatarChanged, DebugEvent, MessageOperations, + VoiceRecorder }, data() { @@ -341,6 +359,7 @@ export default { showContextMenu: false, showContextMenuAnchor: null, initialLoadDone: false, + showRecorder: false, /** * Current chat container size. We need to keep track of this so that if and when @@ -1061,6 +1080,19 @@ export default { dayForEvent(event) { return util.formatDay(event.getTs()); }, + + startRecording() { + this.showRecorder = true; + }, + + onVoiceRecording(event) { + util.sendImage( + this.$matrix.matrixClient, + this.roomId, + event.file, + undefined + ); + } }, }; diff --git a/src/components/VoiceRecorder.vue b/src/components/VoiceRecorder.vue new file mode 100644 index 0000000..16752e9 --- /dev/null +++ b/src/components/VoiceRecorder.vue @@ -0,0 +1,163 @@ + + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index 3712945..548be37 100644 --- a/src/main.js +++ b/src/main.js @@ -32,6 +32,13 @@ Vue.use((Vue) => { }; }); +// Register a global custom directive called `v-blur` that prevents focus +Vue.directive('blur', { + inserted: function (el) { + el.onfocus = (ev) => ev.target.blur() + } +}); + Vue.use(navigation, router); new Vue({ diff --git a/src/plugins/utils.js b/src/plugins/utils.js index 3d63b45..ba866ab 100644 --- a/src/plugins/utils.js +++ b/src/plugins/utils.js @@ -8,6 +8,8 @@ var base64Url = require('json-web-key/lib/base64url'); // Install extended localized format var localizedFormat = require('dayjs/plugin/localizedFormat') dayjs.extend(localizedFormat) +var duration = require('dayjs/plugin/duration') +dayjs.extend(duration); class Util { getAttachment(matrixClient, event) { @@ -443,6 +445,15 @@ class Util { return then.format('L'); } } + + formatRecordDuration(ms) { + return dayjs.duration(ms).format("HH:mm:ss"); + } + + formatRecordStartTime(timestamp) { + var then = dayjs(timestamp); + return then.format('lll'); + } } export default new Util();