diff --git a/README.md b/README.md index d99478a..e100dcd 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ The app loads runtime configutation from the server at "./config.json" and merge The following values can be set via the config file: * **logo** - An url or base64-encoded image data url that represents the app logotype. -* **accentColor** - The accent color of the app UI. +* **accentColor** - The accent color of the app UI. Use a HTML-style color value string, like "#ff0080". * **show_status_messages** - Whether to show only user joins/leaves and display name updates, or the full range of room status updates. Possible values are "never" (only the above), "moderators" (moderators will see all status updates) or "always" (everyone will see all status updates). Defaults to "always". diff --git a/package-lock.json b/package-lock.json index e04c4eb..a3fe23c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@matrix-org/olm": "^3.2.12", "aes-js": "^3.1.2", - "axios": "^0.21.0", + "axios": "^1.4.0", "browserify-fs": "^1.0.0", "buffer": "^6.0.3", "clean-insights-sdk": "^2.4", @@ -4097,6 +4097,11 @@ "lodash": "^4.17.14" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -4153,11 +4158,13 @@ } }, "node_modules/axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", "dependencies": { - "follow-redirects": "^1.14.0" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/babel-eslint": { @@ -5497,6 +5504,17 @@ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -6378,6 +6396,14 @@ "node": ">=0.10.0" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", @@ -7869,6 +7895,19 @@ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -11929,6 +11968,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -19358,6 +19402,11 @@ "lodash": "^4.17.14" } }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -19386,11 +19435,13 @@ } }, "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", "requires": { - "follow-redirects": "^1.14.0" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "babel-eslint": { @@ -20464,6 +20515,14 @@ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -21145,6 +21204,11 @@ "isobject": "^3.0.1" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, "delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", @@ -22325,6 +22389,16 @@ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -25482,6 +25556,11 @@ } } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", diff --git a/package.json b/package.json index 6b1aae7..37f96f0 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "dependencies": { "@matrix-org/olm": "^3.2.12", "aes-js": "^3.1.2", - "axios": "^0.21.0", + "axios": "^1.4.0", "browserify-fs": "^1.0.0", "buffer": "^6.0.3", "clean-insights-sdk": "^2.4", diff --git a/src/App.vue b/src/App.vue index a3fea3a..eb32533 100644 --- a/src/App.vue +++ b/src/App.vue @@ -31,6 +31,7 @@ @@ -195,7 +236,7 @@ export default { } #app { - background-color: $app-background; + background-color: var(--v-app-background); } .main { diff --git a/src/assets/config.json b/src/assets/config.json index 488b681..42d5c8e 100644 --- a/src/assets/config.json +++ b/src/assets/config.json @@ -9,6 +9,7 @@ "productLink": "letsconvene.im", "defaultServer": "https://neo.keanu.im", "identityServer_unset": "", + "registrationToken_unset": "", "rtl": false, "accentColor_unset": "", "logo_unset": "", @@ -44,6 +45,7 @@ } ], "experimental_voice_mode": true, + "experimental_file_mode": true, "experimental_read_only_room": true, "experimental_public_room": true, "show_status_messages": "never" diff --git a/src/assets/css/chat.scss b/src/assets/css/chat.scss index deb30e5..8d7132a 100644 --- a/src/assets/css/chat.scss +++ b/src/assets/css/chat.scss @@ -1,16 +1,19 @@ @import "~vuetify/src/styles/settings/_variables.scss"; @import "@/assets/css/main.scss"; @import "@/assets/css/vendors/v-emoji-picker"; +@import "@/assets/css/filedrop.scss"; $admin-bg: black; $admin-fg: white; body { + --v-app-background: $app-background; --v-background-color: white; --v-foreground-color: black; --v-secondary-color: #242424; --v-divider-color: #eeeeee; &.dark { + --v-app-background: black; --v-background-color: black; --v-foreground-color: white; --v-secondary-color: #c0c0c0; @@ -101,22 +104,17 @@ body { } .notification-alert { - display: inline-block; - background-color: $alert-bg-color; - width: 8px; - height: 8px; - border-radius: 4px; - margin-bottom: 2px; - position: relative; - overflow: visible; + .icon-circle { + color: $alert-bg-color; + } &.popup-open::after { - top: 20px; + top: 35px; color: #246bfd; } .missed-items-popup { position: absolute; bottom: -17px; - left: -20px; + left: -175px; transform: translateY(100%); background: #246bfd; border-radius: 8px; @@ -125,8 +123,10 @@ body { padding: 22px 18px 23px 18px; z-index: 300; user-select: none; + width: 300px; + justify-content: space-between; .text { - white-space: nowrap; + white-space: break-spaces; font-family: "Inter", sans-serif; font-style: normal; font-weight: 500; @@ -161,7 +161,12 @@ body { backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px); } -} + } + + @media #{map-get($display-breakpoints, 'sm-and-down')} { + position: fixed; + z-index: 10; + } } .chat-root { @@ -206,7 +211,6 @@ body { @media #{map-get($display-breakpoints, 'sm-and-down')} { margin-top: 72px; margin-bottom: 70px; - z-index: 9; } } @@ -791,6 +795,7 @@ body { .room-name-inline { text-align: start; + min-width: 75px; } .room-name.no-upper { @@ -953,30 +958,6 @@ body { font-size: 16 * $chat-text-size !important; } - .qr-container { - background-color: white; - border-radius: 8px; - margin-top: 20px !important; - .qr { - width: 60px; - height: 60px; - background-color: #e0e0e0; - } - .link { - font-family: "Inter", sans-serif; - font-size: 16px; - text-decoration: underline; - color: #3d6eff; - overflow-wrap: anywhere; - } - } - .link-copied-in-place .v-btn__content { - font-family: "Inter", sans-serif !important; - font-size: 12px !important; - text-transform: none !important; - color: #3d6eff; - } - .filled-button { @media #{map-get($display-breakpoints, 'sm-and-up')} { min-width: 180px !important; @@ -1077,7 +1058,7 @@ body { } .profile { - background-color: white; + background-color: #e8e8e8; height: 100%; .chat-header { background-color: transparent; @@ -1286,7 +1267,7 @@ body { .option-warning { background: linear-gradient(0deg, #FFF3F3, #FFF3F3), #FFFBED; border-radius: 8px; - padding: 18px; + padding: 18px; font-family: 'Inter', sans-serif; font-style: normal; font-weight: 400; @@ -1294,7 +1275,7 @@ body { line-height: 17px; .v-icon { margin-right: 16px; - } + } } } @@ -1433,6 +1414,14 @@ body { width: 32px !important; height: 32px !important; margin-left: -8px !important; + position: relative; + overflow: visible; + } + .reaction-emoji { + position: absolute; + top: -6px; + right: -6px; + font-size: 17px; } .list-enter-active, .list-leave-active { @@ -1452,6 +1441,9 @@ body { justify-content: flex-end; width: 100%; } + .clap-button { + font-size: 24px; + } .mic-button { align-self: flex-end; } @@ -1539,4 +1531,4 @@ body { right: 20px; bottom: 20px; position: absolute; -} +} \ No newline at end of file diff --git a/src/assets/css/filedrop.scss b/src/assets/css/filedrop.scss new file mode 100644 index 0000000..fdd6f04 --- /dev/null +++ b/src/assets/css/filedrop.scss @@ -0,0 +1,360 @@ +$large-button-height: 48px; +$small-button-height: 36px; + +.file-drop-root { + $hiliteColor: #4642f1; + font-family: "Inter", sans-serif; + position: absolute; + top: 0px; + left: 0; + right: 0; + bottom: 0; + margin: 0; + background-color: var(--v-background-color); + color: var(--v-foreground-color); + overflow: hidden; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 16px; + + .file-drop-title { + color: #fff; + text-align: center; + font-size: 11.54 * $chat-text-size; + font-family: "Inter", sans-serif; + font-weight: 700; + line-height: 140%; + letter-spacing: 0.34px; + text-transform: uppercase; + margin-top: 13px; + margin-bottom: 25px; + } + .background { + width: 100%; + height: 50%; + background-color: #181719; + &.drop-target { + background-color: #383739; + } + border-radius: 19px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .file-format-info { + opacity: 0.6; + color: #fff; + text-align: center; + font-size: 11 * $chat-text-size; + font-family: "Inter", sans-serif; + line-height: 117%; + letter-spacing: 0.4px; + margin-top: 13px; + background: transparent; + } + + .v-btn { + font-family: "Inter", sans-serif; + font-weight: 700; + font-size: 11.54 * $chat-text-size; + line-height: 140%; + color: white; + background-color: $hiliteColor !important; + border-radius: $small-button-height / 2; + min-height: 0; + height: $small-button-height !important; + margin-top: $chat-standard-padding-xs; + margin-bottom: $chat-standard-padding-xs; + &.large { + padding: 16px 23px; + height: $large-button-height; + border-radius: $large-button-height / 2; + } + } + + textarea { + color: rgba(white, 80%) !important; + } + textarea::placeholder { + color: rgba(white, 80%) !important; + } + + .attachment-wrapper { + width: 100%; + flex: 0 0 100%; + overflow-y: auto; + } + .file-drop-current-item { + width: 100%; + height: 70%; + background-color: #181719; + &.drop-target { + background-color: #383739; + } + border-radius: 19px; + overflow: hidden; + .v-image { + width: 100%; + height: 100%; + object-fit: cover; + } + .filename { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } + } + .file-drop-thumbnail-container { + width: 100%; + padding: 13px 20px 15px 20px; + height: 74px; + overflow-x: auto; + overflow-y: hidden; + white-space: nowrap; + text-align: start; + + /* Hide scrollbar for Chrome, Safari and Opera */ + &::-webkit-scrollbar { + display: none; + } + /* Hide scrollbar for IE, Edge and Firefox */ + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + + .file-drop-thumbnail { + width: 46px; + height: 46px; + border-radius: 9px; + overflow: hidden; + background-color: #242424; + border: 2px solid white; + display: inline-block; + position: relative; + &.current { + border: 2px solid #4642f1; + } + &.noborder { + border: 2px solid transparent; + } + .v-image { + width: 100%; + height: 100%; + object-fit: cover; + } + margin-right: 8px; + + .add, + .remove { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + .v-icon { + width: 14px; + height: 15.75px; + } + } + .remove { + // Slight background to make visible + background-color: rgba(black, 0.2); + } + } + } + + .file-drop-section { + margin-top: 20px; + padding: 16px 18px; + background-color: #181719; + border-radius: 19px; + } + + .file-drop-input-container, + .file-drop-sending-input-container, + .file-drop-sent-input-container { + position: relative; + width: 100%; + min-height: 20%; + background-color: #181719; + border-radius: 19px; + display: flex; + flex-direction: column; + .input-area-text { + flex: 0 0 auto; + width: 100%; + margin-bottom: 50px; + padding: 16px 18px; + font-family: "Inter", sans-serif; + font-weight: 300; + } + .v-btn { + position: absolute; + right: 8px; + bottom: 10px; + } + } + + @keyframes fadeInStackItem { + from {opacity: 0;} + to {opacity: 1;} + } + + // Sending + // + .file-drop-sent-stack { + width: 100%; + height: 30%; + display: flex; + align-items: center; + justify-content: center; + .no-items { + display: flex; + align-items: center; + justify-content: center; + div { + position: absolute; + } + .file-drop-stack-item { + transform: rotate(-4.4deg); + } + color: #fff; + text-align: center; + font-size: 21 * $chat-text-size; + font-family: "Poppins", sans-serif; + font-weight: 700; + letter-spacing: 0.34px; + } + .items-sent { + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; + div, .v-icon { + position: absolute; + } + .v-icon, .v-icon__component { + width: 30%; + height: 30%; + } + } + .file-drop-stack-item { + background: #3a3a3c; + position: absolute; + overflow: hidden; + opacity: 0; + .v-image { + width: 100%; + height: 100%; + object-fit: cover; + } + &.direct { + opacity: 1 !important; + } + &.animated { + animation-name: fadeInStackItem; + animation-fill-mode: both; + animation-duration: 1.5s; + } + } + } + + .file-drop-sending-container { + width: 100%; + padding: 13px 0px 15px 0px; + height: 50%; + overflow-x: hidden; + overflow-y: auto; + white-space: nowrap; + text-align: start; + + /* Hide scrollbar for Chrome, Safari and Opera */ + &::-webkit-scrollbar { + display: none; + } + /* Hide scrollbar for IE, Edge and Firefox */ + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + + .file-drop-sending-item { + width: 100%; + height: 64px; + overflow: hidden; + background-color: #242424; + border-radius: 12px; + background: linear-gradient(0deg, #26242b 0%, #26242b 100%), #fff; + position: relative; + padding: 8px; + .v-image { + width: 48px; + height: 48px; + border-radius: 8px; + object-fit: cover; + flex: 0 0 48px; + margin-right: 8px; + } + margin-bottom: 8px; + display: flex; + align-items: center; + .filename { + position: absolute; + top: 18px; + left: 8px; + font-size: 0.7em; + } + .v-progress-linear { + align-self: flex-end; + } + .file-drop-cancel { + position: absolute; + right: 8px; + width: 17px; + height: 17px; + color: green !important; + background: #2e2e3b; + border-radius: 8.5px; + display: flex; + align-items: center; + justify-content: center; + } + } + } + + .file-drop-sending-input-container { + .v-btn { + .v-progress-circular { + margin-left: 8px; + } + background: linear-gradient(0deg, #000 0%, #000 100%), #4642f1; + } + } + + .file-drop-files-sent { + width: 100%; + color: #fff; + text-align: center; + font-size: 21 * $chat-text-size; + font-family: "Poppins", sans-serif; + font-weight: 700; + letter-spacing: 0.34px; + text-align: center; + } + + .file-drop-sent-input-container { + background-color: transparent; + .v-btn { + right: unset; + left: 8px; + background: linear-gradient(0deg, #000 0%, #000 100%), #4642f1; + } + } +} diff --git a/src/assets/icons/ic_check_circle.vue b/src/assets/icons/ic_check_circle.vue new file mode 100644 index 0000000..33ea12b --- /dev/null +++ b/src/assets/icons/ic_check_circle.vue @@ -0,0 +1,15 @@ + diff --git a/src/assets/icons/ic_lock.vue b/src/assets/icons/ic_lock.vue new file mode 100644 index 0000000..fd9324c --- /dev/null +++ b/src/assets/icons/ic_lock.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/assets/icons/ic_trash.vue b/src/assets/icons/ic_trash.vue new file mode 100644 index 0000000..e2d9b30 --- /dev/null +++ b/src/assets/icons/ic_trash.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/assets/sounds/clapping.mp3 b/src/assets/sounds/clapping.mp3 new file mode 100644 index 0000000..bbc9886 Binary files /dev/null and b/src/assets/sounds/clapping.mp3 differ diff --git a/src/assets/translations/bo.json b/src/assets/translations/bo.json index f3cc3c7..c19df4c 100644 --- a/src/assets/translations/bo.json +++ b/src/assets/translations/bo.json @@ -29,7 +29,7 @@ "join_invite": "ཁ་སྣོན་བྱས་པའི་གྲོགས་ཁོ་ན།", "permissions": "ནང་འཛུལ་གྱི་ཆོག་མཆན་ཁག", "created_by": "{user} བཟོས།", - "copy_link": "གདན་ཞུ་འབྲེལ་ཐག་པར་བཤུས་རྒྱོབས།", + "copy_invite_link": "གདན་ཞུ་འབྲེལ་ཐག་པར་བཤུས་རྒྱོབས།", "scan_code": "བཤེར་རིས་བཤེར་ཏེ་ཁ་བརྡ་ཁང་དུ་འཛུལ།", "user_admin": "དོ་དམ་པ།", "experimental_features": "ཚོད་ལྟའི་ཁྱད་ཆོས་ཁག", diff --git a/src/assets/translations/de.json b/src/assets/translations/de.json index 65b8f64..6009de4 100644 --- a/src/assets/translations/de.json +++ b/src/assets/translations/de.json @@ -187,7 +187,7 @@ "permissions": "Beitrittsberechtigungen", "join_invite": "Nur hinzugefügte Personen", "join_public": "Jeder mit einem Link", - "copy_link": "Link zur Einladung kopieren", + "copy_invite_link": "Link zur Einladung kopieren", "link_copied": "Link kopiert!", "purge": "Raum löschen", "members": "Mitglieder", diff --git a/src/assets/translations/en.json b/src/assets/translations/en.json index cc8c121..72c15ac 100644 --- a/src/assets/translations/en.json +++ b/src/assets/translations/en.json @@ -11,7 +11,13 @@ "show_less": "Show less", "show_more": "Show more", "add_reaction": "Add reaction", - "click_to_remove": "Click to remove" + "click_to_remove": "Click to remove", + "time": { + "recently": "just now", + "minutes": "1 minute ago | {n} minutes ago", + "hours": "1 hour ago | {n} hours ago", + "days": "1 day ago | {n} days ago" + } }, "menu": { "start_private_chat": "Private chat with this user", @@ -90,7 +96,12 @@ "incoming_message_deleted_text": "This message was deleted.", "not_allowed_to_send": "Only admins and moderators are allowed to send to the room", "reaction_count_more": "{reactionCount} more", - "seen_by": "Seen by no members | Seen by 1 member | Seen by {count} members" + "seen_by_count": "Seen by no members | Seen by 1 member | Seen by {count} members", + "seen_by": "Seen by", + "file": "File", + "files": "Files", + "images": "Images", + "send_attachements_dialog_title": "Do you want to send following attachments ?" }, "room": { "invitations": "You have no invitations | You have 1 invitation | You have {count} invitations", @@ -164,7 +175,10 @@ "send_verification": "Send verification email", "sent_verification": "An email has been sent to {email}. Please use your regular email client to verify the address.", "resend_verification": "Resend verification email", - "email_not_valid": "Email address not valid" + "email_not_valid": "Email address not valid", + "registration_token": "Please enter registration token", + "send_token": "Send token", + "token_not_valid": "Invalid token" }, "profile": { "title": "My Profile", @@ -206,7 +220,8 @@ "status_logging_in": "Logging in...", "status_joining": "Joining room...", "join_failed": "Failed to join room.", - "choose_name": "Choose a name to use" + "choose_name": "Choose a name to use", + "you_have_been_banned": "You have been banned from this room." }, "invite": { "title": "Add Friends", @@ -249,7 +264,8 @@ "permissions": "Join Permissions", "join_invite": "Only People Added", "join_public": "Anyone with a link", - "copy_link": "Copy invite link", + "copy_invite_link": "Copy invite link", + "copy_link": "Copy link", "link_copied": "Link copied!", "purge": "Delete room", "members": "Members", @@ -264,13 +280,19 @@ "user_admin": "Administrator", "user_moderator": "Moderator", "experimental_features": "Experimental Features", + "room_type": "Room type", + "room_type_default": "Default", "voice_mode": "Voice mode", "voice_mode_info": "Switches the chat interface to a 'listen and record' mode", + "file_mode": "File mode", + "file_mode_info": "Switches the chat interface to a 'file drop' mode", "download_chat": "Download chat", "read_only_room": "Read only room", "read_only_room_info": "Only admins and moderators are allowed to send to the room", "make_public": "Make Public", - "make_public_warning": "warning: Full message history will be visible to new participants" + "make_public_warning": "warning: Full message history will be visible to new participants", + "contact_link": "My Contact Link", + "contact_link_desc": "Share your contact link. When opened, a direct message will be started with you." }, "room_info_sheet": { "this_room": "This room", @@ -329,5 +351,34 @@ "fetched_n_of_total_events": "Fetched {count} of {total} events", "processed_n_of_total_events": "Processed media for {count} of {total} events", "export_filename": "Exported chat {date}" + }, + "notification": { + "title": "New message received" + }, + "emoji": { + "search": "Search...", + "categories": { + "activity": "Activity", + "flags": "Flags", + "foods": "Foods", + "frequently": "Frequently used", + "objects": "Objects", + "nature": "Nature", + "peoples": "Peoples", + "symbols": "Symbols", + "places": "Places" + } + }, + "file_mode": { + "choose_files": "Choose files", + "any_file_format_accepted": "Any file format is accepted", + "secure_file_send": "secure file send", + "add_a_message": "Add a message", + "sending_progress": "Sending...", + "sending": "Sending", + "files_sent":"1 file sent! | {count} files sent!", + "files_sent_with_note":"1 file sent with a note! | {count} files sent with a note!", + "return_to_home": "Return to home", + "files": "Files" } } diff --git a/src/assets/translations/es.json b/src/assets/translations/es.json index 963582c..2971859 100644 --- a/src/assets/translations/es.json +++ b/src/assets/translations/es.json @@ -26,7 +26,7 @@ "leave_room": "Salir", "view_profile": "Vista", "identity_temporary": "Tu identidad {displayName} es temporal. Puedes cambiar tu nombre o establecer una contraseña para conservarla.", - "copy_link": "Copiar el enlace de invitación", + "copy_invite_link": "Copiar el enlace de invitación", "scan_code": "Escanear para unirse a la sala" }, "purge_room": { diff --git a/src/assets/translations/fr.json b/src/assets/translations/fr.json index 317325f..bb08028 100644 --- a/src/assets/translations/fr.json +++ b/src/assets/translations/fr.json @@ -184,7 +184,7 @@ "permissions": "Autorisations d’adhésion", "join_invite": "Seules les personnes ajoutées", "join_public": "Quiconque avec un lien", - "copy_link": "Copier le lien d’invitation", + "copy_invite_link": "Copier le lien d’invitation", "link_copied": "Lien copié !", "purge": "Supprimer le salon", "user_you": "{user} (vous)", diff --git a/src/assets/translations/it.json b/src/assets/translations/it.json index 500d785..3c53d29 100644 --- a/src/assets/translations/it.json +++ b/src/assets/translations/it.json @@ -194,7 +194,7 @@ "leave_room": "Lascia", "scan_code": "Scansiona per entrare nella stanza", "version_info": "Realizzato da Guardian Project. Versione: {version}", - "copy_link": "Copia il collegamento di invito" + "copy_invite_link": "Copia il collegamento di invito" }, "voice_recorder": { "failed_to_record": "Impossibile registrare l’audio", diff --git a/src/assets/translations/nb_NO.json b/src/assets/translations/nb_NO.json index 46e4c3f..63c5225 100644 --- a/src/assets/translations/nb_NO.json +++ b/src/assets/translations/nb_NO.json @@ -60,7 +60,7 @@ "members": "Medlemmer", "purge": "Slett rom", "link_copied": "Lenke kopiert.", - "copy_link": "Kopier invitasjonslenke", + "copy_invite_link": "Kopier invitasjonslenke", "created_by": "Opprettet av {user}", "title": "Romdetaljer" }, diff --git a/src/assets/translations/pt_BR.json b/src/assets/translations/pt_BR.json index a4702e1..cddd3e2 100644 --- a/src/assets/translations/pt_BR.json +++ b/src/assets/translations/pt_BR.json @@ -252,7 +252,7 @@ "permissions": "Permissões de ingresso", "join_invite": "Somente pessoas adicionadas", "join_public": "Qualquer pessoa com um link", - "copy_link": "Copie o link do convite", + "copy_invite_link": "Copie o link do convite", "link_copied": "Link copiado!", "purge": "Excluir a sala", "members": "Membros", diff --git a/src/assets/translations/ro.json b/src/assets/translations/ro.json index 081a30c..cfad603 100644 --- a/src/assets/translations/ro.json +++ b/src/assets/translations/ro.json @@ -53,7 +53,7 @@ "members": "Membri", "purge": "Ștergeți camera", "link_copied": "Link copiat!", - "copy_link": "Copiați link-ul de invitație", + "copy_invite_link": "Copiați link-ul de invitație", "join_public": "Oricine are un link", "join_invite": "Numai persoane adăugate", "permissions": "Permisiuni de aderare", diff --git a/src/assets/translations/ug.json b/src/assets/translations/ug.json index d76f259..f30fa5e 100644 --- a/src/assets/translations/ug.json +++ b/src/assets/translations/ug.json @@ -30,36 +30,20 @@ "edited": "تەھرىرلەندى", "file_prefix": "ھۆججەت ", "user_said": "{user} سۆزلىدى:", - "user_left": "قوللانغۇچى مۇنازىرىدىن چېكىندى", - "user_joined": "قوللانغۇچى مۇنازىرىغا قاتناشتى", - "user_was_invited": "قوللانغۇچى مۇنازىرە ئۆيىگە تەكلىپ قىلىندى...", - "user_encrypted_room": "قوللانغۇچى مۇنازىرە-خانىنى سىفىرلاشتۇردى", - "user_changed_room_avatar": "قوللانغۇچى مۇنازىرە-خانىدىكى كۆرىنىشىنى ئۆزگەرتتى", - "user_changed_avatar": "قوللانغۇچى كۆرىنىشىنى ئۆزگەرتتى", - "user_changed_display_name": "قوللانغۇچىنىڭ ئىسمى«يېڭى ئىسىمغا» ئۆزگەرتىلدى", - "user_aliased_room": "مۇنازىرە ئۆيىنىڭ ئىسمى ئۆزگەرتىلدى", - "user_created_room": "يېڭى مۇنازىرە ئۆيى قۇرۇلدى", "you": "سىز", "room_powerlevel_change": "{user} دەرىجىسىنى ئۆزگەرتىش {changes}", - "user_changed_guest_access_open": "قوللانغۇچى ئەزالارنىڭ مۇنازىرەخانىغا قوشۇلىشىغا رۇخسەت قىلدى", - "user_changed_guest_access_closed": "قوللانغۇچى ئەزالارنىڭ مۇنازىرەخانىغا قوشۇلۇشتىن رەت قىلىندى", - "user_powerlevel_change_from_to": "قوللانغۇچى بۇرۇنقى دەرىجىسىدىن يېڭى دەرىجىسىگە كۆتۈرىلدى", "scale_image": "كىچىكلەنمە رەسىم", "users_are_typing": "ئەزالىرى يېزىۋاتىدۇ {count}", "user_is_typing": "قوللانغۇچى يېزىۋاتىدۇ", "your_message": "ئۇچۇرىڭىز ...", "replying_to": "{user}", "unread_messages": "ئوقۇلمىغان ئۇچۇرلار", - "user_changed_room_topic": "قوللانغۇچى مۇنازىرەخانىنىڭ تېمىسىنى ئۆزگەرتتى", - "user_changed_room_name": "قوللانغۇچى مۇنازىرەخانىنىڭ ئىسمىنى ئۆزگەرتتى", "room_joinrule_public": "كۆپچىلىك", "room_joinrule_invite": "تەكلىپ قىلىڭ", - "user_changed_join_rules": "قوللانغۇچى مۇنازىرەخانىنى مەلۇم تىپقا ئۆزگەرتتى", "room_history_joined": "ئەزالار قاتناشقاندىن باشلاپ ئوقۇغىلى بولىدۇ", "room_history_invited": "ئەزالار تەكلىپ قىلىنغان ۋاقىتتىن باشلاپ ئوقۇغىلى بولىدۇ", "room_history_shared": "مۇنازىرەخانىدىكى ھەركىم ئوقۇيالايدۇ", - "room_history_world_readable": "ھەركىم ئوقۇيالايدۇ", - "user_changed_room_history": "قوللانغۇچى» مۇنازىرەخانىنىڭ تارىخىنى قۇردى»" + "room_history_world_readable": "ھەركىم ئوقۇيالايدۇ" }, "language_display_name": "ئۇيغۇرچە", "new_room": { @@ -160,7 +144,7 @@ "members": "ئەزالار", "purge": "ئۆينى ئۆچۈرۈڭ", "link_copied": "ئۇلىنىش كۆچۈرۈلدى!", - "copy_link": "تەكلىپ ئۇلانمىسىنى كۆچۈرۈڭ", + "copy_invite_link": "تەكلىپ ئۇلانمىسىنى كۆچۈرۈڭ", "join_public": "ئۇلىنىشى بارلار", "join_invite": "پەقەت كىشىلەر قوشۇلدى", "permissions": "ئىجازەتكە قوشۇلۇڭ", diff --git a/src/assets/translations/zh_Hans.json b/src/assets/translations/zh_Hans.json index 4c767d4..3a55911 100644 --- a/src/assets/translations/zh_Hans.json +++ b/src/assets/translations/zh_Hans.json @@ -29,7 +29,7 @@ "join_invite": "仅添加人员", "permissions": "加入权限", "created_by": "由 {user} 创建", - "copy_link": "复制邀请链接", + "copy_invite_link": "复制邀请链接", "scan_code": "扫一扫加入聊天室", "user_admin": "管理员", "voice_mode": "语音模块", diff --git a/src/components/AudioLayout.vue b/src/components/AudioLayout.vue index 735573e..24b04d9 100644 --- a/src/components/AudioLayout.vue +++ b/src/components/AudioLayout.vue @@ -28,38 +28,53 @@ }} + + +
+ + + + {{ + reaction.member.name.substring(0, 1).toUpperCase() + }} +
{{ reaction.emoji }}
+
+
+
+
{{ eventSenderDisplayName(currentAudioEvent) }}
- {{ formatTime(currentAudioEvent.event.origin_server_ts) }} + {{ formatTimeAgo(currentAudioEvent.event.origin_server_ts) }}
{{ currentTime }} / {{ totalTime }}
-
- + $vuetify.icons.rewind - + + $vuetify.icons.pause_circle $vuetify.icons.play_circle - + $vuetify.icons.forward
- - mic - +
+ 👏 + + mic + +
expand_more
@@ -102,87 +117,46 @@ export default { }, data() { return { - src: null, + REACTION_ANIMATION_TIME: 2500, + info: null, currentAudioEvent: null, autoPlayNextEvent: false, - currentAudioSource: null, - player: null, - duration: 0, - playPercent: 0, - playTime: 0, - playing: false, analyzer: null, analyzerDataArray: null, showReadOnlyToast: false, + reactions: [], + updateReactionsTimer: null, }; }, mounted() { + this.$root.$on('audio-playback-started', this.audioPlaybackStarted); + this.$root.$on('audio-playback-paused', this.audioPlaybackPaused); + this.$root.$on('audio-playback-ended', this.audioPlaybackEnded); + this.$root.$on('audio-playback-reaction', this.audioPlaybackReaction); document.body.classList.add("dark"); - this.$root.$on('playback-start', this.onPlaybackStart); - this.player = this.$refs.player; - this.player.autoplay = false; - this.player.addEventListener("timeupdate", this.updateProgressBar); - this.player.addEventListener("play", () => { - if (!this.analyser) { - - const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); - let audioSource = null; - if (audioCtx) { - audioSource = audioCtx.createMediaElementSource(this.player); - this.analyser = audioCtx.createAnalyser(); - audioSource.connect(this.analyser); - this.analyser.connect(audioCtx.destination); - - this.analyser.fftSize = 128; - const bufferLength = this.analyser.frequencyBinCount; - this.analyzerDataArray = new Uint8Array(bufferLength); - } - } - - - this.playing = true; - this.updateVisualization(); - if (this.currentAudioEvent) { - this.$emit("mark-read", this.currentAudioEvent.getId(), this.currentAudioEvent.getId()); - } - }); - this.player.addEventListener("pause", () => { - this.playing = false; - this.clearVisualization(); - }); - this.player.addEventListener("ended", () => { - this.pause(); - this.playing = false; - this.clearVisualization(); - this.onPlaybackEnd(); - }); + this.$audioPlayer.setAutoplay(false); }, beforeDestroy() { + this.$root.$off('audio-playback-started', this.audioPlaybackStarted); + this.$root.$off('audio-playback-paused', this.audioPlaybackPaused); + this.$root.$off('audio-playback-ended', this.audioPlaybackEnded); + this.$root.$off('audio-playback-reaction', this.audioPlaybackReaction); document.body.classList.remove("dark"); + this.$audioPlayer.removeListener(this._uid); this.currentAudioEvent = null; - this.loadAudioAttachmentSource(); // Release - this.$root.$off('playback-start', this.onPlaybackStart); }, computed: { canRecordAudio() { return !this.$matrix.currentRoomIsReadOnlyForUser && util.browserCanRecordAudio(); }, currentTime() { - return util.formatDuration(this.playTime); + return util.formatDuration(this.info ? this.info.currentTime : 0); + }, + currentTimeMs() { + return this.info ? this.info.currentTime : 0; }, totalTime() { - return util.formatDuration(this.duration); - }, - playheadPercent: { - get: function () { - return this.playPercent; - }, - set: function (percent) { - if (this.player.src) { - this.playPercent = percent; - this.player.currentTime = (percent / 100) * this.player.duration; - } - }, + return util.formatDuration(this.info ? this.info.duration : 0); }, recordingMembersExceptMe() { return this.recordingMembers.filter((member) => { @@ -202,18 +176,14 @@ export default { events: { immediate: true, handler(events, ignoredOldValue) { - console.log("Events changed", this.currentAudioEvent, this.autoPlayNextEvent); if (!this.currentAudioEvent || this.autoPlayNextEvent) { // Make sure all events are decrypted! const eventsBeingDecrypted = events.filter((e) => e.isBeingDecrypted()); if (eventsBeingDecrypted.length > 0) { - console.log("All not decrypted, wait"); Promise.allSettled(eventsBeingDecrypted.map((e) => e.getDecryptionPromise())).then(() => { - console.log("DONE DECRYPTING!") this.loadNext(this.autoPlayNextEvent && this.autoplay); }); } else { - console.log("All decrypted, load next"); this.loadNext(this.autoPlayNextEvent && this.autoplay); } } @@ -222,87 +192,96 @@ export default { currentAudioEvent: { immediate: true, handler(value, oldValue) { - console.log("Current audio derom", value, oldValue); if (value && oldValue && value.getId && oldValue.getId && value.getId() === oldValue.getId()) { - console.log("Ignoring change!!!"); return; } if (!value || !value.getId) { return; } - this.src = null; + + this.clearReactions(); + + this.info = this.$audioPlayer.addListener(this._uid, value); + const autoPlayWasSet = this.autoPlayNextEvent; this.autoPlayNextEvent = false; if (value.getSender() == this.$matrix.currentUserId) { // Sent by us. Don't autoplay if we just sent this (i.e. it is ahead of our read marker) if (this.room && !this.room.getReceiptsForEvent(value).includes(value.getSender())) { - this.player.autoplay = false; + this.$audioPlayer.setAutoplay(false); this.autoPlayNextEvent = autoPlayWasSet; } } - this.loadAudioAttachmentSource(); + this.$audioPlayer.load(value, this.timelineSet); } }, - src: { - immediate: true, - handler(value, ignoredOldValue) { - console.log("Source changed to", value, ignoredOldValue); - } - } }, methods: { play() { - if (this.player.src) { - this.$root.$emit("playback-start", this); - if (this.player.paused) { - this.player.play(); - } else if (this.player.ended) { - // restart - this.player.currentTime = 0; - this.player.play(); - } + if (this.currentAudioEvent) { + this.$audioPlayer.setAutoplay(false); + this.$audioPlayer.play(this.currentAudioEvent, this.timelineSet); } }, pause() { - this.player.autoplay = false; - if (this.player.src) { - this.player.pause(); + this.$audioPlayer.setAutoplay(false); + if (this.currentAudioEvent) { + this.$audioPlayer.pause(this.currentAudioEvent); } }, rewind() { - if (this.player.src) { - this.player.currentTime = Math.max(0, this.player.currentTime - 15); + if (this.currentAudioEvent) { + this.$audioPlayer.seekRelative(this.currentAudioEvent, -15000); } }, forward() { - if (this.player.src) { - this.player.currentTime = Math.min(this.player.duration, this.player.currentTime + 15); + if (this.currentAudioEvent) { + this.$audioPlayer.seekRelative(this.currentAudioEvent, 15000); } }, - updateProgressBar() { - if (this.player.duration > 0) { - this.playPercent = Math.floor( - (100 / this.player.duration) * this.player.currentTime - ); - } else { - this.playPercent = 0; + audioPlaybackStarted() { + if (!this.analyser) { + const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + let audioSource = null; + if (audioCtx) { + audioSource = audioCtx.createMediaElementSource(this.$audioPlayer.getPlayerElement()); + this.analyser = audioCtx.createAnalyser(); + audioSource.connect(this.analyser); + this.analyser.connect(audioCtx.destination); + + this.analyser.fftSize = 128; + const bufferLength = this.analyser.frequencyBinCount; + this.analyzerDataArray = new Uint8Array(bufferLength); + } } - this.playTime = 1000 * this.player.currentTime; - }, - updateDuration() { - this.duration = 1000 * this.player.duration; - }, - onPlaybackStart(item) { - this.player.autoplay = false; - if (item != this && this.playing) { - this.pause(); + this.updateVisualization(); + if (this.currentAudioEvent) { + this.$emit("mark-read", this.currentAudioEvent.getId(), this.currentAudioEvent.getId()); } }, - onPlaybackEnd() { + audioPlaybackPaused() { + this.clearVisualization(); + }, + audioPlaybackEnded() { + this.clearVisualization(); this.loadNext(true && this.autoplay); }, + audioPlaybackReaction(reaction) { + // Play sound! + const audio = new Audio(require("@/assets/sounds/clapping.mp3")); + audio.volume = 0.6; + audio.play(); + + const member = this.room.getMember(reaction.sender); + if (member) { + this.reactions.push(Object.assign({ addedAt: Date.now(), member: member}, reaction)); + if (!this.updateReactionsTimer) { + this.updateReactionsTimer = setInterval(this.updateReactions, 300); + } + } + }, loadPrevious() { const audioMessages = this.events.filter((e) => e.getContent().msgtype === "m.audio"); for (let i = 0; i < audioMessages.length; i++) { @@ -332,11 +311,11 @@ export default { if (e.getId() === this.readMarker) { if (i < (audioMessages.length - 1)) { this.pause(); - this.player.autoplay = autoplay; + this.$audioPlayer.setAutoplay(autoplay); this.currentAudioEvent = audioMessages[i + 1]; } else { this.autoPlayNextEvent = true; - this.player.autoplay = autoplay; + this.$audioPlayer.setAutoplay(autoplay); this.currentAudioEvent = e; this.$emit("loadnext"); } @@ -347,7 +326,7 @@ export default { // No read marker found. Just use the first event here... if (audioMessages.length > 0) { this.pause(); - this.player.autoplay = autoplay; + this.$audioPlayer.setAutoplay(autoplay); this.currentAudioEvent = audioMessages[0]; } return; @@ -358,11 +337,11 @@ export default { if (e.getId() === this.currentAudioEvent.getId()) { if (i < (audioMessages.length - 1)) { this.pause(); - this.player.autoplay = autoplay; + this.$audioPlayer.setAutoplay(autoplay); this.currentAudioEvent = audioMessages[i + 1]; } else { this.autoPlayNextEvent = true; - this.player.autoplay = autoplay; + this.$audioPlayer.setAutoplay(autoplay); this.$emit("loadnext"); } break; @@ -390,8 +369,7 @@ export default { volume.style.height = "" + w + "px"; const color = 80 + (value * (256 - 80)) / 256; volume.style.backgroundColor = `rgb(${color},${color},${color})`; - - if (this.playing) { + if (this.info && this.info.playing) { requestAnimationFrame(this.updateVisualization); } else { this.clearVisualization(); @@ -404,36 +382,24 @@ export default { volume.style.height = "0px"; volume.style.backgroundColor = "transparent"; }, - loadAudioAttachmentSource() { - console.log("loadAUto"); - if (this.src) { - const objectUrl = this.src; - this.src = null; - URL.revokeObjectURL(objectUrl); - } - if (this.currentAudioEvent) { - console.log("Will load"); - if (this.currentAudioSource) { - this.currentAudioSource.reject("Aborted"); - } - this.currentAudioSource = - util - .getAttachment(this.$matrix.matrixClient, this.currentAudioEvent, (progress) => { - this.downloadProgress = progress; - }) - .then((url) => { - console.log("Loaded", url); - this.src = url; - this.currentAudioSource = null; - this.$nextTick(() => { - this.player.load(); - }); - }) - .catch((err) => { - console.log("Failed to fetch attachment: ", err); - }); + updateReactions() { + const now = Date.now(); + this.reactions = this.reactions.filter(r => { + return (r.addedAt + this.REACTION_ANIMATION_TIME > now); + }); + if (this.reactions.length == 0) { + this.clearReactions(); } }, + + clearReactions() { + if (this.updateReactionsTimer) { + clearInterval(this.updateReactionsTimer); + this.updateReactionsTimer = null; + } + this.reactions = []; + }, + memberAvatar(member) { if (member) { return member.getAvatarUrl( @@ -456,6 +422,18 @@ export default { } else { this.$emit('start-recording'); } + }, + + clapButtonClicked() { + if (this.currentAudioEvent) { + this.$emit("sendclap", { event: this.currentAudioEvent, timeOffset: this.currentTimeMs }) + + // Also, play locally + this.audioPlaybackReaction({ + sender: this.$matrix.currentUserId, + emoji: "👏" + }); + } } } }; diff --git a/src/components/BottomSheet.vue b/src/components/BottomSheet.vue index aa43dba..ecdb989 100644 --- a/src/components/BottomSheet.vue +++ b/src/components/BottomSheet.vue @@ -182,7 +182,7 @@ export default { bottom: 0; overflow-x: hidden; overflow-y: hidden; - z-index: 10; + z-index: 20; } .bottom-sheet-bg { diff --git a/src/components/Chat.vue b/src/components/Chat.vue index c587fd1..699aee8 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -1,6 +1,6 @@