diff --git a/package-lock.json b/package-lock.json index ea8c385..11c5532 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "keanuapp-weblite", - "version": "0.1.21", + "version": "0.1.25", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1441,9 +1441,9 @@ "dev": true }, "@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, "@types/serve-static": { "version": "1.13.10", @@ -2334,7 +2334,7 @@ "another-json": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/another-json/-/another-json-0.2.0.tgz", - "integrity": "sha1-tfQBnJc7bdXGUGotk0acttMq7tw=" + "integrity": "sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==" }, "ansi-colors": { "version": "3.2.4", @@ -2963,7 +2963,7 @@ "browser-request": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz", - "integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=" + "integrity": "sha512-YyNI4qJJ+piQG6MMEuo7J3Bzaqssufx04zpEKYfSrl/1Op59HWali9zMtBpXnkmqMcOuWJPZvudrm9wISmnCbg==" }, "browserify-aes": { "version": "1.2.0", @@ -3081,7 +3081,7 @@ "bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", "requires": { "base-x": "^3.0.2" } @@ -6119,6 +6119,11 @@ } } }, + "file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -6982,6 +6987,11 @@ "queue": "6.0.2" } }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", @@ -7758,6 +7768,17 @@ "verror": "1.10.0" } }, + "jszip": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.0.tgz", + "integrity": "sha512-LDfVtOLtOxb9RXkYOwPyNBTQDL4eUbqahtoY6x07GiDJHwSYvn8sHHIw8wINImV3MqbMNve2gSuM1DDqEKk09Q==", + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -7812,6 +7833,14 @@ "type-check": "~0.4.0" } }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "requires": { + "immediate": "~3.0.5" + } + }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -8023,10 +8052,15 @@ "resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-6.1.0.tgz", "integrity": "sha512-wRJtOo1v1ch+gN8PRsj0IGJznk+kQ8mz13ds/nuhLI+Qyf/931ZlRpd92oq0IRPpZIb+bhX8pRjzIVdcPDKmiQ==" }, + "matrix-events-sdk": { + "version": "0.0.1-beta.7", + "resolved": "https://registry.npmjs.org/matrix-events-sdk/-/matrix-events-sdk-0.0.1-beta.7.tgz", + "integrity": "sha512-9jl4wtWanUFSy2sr2lCjErN/oC8KTAtaeaozJtrgot1JiQcEI4Rda9OLgQ7nLKaqb4Z/QUx/fR3XpDzm5Jy1JA==" + }, "matrix-js-sdk": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-15.2.0.tgz", - "integrity": "sha512-jZOM8Fn86oNvU3zVQcc+JTKKrtYq4ADN6rPZs4Mwxj/X/GDP+2YIP5176GtviF0GM6VO1dcnPZY73ykl8DayjA==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-17.2.0.tgz", + "integrity": "sha512-/IrgHCSVUZNVcKoPO20OF9Xog9X79a1ckmR7FwF5lSTNdmC7eQvU0XcFYCi5IXo57du+im69lEw8dLbPngZhoQ==", "requires": { "@babel/runtime": "^7.12.5", "another-json": "^0.2.0", @@ -8034,6 +8068,7 @@ "bs58": "^4.0.1", "content-type": "^1.0.4", "loglevel": "^1.7.1", + "matrix-events-sdk": "^0.0.1-beta.7", "p-retry": "^4.5.0", "qs": "^6.9.6", "request": "^2.88.2", @@ -8902,11 +8937,11 @@ "dev": true }, "p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "requires": { - "@types/retry": "^0.12.0", + "@types/retry": "0.12.0", "retry": "^0.13.1" } }, @@ -8918,8 +8953,7 @@ "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "parallel-transform": { "version": "1.2.0", @@ -10702,8 +10736,7 @@ "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "progress": { "version": "2.0.3", @@ -10817,9 +10850,9 @@ } }, "qs": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "requires": { "side-channel": "^1.0.4" } @@ -10922,7 +10955,6 @@ "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -10936,14 +10968,12 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, @@ -11599,8 +11629,7 @@ "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, "setprototypeof": { "version": "1.1.1", @@ -12196,7 +12225,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" }, @@ -12204,8 +12232,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, @@ -13051,8 +13078,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { "version": "1.0.1", diff --git a/package.json b/package.json index 53281e8..f563dfa 100644 --- a/package.json +++ b/package.json @@ -16,15 +16,17 @@ "core-js": "^3.6.5", "data-uri-to-buffer": "^3.0.1", "dayjs": "^1.10.3", + "file-saver": "^2.0.5", "fix-webm-duration": "^1.0.0", "image-resize": "^1.1.5", "image-size": "^1.0.0", "intersection-observer": "^0.12", "js-sha256": "^0.9.0", "json-web-key": "^0.4.0", + "jszip": "^3.9.1", "linkifyjs": "3.0.0-beta.3", "material-design-icons-iconfont": "^6.1", - "matrix-js-sdk": "^15.2.0", + "matrix-js-sdk": "^17.2.0", "md-gum-polyfill": "^1.0.0", "mic-recorder-to-mp3": "^2.2.2", "pretty-bytes": "^5.6.0", diff --git a/src/assets/css/_variables.scss b/src/assets/css/_variables.scss index 8e3f8cb..d0f2e67 100644 --- a/src/assets/css/_variables.scss +++ b/src/assets/css/_variables.scss @@ -14,4 +14,6 @@ $chat-button-height: 50px; $voice-recorder-color: #6f6f6f; $voice-recording-color: red; -$voice-recorded-color: #3ae17d; \ No newline at end of file +$voice-recorded-color: #3ae17d; +$poll-hilite-color: #6360f0; +$poll-hilite-color-bg: #d6d5fc; \ No newline at end of file diff --git a/src/assets/css/chat.scss b/src/assets/css/chat.scss index df5edc0..ef7a386 100644 --- a/src/assets/css/chat.scss +++ b/src/assets/css/chat.scss @@ -119,7 +119,7 @@ $admin-fg: white; padding: 10px; background-color: #f2f2f2; } - + .chat-content { margin: 0; padding-top: $chat-standard-padding-s; @@ -596,16 +596,9 @@ $admin-fg: white; position: absolute; width: fit-content; background-color: white; - height: 44px; + height: 34px; border-radius: 22px; box-shadow: 4px 4px 8px rgba(0,0,0,0.15); - // &.incoming { - // right: 30%; - // } - // &.outgoing { - // left: unset !important; - // right: 10px !important; - // } } .avatar-operations { @@ -618,6 +611,10 @@ $admin-fg: white; box-shadow: 4px 4px 8px rgba(0,0,0,0.15); } +.send-options { + z-index: 11; // Above mic button +} + .message-operations-picker { background-color: white; text-align: center; @@ -1140,4 +1137,9 @@ $admin-fg: white; .loading-indicator { position: absolute; background-color: rgba(0, 0, 0, 0.2); +} + +.exporting-indicator { + position: absolute; + background-color: white; } \ No newline at end of file diff --git a/src/assets/css/components/_poll.scss b/src/assets/css/components/_poll.scss new file mode 100644 index 0000000..948bb65 --- /dev/null +++ b/src/assets/css/components/_poll.scss @@ -0,0 +1,116 @@ +.poll-bubble { + width: 70%; +} + +.poll-bubble { + color: black; + padding: $chat-standard-padding-s !important; + font-family: "Inter", sans-serif; + font-size: 16 * $chat-text-size; + line-height: 16 * $chat-text-size; +} + +.from-admin .poll-bubble { + color: rgba(white, 0.9); +} + +.poll-icon { + path { + fill: currentColor; + } +} + +.poll-check-icon { + width: 14.18px; + height: 12px; +} + +.poll-question { + font-weight: 700; + margin-top: $chat-standard-padding-xs; + margin-bottom: $chat-standard-padding-s; +} + +.poll-answer { + border: 1px solid currentColor; + border-radius: 4px; + padding: 15px 14px; + margin: 0px; + &.winner { + font-weight: 700; + } + &.selected { + border: 1px solid $poll-hilite-color; + background-color: $poll-hilite-color-bg; + color: #1d1d1d; + font-weight: 700; + } + &.result { + border: none; + padding: 15px 0px; + } + .poll-answer-title { + } + .poll-answer-num-votes { + font-size: 0.75rem; + } + justify-content: space-between; + position: relative; +} + +.poll-percent-indicator { + position: absolute; + bottom: 2px; + left: 0px; + right: 0px; + height: 8px; + margin-top: 4px; + .bar { + background-color: #7e7cf8; + position: absolute; + bottom: 0px; + left: 0px; + top: 0px; + border-radius: 4px; + } +} + +.poll-status { + justify-content: space-between; + font-size: 13px; + line-height: 117%; + margin: 0px; + .poll-status-title { + } + + .poll-status-close { + color: $poll-hilite-color; + } +} + +.poll-submit { + .v-btn { + font-family: "Inter", sans-serif; + font-weight: 700; + font-size: 11 * $chat-text-size; + color: white; + text-transform: uppercase; + background-color: $poll-hilite-color !important; + border: 1px solid black; + border-radius: 21px !important; + height: 42px !important; + margin-top: $chat-standard-padding-xs; + margin-bottom: $chat-standard-padding-xs; + } +} + +// Creation dialog +// +.poll-create-dialog-content { + max-height: 50vh; + overflow-x: hidden; + overflow-y: auto; +} +.poll-create-status { + font-size: 0.7rem; +} diff --git a/src/assets/css/join.scss b/src/assets/css/join.scss index ab1d755..b9a0d0a 100644 --- a/src/assets/css/join.scss +++ b/src/assets/css/join.scss @@ -37,12 +37,6 @@ background: white; box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.08); - .join-user-info { - display: flex; - flex-wrap: nowrap; - max-width: 500px; - } - @media #{map-get($display-breakpoints, 'sm-and-down')} { padding: 20px; } diff --git a/src/assets/css/vendors/_v-emoji-picker.scss b/src/assets/css/vendors/_v-emoji-picker.scss index 469cb39..7266c15 100644 --- a/src/assets/css/vendors/_v-emoji-picker.scss +++ b/src/assets/css/vendors/_v-emoji-picker.scss @@ -1,6 +1,7 @@ #EmojiPicker { width: 100%; background-color: #ffffff; + margin-top: 15px; .container-emoji { height: 60vh; diff --git a/src/assets/icons/addReaction.vue b/src/assets/icons/addReaction.vue new file mode 100644 index 0000000..b6385d8 --- /dev/null +++ b/src/assets/icons/addReaction.vue @@ -0,0 +1,6 @@ + diff --git a/src/assets/icons/ic_check.svg b/src/assets/icons/ic_check.svg new file mode 100644 index 0000000..229191f --- /dev/null +++ b/src/assets/icons/ic_check.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/ic_poll.svg b/src/assets/icons/ic_poll.svg new file mode 100644 index 0000000..4e711d5 --- /dev/null +++ b/src/assets/icons/ic_poll.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/translations/bo.json b/src/assets/translations/bo.json index 9267c66..fdc284a 100644 --- a/src/assets/translations/bo.json +++ b/src/assets/translations/bo.json @@ -69,7 +69,8 @@ "new_room": "ཁ་བརྡ་ཁང་གསར་པ།", "name_room": "ཁ་བརྡ་ཁང་ལ་མིང་ཐོགས།", "room_topic": "གལ་ཏེ་འདོད་པ་ཡོད་ན། ཚོགས་པའི་སྐོར་གྱི་འགྲེལ་བཤད་ཐུང་ངུ་ཞིག་འབྲི་ཆོག", - "create": "བཟོས།" + "create": "བཟོས།", + "room_name_limit_error_msg": "" }, "menu": { "logout": "ཕྱིར་ཐོན།", @@ -222,7 +223,8 @@ "remember_me": "ང་དྲན་པར་བྱོས།", "user_name_label": "སྤྱོད་མིང་།", "title": "ཁྱེད་རང་ནང་དུ་ཞུགས་པར་དགའ་བསུ་ཞུ།", - "join_failed": "ཁ་བརྡ་ཁང་དུ་འཛུལ་ཐུབ་མ་སོང་།" + "join_failed": "ཁ་བརྡ་ཁང་དུ་འཛུལ་ཐུབ་མ་སོང་།", + "choose_name": "" }, "profile_info_popup": { "powered_by": "ཁ་བརྡ་ཁང་འདི་{product} ནུས་ཤུགས་བསྩལ་ཡོད། {productLink} ནས་དེ་ལས་མང་བ་སྦྱོང་ཆོག་ལ། མདུན་དུ་བསྐྱོད་དེ་ཁ་བརྡ་ཁང་གཞན་ཞིག་བསྐྲུན་ཆོག", diff --git a/src/assets/translations/de.json b/src/assets/translations/de.json index f0ec7fd..4a6e776 100644 --- a/src/assets/translations/de.json +++ b/src/assets/translations/de.json @@ -94,7 +94,8 @@ "create": "Erstellen", "next": "Nächste", "name_room": "Raum benennen", - "room_topic": "Füge eine Beschreibung hinzu, wenn du möchtest" + "room_topic": "Füge eine Beschreibung hinzu, wenn du möchtest", + "room_name_limit_error_msg": "" }, "device_list": { "title": "GERÄTE", @@ -144,7 +145,8 @@ "status_logging_in": "Wird angemeldet …", "status_joining": "Raum beitreten …", "join_failed": "Beitritt zum Raum fehlgeschlagen.", - "title": "Willkommen in {roomName}" + "title": "Willkommen in {roomName}", + "choose_name": "" }, "invite": { "title": "Freunde hinzufügen", diff --git a/src/assets/translations/en.json b/src/assets/translations/en.json index a5a28ea..45a13bb 100644 --- a/src/assets/translations/en.json +++ b/src/assets/translations/en.json @@ -90,7 +90,7 @@ "new_room": "New Room", "create": "Create", "next": "Next", - "name_room": "Name room", + "name_room": "Room name", "room_topic": "Add a description if you like", "join_permissions": "Join permissions", "set_join_permissions": "Set Join Permissions", @@ -104,7 +104,8 @@ "invite_description": "Choose from a list or search by account ID", "status_creating": "Creating room", "status_avatar_total": "Uploading avatar: {count} of {total}", - "status_avatar": "Uploading avatar: {count}" + "status_avatar": "Uploading avatar: {count}", + "room_name_limit_error_msg": "Maximum 50 characters allowed" }, "device_list": { "title": "DEVICES", @@ -158,7 +159,8 @@ "enter_room": "Enter room", "status_logging_in": "Logging in...", "status_joining": "Joining room...", - "join_failed": "Failed to join room." + "join_failed": "Failed to join room.", + "choose_name": "Choose a name to use" }, "invite": { "title": "Add Friends", @@ -208,7 +210,8 @@ "show_all": "Show all >", "leave_room": "Leave", "version_info": "Powered by Guardian Project. Version: {version}", - "scan_code": "Scan to join the room" + "scan_code": "Scan to join the room", + "export_room": "Export chat" }, "room_info_sheet": { "this_room": "This room", @@ -233,5 +236,34 @@ "video_file": "Video file", "original_text": "", "download_name": "Download" + }, + "poll_create": { + "title": "Create poll", + "intro": "Please fill in details below.", + "create": "Create", + "creating": "Creating poll", + "poll_disclosed": "Open - current results are shown at all times.", + "poll_undisclosed": "Closed - users will see the results when poll is closed.", + "add_answer": "Add answer", + "failed": "Failed to create poll, please try again later.", + "question_label": "Type your question here", + "question_required": "You need to enter a question!", + "answer_label": "Answer no {index}", + "answer_required": "Answer can't be empty. Please enter some text or remove this option.", + "create_poll_menu_option": "Create poll", + "poll_status_closed": "Poll is closed", + "poll_status_disclosed": "Results will be shown when poll is closed.", + "poll_status_open": "Poll is open", + "poll_status_open_not_voted": "Poll is open - vote to see the results", + "close_poll": "Close poll", + "poll_submit": "Submit", + "num_answered": "{count} have answered" + }, + "export": { + "exported_date": "Exported on {date}", + "fetched_n_events": "Fetched {count} events", + "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}" } } diff --git a/src/assets/translations/es.json b/src/assets/translations/es.json index 44efa99..b4b178b 100644 --- a/src/assets/translations/es.json +++ b/src/assets/translations/es.json @@ -63,7 +63,8 @@ "remember_me": "Recordarme", "user_name_label": "Nombre de usuario", "title": "Bienvenido has sido invitado a unirte", - "join_failed": "No se pudo unir a la sala." + "join_failed": "No se pudo unir a la sala.", + "choose_name": "" }, "profile": { "display_name": "Nombre para mostrar", @@ -117,7 +118,8 @@ "done": "Listo", "new_room": "Nueva Sala", "create": "Crear", - "room_topic": "Añade una descripción si quieres" + "room_topic": "Añade una descripción si quieres", + "room_name_limit_error_msg": "" }, "room_welcome": { "join_public": "Cualquiera puede unirse abriendo este vínculo: {link}", diff --git a/src/assets/translations/fi.json b/src/assets/translations/fi.json index 79691d9..faa21ea 100644 --- a/src/assets/translations/fi.json +++ b/src/assets/translations/fi.json @@ -27,7 +27,8 @@ "room_topic": "Lisää kuvaus, jos haluat", "add_people": "Lisää ihmisiä", "link_copied": "Linkki kopioitu!", - "public_info": "Kuka tahansa, jolla on linkki" + "public_info": "Kuka tahansa, jolla on linkki", + "room_name_limit_error_msg": "" }, "purge_room": { "n_seconds": "{seconds} sekuntia", @@ -72,7 +73,8 @@ "user_name_label": "Käyttäjätunnus", "status_joining": "Liittyminen huoneeseen…", "status_logging_in": "Kirjautuminen sisään…", - "join_failed": "Huoneeseen liittyminen epäonnistui." + "join_failed": "Huoneeseen liittyminen epäonnistui.", + "choose_name": "" }, "leave": { "title_public": "Näkemiin, {user}", diff --git a/src/assets/translations/fr.json b/src/assets/translations/fr.json index 4349670..79b2a50 100644 --- a/src/assets/translations/fr.json +++ b/src/assets/translations/fr.json @@ -94,7 +94,8 @@ "get_link": "Obtenir le lien", "public_info": "Quiconque avec un lien", "join_permissions_info": "Ces autorisations déterminent comment les personnes peuvent rejoindre le salon et avec quelle facilité d’autres personnes peuvent être invitées. Elles peuvent être modifiées à tout moment.", - "status_creating": "Création du salon" + "status_creating": "Création du salon", + "room_name_limit_error_msg": "" }, "device_list": { "title": "APPAREILS", @@ -144,7 +145,8 @@ "status_joining": "Adhésion au salon…", "join_failed": "Impossible de rejoindre le salon.", "joining_as": "Vous rejoignez en tant que :", - "join_guest": "Rejoindre comme invité·e" + "join_guest": "Rejoindre comme invité·e", + "choose_name": "" }, "invite": { "title": "Ajouter des amis", diff --git a/src/assets/translations/it.json b/src/assets/translations/it.json index 9c53650..ef969aa 100644 --- a/src/assets/translations/it.json +++ b/src/assets/translations/it.json @@ -93,7 +93,8 @@ "new_room": "Nuova stanza", "invite_info": "Solo le persone aggiunte", "join_permissions_info": "Questi permessi determinano come le persone possono entrare nella stanza e quanto facilmente gli altri possono essere invitati. Possono essere cambiati in qualsiasi momento.", - "public_info": "Chiunque abbia un collegamento" + "public_info": "Chiunque abbia un collegamento", + "room_name_limit_error_msg": "" }, "device_list": { "title": "DISPOSITIVI", @@ -143,7 +144,8 @@ "join_guest": "Unisciti come ospite", "status_joining": "Unendosi alla stanza…", "join_failed": "Impossibile unirsi alla stanza.", - "status_logging_in": "Accesso in corso…" + "status_logging_in": "Accesso in corso…", + "choose_name": "" }, "invite": { "title": "Aggiungi amici", diff --git a/src/assets/translations/nb_NO.json b/src/assets/translations/nb_NO.json index a182382..9f14738 100644 --- a/src/assets/translations/nb_NO.json +++ b/src/assets/translations/nb_NO.json @@ -75,7 +75,8 @@ "status_joining": "Tar del i rom…", "status_logging_in": "Logger inn …", "enter_room": "", - "title": "Velkommen til {roomName}" + "title": "Velkommen til {roomName}", + "choose_name": "" }, "profile_info_popup": { "identity_temporary": "{displayName}", @@ -113,7 +114,8 @@ "link_copied": "Lenke kopiert.", "next": "Neste", "create": "Opprett", - "new_room": "Nytt rom" + "new_room": "Nytt rom", + "room_name_limit_error_msg": "" }, "room_welcome": { "room_history_is": "Romhistorikken er {type}.", diff --git a/src/assets/translations/pt_BR.json b/src/assets/translations/pt_BR.json index f816029..c24a0d1 100644 --- a/src/assets/translations/pt_BR.json +++ b/src/assets/translations/pt_BR.json @@ -117,7 +117,8 @@ "invite_description": "Escolha numa lista ou busque pelo ID da conta", "status_creating": "Criando a sala", "status_avatar_total": "Enviando o avatar: {count} de {total}", - "status_avatar": "Enviando avatar: {count}" + "status_avatar": "Enviando avatar: {count}", + "room_name_limit_error_msg": "" }, "device_list": { "title": "DISPOSITIVOS", @@ -171,7 +172,8 @@ "enter_room": "Entre na sala", "status_logging_in": "Fazendo login...", "status_joining": "Entrando na sala...", - "join_failed": "Houve uma falha ao entrar na sala." + "join_failed": "Houve uma falha ao entrar na sala.", + "choose_name": "" }, "leave": { "title_public": "Adeus, {user}", diff --git a/src/assets/translations/ro.json b/src/assets/translations/ro.json index bccfe04..b4209f4 100644 --- a/src/assets/translations/ro.json +++ b/src/assets/translations/ro.json @@ -99,7 +99,8 @@ "joining_as": "Vă înscrieți ca:", "remember_me": "Amintește-ți de mine", "user_name_label": "Numele utilizatorului", - "title": "Bine ați venit, ați fost invitat să vă alăturați" + "title": "Bine ați venit, ați fost invitat să vă alăturați", + "choose_name": "" }, "profile_info_popup": { "new_room": "+ Cameră nouă", @@ -162,7 +163,8 @@ "name_room": "Nume cameră", "next": "Următorul", "create": "Creați", - "new_room": "Cameră nouă" + "new_room": "Cameră nouă", + "room_name_limit_error_msg": "" }, "room_welcome": { "got_it": "L-am prins", diff --git a/src/assets/translations/ug.json b/src/assets/translations/ug.json index f985be0..b8e401e 100644 --- a/src/assets/translations/ug.json +++ b/src/assets/translations/ug.json @@ -83,7 +83,8 @@ "name_room": "مۇنازىرەخانىغا ئىسىم قويۇڭ", "next": "كېيىنكى", "create": "قۇرۇش", - "new_room": "يېڭى مۇنازىرەخانا" + "new_room": "يېڭى مۇنازىرەخانا", + "room_name_limit_error_msg": "" }, "room": { "purge_failed": "مۇنازىرەخانىنى يۇيۇش مەغلۇب بولدى!", @@ -114,7 +115,8 @@ "joining_as": "سىز تۆۋەندىكىدەك قاتنىشىۋاتىسىز:", "remember_me": "", "user_name_label": "قوللانغۇچى ئىسمى", - "title": "{ياتاق ئىسمى} غا خۇش كەپسىز" + "title": "{ياتاق ئىسمى} غا خۇش كەپسىز", + "choose_name": "" }, "room_welcome": { "info_permissions": "ياتاق تەڭشىكىدە خالىغان ۋاقىتتا «قوشۇلۇش ئىجازەتنامىسى» نى ئۆزگەرتەلەيسىز.", diff --git a/src/assets/translations/zh_Hans.json b/src/assets/translations/zh_Hans.json index a5afc2b..5b0a8ef 100644 --- a/src/assets/translations/zh_Hans.json +++ b/src/assets/translations/zh_Hans.json @@ -174,7 +174,8 @@ "remember_me": "记得我", "user_name_label": "用户名", "title": "欢迎您被邀请加入", - "join_failed": "加入聊天室失败。" + "join_failed": "加入聊天室失败。", + "choose_name": "" }, "profile": { "display_name": "显示名称", @@ -211,7 +212,8 @@ "done": "完毕", "new_room": "新的聊天室", "room_topic": "如果您愿意,请添加说明", - "create": "创建" + "create": "创建", + "room_name_limit_error_msg": "" }, "room_welcome": { "got_it": "知道了", diff --git a/src/components/ActionRow.vue b/src/components/ActionRow.vue index 80f82ec..8ba0907 100644 --- a/src/components/ActionRow.vue +++ b/src/components/ActionRow.vue @@ -34,4 +34,4 @@ export default { \ No newline at end of file + \ No newline at end of file diff --git a/src/components/Chat.vue b/src/components/Chat.vue index a86caf2..abdf012 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -1,12 +1,9 @@ \ No newline at end of file + diff --git a/src/components/ChatHeader.vue b/src/components/ChatHeader.vue index 6bb07e3..79cfb91 100644 --- a/src/components/ChatHeader.vue +++ b/src/components/ChatHeader.vue @@ -7,7 +7,7 @@ @click.stop="onHeaderClicked" > - + diff --git a/src/components/CreatePollDialog.vue b/src/components/CreatePollDialog.vue new file mode 100644 index 0000000..8decf7b --- /dev/null +++ b/src/components/CreatePollDialog.vue @@ -0,0 +1,195 @@ + + + + diff --git a/src/components/CreateRoom.vue b/src/components/CreateRoom.vue index a75836d..a0afa15 100644 --- a/src/components/CreateRoom.vue +++ b/src/components/CreateRoom.vue @@ -20,7 +20,7 @@ !roomName || (step != steps.INITIAL && step != steps.CREATED) " class="header-button-right" - @click.stop="next" + @click.stop="onCreate" > {{ step == steps.CREATED ? $t("new_room.done") : $t("new_room.next") @@ -28,54 +28,6 @@ --> - @@ -86,34 +38,49 @@ - - + + +
{{ $t("new_room.name_room") }}
+
{{ $t("new_room.room_topic") }}
{{ $t("new_room.create") }} + @click.stop="onCreate" + :disabled="status ? true : roomName.length === 0 || roomName.length > 50" + > +
+ {{ status }} + +
+ {{ $t("new_room.create") }} +
@@ -192,7 +159,7 @@ {{ $t("new_room.link_copied") }} --> -
+ + + + + + +
{{ $t("join.choose_name") }}
+ + + + +
+ + + + + +
+ + + + + + + {{ $t("join.enter_room") }} + +
+
+
diff --git a/src/components/RoomInfo.vue b/src/components/RoomInfo.vue index 556907b..ab1c4d6 100644 --- a/src/components/RoomInfo.vue +++ b/src/components/RoomInfo.vue @@ -153,7 +153,7 @@ }) }}
-
Start private chat
+
{{ $t("menu.start_private_chat") }}
+ +
+ {{ $t("room_info.export_room") }} +
+ + +
+ {{ $t("room_info.purge") }} +
+
{{ $t("room_info.version_info", { version: buildVersion }) }}
@@ -177,14 +201,23 @@ @close="showLeaveConfirmation = false" /> + + + diff --git a/src/components/RoomInfoBottomSheet.vue b/src/components/RoomInfoBottomSheet.vue index aa10dce..086749e 100644 --- a/src/components/RoomInfoBottomSheet.vue +++ b/src/components/RoomInfoBottomSheet.vue @@ -5,12 +5,30 @@ >
- - + + {{ roomName.substring(0, 1).toUpperCase() }} + + + {{ loadValue }} +
{{$t('room_info_sheet.this_room')}}
{{ roomName }}
diff --git a/src/components/RoomList.vue b/src/components/RoomList.vue index b78de3a..5010a7c 100644 --- a/src/components/RoomList.vue +++ b/src/components/RoomList.vue @@ -18,7 +18,10 @@ :value="room.roomId" > - + + {{ + room.name.substring(0, 1).toUpperCase() + }} {{ room.name }} @@ -50,7 +53,10 @@ :value="room.roomId" > - + + {{ + room.name.substring(0, 1).toUpperCase() + }}
{{ notificationCount(room) }} diff --git a/src/components/VoiceRecorder.vue b/src/components/VoiceRecorder.vue index acd4251..d1debf6 100644 --- a/src/components/VoiceRecorder.vue +++ b/src/components/VoiceRecorder.vue @@ -233,6 +233,7 @@ export default { this.state = State.INITIAL; this.errorMessage = null; this.recordedFile = null; + this.recordingTime = String.fromCharCode(160); if (this.ptt) { document.addEventListener("mouseup", this.mouseUp, false); document.addEventListener("mousemove", this.mouseMove, false); diff --git a/src/components/chatMixin.js b/src/components/chatMixin.js new file mode 100644 index 0000000..c8d5356 --- /dev/null +++ b/src/components/chatMixin.js @@ -0,0 +1,247 @@ +import util from "../plugins/utils"; +import MessageIncomingText from "./messages/MessageIncomingText"; +import MessageIncomingFile from "./messages/MessageIncomingFile"; +import MessageIncomingImage from "./messages/MessageIncomingImage.vue"; +import MessageIncomingAudio from "./messages/MessageIncomingAudio.vue"; +import MessageIncomingVideo from "./messages/MessageIncomingVideo.vue"; +import MessageIncomingSticker from "./messages/MessageIncomingSticker.vue"; +import MessageIncomingPoll from "./messages/MessageIncomingPoll.vue"; +import MessageOutgoingText from "./messages/MessageOutgoingText"; +import MessageOutgoingFile from "./messages/MessageOutgoingFile"; +import MessageOutgoingImage from "./messages/MessageOutgoingImage.vue"; +import MessageOutgoingAudio from "./messages/MessageOutgoingAudio.vue"; +import MessageOutgoingVideo from "./messages/MessageOutgoingVideo.vue"; +import MessageOutgoingSticker from "./messages/MessageOutgoingSticker.vue"; +import MessageOutgoingPoll from "./messages/MessageOutgoingPoll.vue"; +import MessageIncomingImageExport from "./messages/export/MessageIncomingImageExport"; +import MessageIncomingAudioExport from "./messages/export/MessageIncomingAudioExport"; +import MessageIncomingVideoExport from "./messages/export/MessageIncomingVideoExport"; +import MessageOutgoingImageExport from "./messages/export/MessageOutgoingImageExport"; +import MessageOutgoingAudioExport from "./messages/export/MessageOutgoingAudioExport"; +import MessageOutgoingVideoExport from "./messages/export/MessageOutgoingVideoExport"; +import ContactJoin from "./messages/ContactJoin.vue"; +import ContactLeave from "./messages/ContactLeave.vue"; +import ContactInvited from "./messages/ContactInvited.vue"; +import ContactChanged from "./messages/ContactChanged.vue"; +import RoomCreated from "./messages/RoomCreated.vue"; +import RoomAliased from "./messages/RoomAliased.vue"; +import RoomNameChanged from "./messages/RoomNameChanged.vue"; +import RoomTopicChanged from "./messages/RoomTopicChanged.vue"; +import RoomAvatarChanged from "./messages/RoomAvatarChanged.vue"; +import RoomHistoryVisibility from "./messages/RoomHistoryVisibility.vue"; +import MessageOperations from "./messages/MessageOperations.vue"; +import AvatarOperations from "./messages/AvatarOperations.vue"; +import ChatHeader from "./ChatHeader"; +import VoiceRecorder from "./VoiceRecorder"; +import RoomInfoBottomSheet from "./RoomInfoBottomSheet"; +import CreatedRoomWelcomeHeader from "./CreatedRoomWelcomeHeader"; +import MessageOperationsBottomSheet from "./MessageOperationsBottomSheet"; +import stickers from "../plugins/stickers"; +import StickerPickerBottomSheet from "./StickerPickerBottomSheet"; +import BottomSheet from "./BottomSheet.vue"; +import CreatePollDialog from "./CreatePollDialog.vue"; +import RoomJoinRules from "./messages/RoomJoinRules.vue"; +import RoomPowerLevelsChanged from "./messages/RoomPowerLevelsChanged.vue"; +import RoomGuestAccessChanged from "./messages/RoomGuestAccessChanged.vue"; +import RoomEncrypted from "./messages/RoomEncrypted.vue"; +import RoomDeletionNotice from "./messages/RoomDeletionNotice.vue"; +import DebugEvent from "./messages/DebugEvent.vue"; + +export default { + components: { + ChatHeader, + MessageIncomingText, + MessageIncomingFile, + MessageIncomingImage, + MessageIncomingAudio, + MessageIncomingVideo, + MessageIncomingSticker, + MessageOutgoingText, + MessageOutgoingFile, + MessageOutgoingImage, + MessageOutgoingAudio, + MessageOutgoingVideo, + MessageOutgoingSticker, + MessageOutgoingPoll, + ContactJoin, + ContactLeave, + ContactInvited, + ContactChanged, + RoomCreated, + RoomAliased, + RoomNameChanged, + RoomTopicChanged, + RoomAvatarChanged, + RoomHistoryVisibility, + RoomJoinRules, + RoomPowerLevelsChanged, + RoomGuestAccessChanged, + RoomEncrypted, + RoomDeletionNotice, + DebugEvent, + MessageOperations, + VoiceRecorder, + RoomInfoBottomSheet, + CreatedRoomWelcomeHeader, + MessageOperationsBottomSheet, + StickerPickerBottomSheet, + BottomSheet, + AvatarOperations, + CreatePollDialog, + }, + methods: { + showDayMarkerBeforeEvent(event) { + const idx = this.events.indexOf(event); + if (idx <= 0) { + return true; + } + const previousEvent = this.events[idx - 1]; + return util.dayDiff(previousEvent.getTs(), event.getTs()) > 0; + }, + + dayForEvent(event) { + let dayDiff = util.dayDiffToday(event.getTs()); + if (dayDiff < 7) { + return this.$tc("message.time_ago", dayDiff); + } else { + return util.formatDay(event.getTs()); + } + }, + + dateForEvent(event) { + return util.formatDay(event.getTs()); + }, + + componentForEvent(event, isForExport = false) { + switch (event.getType()) { + case "m.room.member": + if (event.getContent().membership == "join") { + if (event.getPrevContent() && event.getPrevContent().membership == "join") { + // We we already joined, so this must be a display name and/or avatar update! + return ContactChanged; + } else { + return ContactJoin; + } + } else if (event.getContent().membership == "leave") { + return ContactLeave; + } else if (event.getContent().membership == "invite") { + return ContactInvited; + } + break; + + case "m.room.message": + if (event.getSender() != this.$matrix.currentUserId) { + if (event.getContent().msgtype == "m.image") { + // For SVG, make downloadable + if ( + event.getContent().info && + event.getContent().info.mimetype && + event.getContent().info.mimetype.startsWith("image/svg") + ) { + return MessageIncomingFile; + } + if (isForExport) { + return MessageIncomingImageExport; + } + return MessageIncomingImage; + } else if (event.getContent().msgtype == "m.audio") { + if (isForExport) { + return MessageIncomingAudioExport; + } + return MessageIncomingAudio; + } else if (event.getContent().msgtype == "m.video") { + if (isForExport) { + return MessageIncomingVideoExport; + } + return MessageIncomingVideo; + } else if (event.getContent().msgtype == "m.file") { + return MessageIncomingFile; + } else if (stickers.isStickerShortcode(event.getContent().body)) { + return MessageIncomingSticker; + } + return MessageIncomingText; + } else { + if (event.getContent().msgtype == "m.image") { + // For SVG, make downloadable + if ( + event.getContent().info && + event.getContent().info.mimetype && + event.getContent().info.mimetype.startsWith("image/svg") + ) { + return MessageOutgoingImage; + } + if (isForExport) { + return MessageOutgoingImageExport; + } + return MessageOutgoingImage; + } else if (event.getContent().msgtype == "m.audio") { + if (isForExport) { + return MessageOutgoingAudioExport; + } + return MessageOutgoingAudio; + } else if (event.getContent().msgtype == "m.video") { + if (isForExport) { + return MessageOutgoingVideoExport; + } + return MessageOutgoingVideo; + } else if (event.getContent().msgtype == "m.file") { + return MessageOutgoingFile; + } else if (stickers.isStickerShortcode(event.getContent().body)) { + return MessageOutgoingSticker; + } + return MessageOutgoingText; + } + + case "m.room.create": + return RoomCreated; + + case "m.room.canonical_alias": + return RoomAliased; + + case "m.room.name": + return RoomNameChanged; + + case "m.room.topic": + return RoomTopicChanged; + + case "m.room.avatar": + return RoomAvatarChanged; + + case "m.room.history_visibility": + return RoomHistoryVisibility; + + case "m.room.join_rules": + return RoomJoinRules; + + case "m.room.power_levels": + return RoomPowerLevelsChanged; + + case "m.room.guest_access": + return RoomGuestAccessChanged; + + case "m.room.encryption": + return RoomEncrypted; + + case "m.poll.start": + case "org.matrix.msc3381.poll.start": + if (event.getSender() != this.$matrix.currentUserId) { + return MessageIncomingPoll; + } else { + return MessageOutgoingPoll; + } + + case "im.keanu.room_deletion_notice": { + // Custom event for notice 30 seconds before a room is deleted/purged. + const deletionNotices = this.room.currentState.getStateEvents("im.keanu.room_deletion_notice"); + if (deletionNotices && deletionNotices.length > 0 && deletionNotices[deletionNotices.length - 1] == event) { + // This is the latest/last one. Look at the status flag. Show nothing if it is "cancel". + if (event.getContent().status != "cancel") { + return RoomDeletionNotice; + } + } + } + } + return this.debugging ? DebugEvent : null; + }, + }, +}; diff --git a/src/components/messages/MessageIncomingPoll.vue b/src/components/messages/MessageIncomingPoll.vue new file mode 100644 index 0000000..2b956a3 --- /dev/null +++ b/src/components/messages/MessageIncomingPoll.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/src/components/messages/MessageOperations.vue b/src/components/messages/MessageOperations.vue index 75429a2..20d53a6 100644 --- a/src/components/messages/MessageOperations.vue +++ b/src/components/messages/MessageOperations.vue @@ -1,16 +1,26 @@