From e8f04d79c9c5d049fc94ce8f679726283ba3049a Mon Sep 17 00:00:00 2001 From: N-Pex Date: Wed, 28 May 2025 12:29:04 +0200 Subject: [PATCH] Knock support Also, fix token refresh functionality --- src/assets/css/chat.scss | 6 ++ src/assets/translations/en.json | 12 ++- src/components/Chat.vue | 6 +- src/components/Join.vue | 101 ++++++++++++++--------- src/components/RoomInfo.vue | 119 ++++++++++++++++++++++++++- src/components/RoomList.vue | 26 ++++++ src/components/UserProfileDialog.vue | 4 + src/components/chatMixin.js | 10 ++- src/components/roomInfoMixin.js | 5 +- src/router/index.js | 21 +++-- src/services/matrix.service.js | 75 ++++++++++++----- 11 files changed, 310 insertions(+), 75 deletions(-) diff --git a/src/assets/css/chat.scss b/src/assets/css/chat.scss index 1a2c77e..c69b606 100644 --- a/src/assets/css/chat.scss +++ b/src/assets/css/chat.scss @@ -1015,6 +1015,12 @@ body { margin-left: 6px; } + .member .knock-reason { + margin-left: 38px; + font-size: 0.7em; + color: #aaa; + } + .member .user-power { margin-left: 6px; color: #aaa; diff --git a/src/assets/translations/en.json b/src/assets/translations/en.json index 12feb55..f922d0b 100644 --- a/src/assets/translations/en.json +++ b/src/assets/translations/en.json @@ -48,7 +48,8 @@ "user_make_moderator": "Make moderator", "user_revoke_moderator": "Revoke moderator", "pin": "Pin post", - "unpin": "Unpin post" + "unpin": "Unpin post", + "cancel_knock": "Cancel knock" }, "message": { "you": "You", @@ -138,6 +139,7 @@ "room_history_joined": "People can only see the messages sent after they join.", "join_public": "Anyone can join by opening this link: {link}.", "join_invite": "Only people you invite can join.", + "join_knock": "People can request to join by ´knocking´.", "info_permissions": "You can change ‘join permissions’ at any time in the room settings.", "got_it": "Got it", "no_past_messages": "Welcome! For your security, past messages are not available.", @@ -277,10 +279,14 @@ "joining_as": "You are joining as:", "join": "Join room", "join_user": "Start chat", + "knock": "Knock", + "knock_reason": "Knock reason (optional)", "enter_room": "Enter room", "enter_room_user": "Start chat", + "enter_knock": "Request to join", "status_logging_in": "Logging in...", "status_joining": "Joining room...", + "status_knocking": "Knocking...", "join_failed": "Failed to join room.", "choose_name": "Choose a name to use", "you_have_been_banned": "You have been banned from this room.", @@ -328,11 +334,15 @@ "permissions": "Join Permissions", "join_invite": "Only People Added", "join_public": "Anyone with a link", + "join_knock": "People can ´knock´.", "copy_invite_link": "Copy invite link", "copy_link": "Copy link", "link_copied": "Link copied!", "purge": "Delete room", "members": "Members", + "knocks": "Knocks", + "accept_knock": "Accept", + "reject_knock": "Deny", "user": "{user}", "user_you": "{user} (you)", "hide_all": "Hide", diff --git a/src/components/Chat.vue b/src/components/Chat.vue index f679653..b7289d6 100644 --- a/src/components/Chat.vue +++ b/src/components/Chat.vue @@ -1178,7 +1178,11 @@ export default { this.$navigation.push( { name: "Join", - params: { roomId: util.sanitizeRoomId(this.roomAliasOrId), join: this.$route.params.join }, + params: { + roomId: util.sanitizeRoomId(this.roomAliasOrId), + join: this.$route.params.join + }, + query: this.$route.query }, 0 ); diff --git a/src/components/Join.vue b/src/components/Join.vue index 62c4055..b8ed847 100644 --- a/src/components/Join.vue +++ b/src/components/Join.vue @@ -90,13 +90,22 @@ + + {{ - roomId && roomId.startsWith("@") ? $t("join.enter_room_user") : $t("join.enter_room") + roomId && roomId.startsWith("@") ? $t("join.enter_room_user") : this.roomNeedsKnock ? $t("join.enter_knock") : $t("join.enter_room") }} {{ - roomId && roomId.startsWith("@") ? $t("join.join_user") : $t("join.join") + roomId && roomId.startsWith("@") ? $t("join.join_user") : this.roomNeedsKnock ? $t("join.knock") : $t("join.join") }}
{{ loadingMessage }}
@@ -164,6 +173,20 @@ export default { InteractiveAuth, AuthedImage }, + props: { + roomDisplayName: { + type: String, + default: function () { + return null; + } + }, + roomNeedsKnock: { + type: Boolean, + default: function () { + return false; + } + } + }, data() { return { roomName: null, @@ -178,6 +201,7 @@ export default { showEditDisplaynameDialog: false, showSelectLanguageDialog: false, acceptUA: false, + knockReason: "", }; }, computed: { @@ -233,14 +257,6 @@ export default { let activeLanguages = [...this.getLanguages()]; return activeLanguages.filter((lang) => lang.value === this.$i18n.locale); }, - roomDisplayName() { - // If there is a display name in to invite link, use that! - try { - return new URL(location.href).searchParams.get('roomName'); - } catch(ignoredError) { - return undefined; - } - } }, watch: { roomId: { @@ -312,8 +328,13 @@ export default { this.$nextTick(() => { this.handleJoin(); }); - } - else if (this.roomId.startsWith("#")) { + } else if (this.roomId.startsWith("@")) { + // Direct chat with user + this.waitingForRoomCreation = true; + this.$nextTick(() => { + this.handleJoin(); + }); + } else { this.$matrix .getPublicRoomInfo(this.roomId) .then((room) => { @@ -323,25 +344,18 @@ export default { }) .catch((err) => { console.log("Could not find room info", err); + + // Private room, try to get name + const room = this.$matrix.getRoom(this.roomId); + if (room) { + this.roomName = this.removeHomeServer(room.name || this.roomName); + } else { + this.roomName = this.removeHomeServer(this.roomAliasOrId); + } }) .finally(() => { this.waitingForInfo = false; }); - } else if (this.roomId.startsWith("@")) { - // Direct chat with user - this.waitingForRoomCreation = true; - this.$nextTick(() => { - this.handleJoin(); - }); - } else { - // Private room, try to get name - const room = this.$matrix.getRoom(this.roomId); - if (room) { - this.roomName = this.removeHomeServer(room.name || this.roomName); - } else { - this.roomName = this.removeHomeServer(this.roomAliasOrId); - } - this.waitingForInfo = false; } }, @@ -359,10 +373,6 @@ export default { } }, - handleOpenApp() { - console.log("Open app..."); //TODO - }, - handleJoin() { this.loading = true; this.loadingMessage = this.$t("join.status_logging_in"); @@ -412,6 +422,11 @@ export default { this.$matrix.setCurrentRoomId(room.roomId); return room; }); + } else if (this.roomNeedsKnock) { + console.log("Join: knocking room"); + this.$analytics.event("Invitations", "Room Knocked"); + this.loadingMessage = this.$t("join.status_knocking"); + return this.$matrix.matrixClient.knockRoom(this.roomId, this.knockReason.length > 0 ? { reason: this.knockReason} : undefined); } else { console.log("Join: joining room"); this.$analytics.event("Invitations", "Room Joined"); @@ -423,13 +438,23 @@ export default { this.loading = false; this.loadingMessage = null; this.$nextTick(() => { - this.$navigation.push( - { - name: "Chat", - params: { roomId: util.sanitizeRoomId(room.roomId) }, - }, - -1 - ); + if (this.roomNeedsKnock) { + // For knocks, send to room list + this.$navigation.push( + { + name: "Home", + }, + -1 + ); + } else { + this.$navigation.push( + { + name: "Chat", + params: { roomId: util.sanitizeRoomId(room.roomId) }, + }, + -1 + ); + } }); }) .catch((err) => { diff --git a/src/components/RoomInfo.vue b/src/components/RoomInfo.vue index a2c868a..183b2e7 100644 --- a/src/components/RoomInfo.vue +++ b/src/components/RoomInfo.vue @@ -192,7 +192,7 @@
@@ -236,6 +236,81 @@
+ + + {{ $t("room_info.knocks") }} +
{{ knocks.length }}
+ + + +
+ {{ showAllKnocks ? $t("room_info.hide_all") : $t("room_info.show_all") }} +
+
+
rp.value===retention) this.messageRetentionDisplay = retentionPeriodsFound.text }, - onListItemClick(member) { + onMemberClick(member) { this.activeMember = member this.showMemberActionConfirmation = true }, + onKnockClick(member) { + this.activeMember = member + this.showMemberActionConfirmation = true + }, + acceptKnock(member) { + this.$matrix.answerKnock(member.roomId, member.userId, true, undefined); + }, + rejectKnock(member) { + this.$matrix.answerKnock(member.roomId, member.userId, false, undefined); + }, + onEvent(event) { if (this.room && this.room.roomId == event.getRoomId()) { // For this room @@ -466,8 +559,30 @@ export default { const bName = b.user ? b.user.displayName : b.name; return aName.localeCompare(bName); }); + this.knocks = this.room.getMembersWithMembership("knock").sort((a, b) => { + // Place ourselves at the top! + if (a.userId == myUserId) { + return -1; + } else if (b.userId == myUserId) { + return 1; + } + + // Then sort by power level + if (a.powerLevel > b.powerLevel) { + return -1; + } else if (b.powerLevel > a.powerLevel) { + return 1; + } + + // Then by name + const aName = a.user ? a.user.displayName : a.name; + const bName = b.user ? b.user.displayName : b.name; + return aName.localeCompare(bName); + }); + } else { this.members = []; + this.knocks = []; } }, diff --git a/src/components/RoomList.vue b/src/components/RoomList.vue index 0bdaee6..13a0a97 100644 --- a/src/components/RoomList.vue +++ b/src/components/RoomList.vue @@ -37,6 +37,29 @@ + + + + + {{ room.name }} + {{ room.topic }} + + +