From e2419dc75b39647c352a5f21aac5dba5b7ced354 Mon Sep 17 00:00:00 2001 From: Dariusz Niemczyk Date: Thu, 26 Aug 2021 12:41:29 +0200 Subject: [PATCH 1/8] Make stronger background blur for light theme Fixes https://github.com/vector-im/element-web/issues/18708 --- res/themes/light/css/_light.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index 200d5bb12a..96e5fd7155 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -354,7 +354,7 @@ $appearance-tab-border-color: $input-darker-bg-color; // blur amounts for left left panel (only for element theme) :root { - --lp-background-blur: 30px; + --lp-background-blur: 40px; } $composer-shadow-color: rgba(0, 0, 0, 0.04); From d3ba33172b8e195233528eb991c0bd0f9d2f0bac Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 31 Aug 2021 16:42:21 +0100 Subject: [PATCH 2/8] Only make the initial space rooms suggested by default --- src/components/structures/SpaceRoomView.tsx | 1 + src/createRoom.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 767e0999c3..5c9662dcf7 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -517,6 +517,7 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => { andView: false, inlineErrors: true, parentSpace: space, + suggested: true, }); })); onFinished(filteredRoomNames.length > 0); diff --git a/src/createRoom.ts b/src/createRoom.ts index 31774bf56f..25e7257289 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -62,6 +62,8 @@ export interface IOpts { roomType?: RoomType | string; historyVisibility?: HistoryVisibility; parentSpace?: Room; + // contextually only makes sense if parentSpace is specified, if true then will be added to parentSpace as suggested + suggested?: boolean; joinRule?: JoinRule; } @@ -228,7 +230,7 @@ export default async function createRoom(opts: IOpts): Promise { } }).then(() => { if (opts.parentSpace) { - return SpaceStore.instance.addRoomToSpace(opts.parentSpace, roomId, [client.getDomain()], true); + return SpaceStore.instance.addRoomToSpace(opts.parentSpace, roomId, [client.getDomain()], opts.suggested); } if (opts.associatedWithCommunity) { return GroupStore.addRoomToGroup(opts.associatedWithCommunity, roomId, false); From dca268e67a0c44ccd8659c8fa2ed40fa1b8efa34 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 1 Sep 2021 10:55:47 +0100 Subject: [PATCH 3/8] Replace eventIsReply util with replyEventId getter --- src/components/views/rooms/EditMessageComposer.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx index b7e067ee93..7a3767deb7 100644 --- a/src/components/views/rooms/EditMessageComposer.tsx +++ b/src/components/views/rooms/EditMessageComposer.tsx @@ -43,11 +43,6 @@ import QuestionDialog from "../dialogs/QuestionDialog"; import { ActionPayload } from "../../../dispatcher/payloads"; import AccessibleButton from '../elements/AccessibleButton'; -function eventIsReply(mxEvent: MatrixEvent): boolean { - const relatesTo = mxEvent.getContent()["m.relates_to"]; - return !!(relatesTo && relatesTo["m.in_reply_to"]); -} - function getHtmlReplyFallback(mxEvent: MatrixEvent): string { const html = mxEvent.getContent().formatted_body; if (!html) { @@ -72,7 +67,7 @@ function createEditContent(model: EditorModel, editedEvent: MatrixEvent): IConte if (isEmote) { model = stripEmoteCommand(model); } - const isReply = eventIsReply(editedEvent); + const isReply = !!editedEvent.replyEventId; let plainPrefix = ""; let htmlPrefix = ""; From 95d1b06abb4ad612bd00ee5569b4dd85269ddde3 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Wed, 1 Sep 2021 12:12:40 +0100 Subject: [PATCH 4/8] Make composer able to reply in thread or in room timeline --- src/components/structures/ThreadView.tsx | 1 + src/components/views/elements/ReplyThread.tsx | 4 ++- .../views/rooms/MessageComposer.tsx | 3 +++ .../views/rooms/SendMessageComposer.tsx | 27 ++++++++++++++----- .../views/rooms/SendMessageComposer-test.js | 8 +++--- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index a2595debc8..94f3f26261 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -136,6 +136,7 @@ export default class ThreadView extends React.Component { { return { body, html }; } - public static makeReplyMixIn(ev: MatrixEvent) { + public static makeReplyMixIn(ev: MatrixEvent, replyInThread: boolean) { if (!ev) return {}; return { 'm.relates_to': { 'm.in_reply_to': { 'event_id': ev.getId(), + [UNSTABLE_ELEMENT_REPLY_IN_THREAD.name]: replyInThread, }, }, }; diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index fbf3b58570..466675ac64 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -183,6 +183,7 @@ interface IProps { resizeNotifier: ResizeNotifier; permalinkCreator: RoomPermalinkCreator; replyToEvent?: MatrixEvent; + replyInThread?: boolean; showReplyPreview?: boolean; e2eStatus?: E2EStatus; compact?: boolean; @@ -204,6 +205,7 @@ export default class MessageComposer extends React.Component { private voiceRecordingButton: VoiceRecordComposerTile; static defaultProps = { + replyInThread: false, showReplyPreview: true, compact: false, }; @@ -383,6 +385,7 @@ export default class MessageComposer extends React.Component { room={this.props.room} placeholder={this.renderPlaceholderText()} permalinkCreator={this.props.permalinkCreator} + replyInThread={this.props.replyInThread} replyToEvent={this.props.replyToEvent} onChange={this.onChange} disabled={this.state.haveRecording} diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 205320fb68..aca397b6b2 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -57,15 +57,16 @@ import { ActionPayload } from "../../../dispatcher/payloads"; function addReplyToMessageContent( content: IContent, - repliedToEvent: MatrixEvent, + replyToEvent: MatrixEvent, + replyInThread: boolean, permalinkCreator: RoomPermalinkCreator, ): void { - const replyContent = ReplyThread.makeReplyMixIn(repliedToEvent); + const replyContent = ReplyThread.makeReplyMixIn(replyToEvent, replyInThread); Object.assign(content, replyContent); // Part of Replies fallback support - prepend the text we're sending // with the text we're replying to - const nestedReply = ReplyThread.getNestedReplyText(repliedToEvent, permalinkCreator); + const nestedReply = ReplyThread.getNestedReplyText(replyToEvent, permalinkCreator); if (nestedReply) { if (content.formatted_body) { content.formatted_body = nestedReply.html + content.formatted_body; @@ -77,8 +78,9 @@ function addReplyToMessageContent( // exported for tests export function createMessageContent( model: EditorModel, - permalinkCreator: RoomPermalinkCreator, replyToEvent: MatrixEvent, + replyInThread: boolean, + permalinkCreator: RoomPermalinkCreator, ): IContent { const isEmote = containsEmote(model); if (isEmote) { @@ -101,7 +103,7 @@ export function createMessageContent( } if (replyToEvent) { - addReplyToMessageContent(content, replyToEvent, permalinkCreator); + addReplyToMessageContent(content, replyToEvent, replyInThread, permalinkCreator); } return content; @@ -129,6 +131,7 @@ interface IProps { room: Room; placeholder?: string; permalinkCreator: RoomPermalinkCreator; + replyInThread?: boolean; replyToEvent?: MatrixEvent; disabled?: boolean; onChange?(model: EditorModel): void; @@ -357,7 +360,12 @@ export default class SendMessageComposer extends React.Component { if (cmd.category === CommandCategories.messages) { content = await this.runSlashCommand(cmd, args); if (replyToEvent) { - addReplyToMessageContent(content, replyToEvent, this.props.permalinkCreator); + addReplyToMessageContent( + content, + replyToEvent, + this.props.replyInThread, + this.props.permalinkCreator, + ); } } else { this.runSlashCommand(cmd, args); @@ -400,7 +408,12 @@ export default class SendMessageComposer extends React.Component { const startTime = CountlyAnalytics.getTimestamp(); const { roomId } = this.props.room; if (!content) { - content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent); + content = createMessageContent( + this.model, + replyToEvent, + this.props.replyInThread, + this.props.permalinkCreator, + ); } // don't bother sending an empty message if (!content.body.trim()) return; diff --git a/test/components/views/rooms/SendMessageComposer-test.js b/test/components/views/rooms/SendMessageComposer-test.js index 0c4bde76a8..db5b55df90 100644 --- a/test/components/views/rooms/SendMessageComposer-test.js +++ b/test/components/views/rooms/SendMessageComposer-test.js @@ -46,7 +46,7 @@ describe('', () => { const model = new EditorModel([], createPartCreator(), createRenderer()); model.update("hello world", "insertText", { offset: 11, atNodeEnd: true }); - const content = createMessageContent(model, permalinkCreator); + const content = createMessageContent(model, null, false, permalinkCreator); expect(content).toEqual({ body: "hello world", @@ -58,7 +58,7 @@ describe('', () => { const model = new EditorModel([], createPartCreator(), createRenderer()); model.update("hello *world*", "insertText", { offset: 13, atNodeEnd: true }); - const content = createMessageContent(model, permalinkCreator); + const content = createMessageContent(model, null, false, permalinkCreator); expect(content).toEqual({ body: "hello *world*", @@ -72,7 +72,7 @@ describe('', () => { const model = new EditorModel([], createPartCreator(), createRenderer()); model.update("/me blinks __quickly__", "insertText", { offset: 22, atNodeEnd: true }); - const content = createMessageContent(model, permalinkCreator); + const content = createMessageContent(model, null, false, permalinkCreator); expect(content).toEqual({ body: "blinks __quickly__", @@ -86,7 +86,7 @@ describe('', () => { const model = new EditorModel([], createPartCreator(), createRenderer()); model.update("//dev/null is my favourite place", "insertText", { offset: 32, atNodeEnd: true }); - const content = createMessageContent(model, permalinkCreator); + const content = createMessageContent(model, null, false, permalinkCreator); expect(content).toEqual({ body: "/dev/null is my favourite place", From 9b2c380b642a4a6abc401df1b19a3a912b334332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 1 Sep 2021 17:28:02 +0200 Subject: [PATCH 5/8] Split autoplay gifs and videos in to different settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/messages/MImageBody.tsx | 8 ++++---- src/components/views/messages/MVideoBody.tsx | 4 ++-- .../tabs/user/PreferencesUserSettingsTab.tsx | 3 ++- src/settings/Settings.tsx | 9 +++++++-- src/settings/handlers/AccountSettingsHandler.ts | 15 +++++++++++++++ 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/components/views/messages/MImageBody.tsx b/src/components/views/messages/MImageBody.tsx index 8ead8d9ba2..e36e4c3113 100644 --- a/src/components/views/messages/MImageBody.tsx +++ b/src/components/views/messages/MImageBody.tsx @@ -128,7 +128,7 @@ export default class MImageBody extends React.Component { private onImageEnter = (e: React.MouseEvent): void => { this.setState({ hover: true }); - if (!this.state.showImage || !this.isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) { + if (!this.state.showImage || !this.isGif() || SettingsStore.getValue("autoplayGifs")) { return; } const imgElement = e.currentTarget; @@ -138,7 +138,7 @@ export default class MImageBody extends React.Component { private onImageLeave = (e: React.MouseEvent): void => { this.setState({ hover: false }); - if (!this.state.showImage || !this.isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) { + if (!this.state.showImage || !this.isGif() || SettingsStore.getValue("autoplayGifs")) { return; } const imgElement = e.currentTarget; @@ -387,7 +387,7 @@ export default class MImageBody extends React.Component { showPlaceholder = false; // because we're hiding the image, so don't show the placeholder. } - if (this.isGif() && !SettingsStore.getValue("autoplayGifsAndVideos") && !this.state.hover) { + if (this.isGif() && !SettingsStore.getValue("autoplayGifs") && !this.state.hover) { gifLabel =

GIF

; } @@ -487,7 +487,7 @@ export default class MImageBody extends React.Component { const contentUrl = this.getContentUrl(); let thumbUrl; - if (this.isGif() && SettingsStore.getValue("autoplayGifsAndVideos")) { + if (this.isGif() && SettingsStore.getValue("autoplayGifs")) { thumbUrl = contentUrl; } else { thumbUrl = this.getThumbUrl(); diff --git a/src/components/views/messages/MVideoBody.tsx b/src/components/views/messages/MVideoBody.tsx index 77c7ebacda..de1915299c 100644 --- a/src/components/views/messages/MVideoBody.tsx +++ b/src/components/views/messages/MVideoBody.tsx @@ -145,7 +145,7 @@ export default class MVideoBody extends React.PureComponent } async componentDidMount() { - const autoplay = SettingsStore.getValue("autoplayGifsAndVideos") as boolean; + const autoplay = SettingsStore.getValue("autoplayVideo") as boolean; this.loadBlurhash(); if (this.props.mediaEventHelper.media.isEncrypted && this.state.decryptedUrl === null) { @@ -209,7 +209,7 @@ export default class MVideoBody extends React.PureComponent render() { const content = this.props.mxEvent.getContent(); - const autoplay = SettingsStore.getValue("autoplayGifsAndVideos"); + const autoplay = SettingsStore.getValue("autoplayVideo"); if (this.state.error !== null) { return ( diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx index 21c3ab24ec..2209537967 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx @@ -172,7 +172,8 @@ export default class PreferencesUserSettingsTab extends React.Component Date: Wed, 1 Sep 2021 17:28:09 +0200 Subject: [PATCH 6/8] i18n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/i18n/strings/en_EN.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 2cb0a546aa..7fc29b02e2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -832,7 +832,8 @@ "Show read receipts sent by other users": "Show read receipts sent by other users", "Show timestamps in 12 hour format (e.g. 2:30pm)": "Show timestamps in 12 hour format (e.g. 2:30pm)", "Always show message timestamps": "Always show message timestamps", - "Autoplay GIFs and videos": "Autoplay GIFs and videos", + "Autoplay GIFs": "Autoplay GIFs", + "Autoplay videos": "Autoplay videos", "Enable automatic language detection for syntax highlighting": "Enable automatic language detection for syntax highlighting", "Expand code blocks by default": "Expand code blocks by default", "Show line numbers in code blocks": "Show line numbers in code blocks", From 2ce86471206cba5f54985e63d9f9a16c91cc6d59 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Thu, 2 Sep 2021 08:36:20 +0100 Subject: [PATCH 7/8] Prevent unstable property to be sent with all events --- src/components/views/elements/ReplyThread.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/views/elements/ReplyThread.tsx b/src/components/views/elements/ReplyThread.tsx index d5b6af17f2..d061d52f46 100644 --- a/src/components/views/elements/ReplyThread.tsx +++ b/src/components/views/elements/ReplyThread.tsx @@ -209,14 +209,26 @@ export default class ReplyThread extends React.Component { public static makeReplyMixIn(ev: MatrixEvent, replyInThread: boolean) { if (!ev) return {}; - return { + + const replyMixin = { 'm.relates_to': { 'm.in_reply_to': { 'event_id': ev.getId(), - [UNSTABLE_ELEMENT_REPLY_IN_THREAD.name]: replyInThread, }, }, }; + + /** + * @experimental + * Rendering hint for threads, only attached if true to make + * sure that Element does not start sending that property for all events + */ + if (replyInThread) { + const inReplyTo = replyMixin['m.relates_to']['m.in_reply_to']; + inReplyTo[UNSTABLE_ELEMENT_REPLY_IN_THREAD.name] = replyInThread; + } + + return replyMixin; } public static makeThread( From c246b027bea6530fc7d686ef6d28c27bc66dec85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Thu, 2 Sep 2021 17:39:13 +0200 Subject: [PATCH 8/8] Add missing space Co-authored-by: Dariusz Niemczyk <3636685+Palid@users.noreply.github.com> --- src/settings/handlers/AccountSettingsHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/handlers/AccountSettingsHandler.ts b/src/settings/handlers/AccountSettingsHandler.ts index 75cef07685..5afe50e4e9 100644 --- a/src/settings/handlers/AccountSettingsHandler.ts +++ b/src/settings/handlers/AccountSettingsHandler.ts @@ -116,7 +116,7 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa const value = settings[settingName]; // Fallback to old combined setting if (value === null || value === undefined) { - const oldCombinedValue= settings["autoplayGifsAndVideos"]; + const oldCombinedValue = settings["autoplayGifsAndVideos"]; // Write, so that we can remove this in the future this.setValue("autoplayGifs", roomId, oldCombinedValue); this.setValue("autoplayVideo", roomId, oldCombinedValue);