diff --git a/README.md b/README.md index 0fbed22030..d6fd6db1b7 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ All code lands on the `develop` branch - `master` is only used for stable releas **Please file PRs against `develop`!!** Please follow the standard Matrix contributor's guide: -https://github.com/matrix-org/synapse/tree/master/CONTRIBUTING.rst +https://github.com/matrix-org/matrix-js-sdk/blob/develop/CONTRIBUTING.rst Please follow the Matrix JS/React code style as per: https://github.com/matrix-org/matrix-react-sdk/blob/master/code_style.md diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index d292c729dd..09827fe3bb 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -289,17 +289,11 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody { display: inline-block; width: 14px; height: 14px; - top: 29px; + top: -19px; user-select: none; z-index: 1; } -.mx_EventTile_continuation .mx_EventTile_readAvatars, -.mx_EventTile_info .mx_EventTile_readAvatars, -.mx_EventTile_emote .mx_EventTile_readAvatars { - top: 7px; -} - .mx_EventTile_readAvatars .mx_BaseAvatar { position: absolute; display: inline-block; @@ -634,15 +628,6 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody { top: 27px; } - .mx_EventTile_continuation .mx_EventTile_readAvatars, - .mx_EventTile_emote .mx_EventTile_readAvatars { - top: 5px; - } - - .mx_EventTile_info .mx_EventTile_readAvatars { - top: 4px; - } - .mx_RoomView_MessageList h2 { margin-top: 6px; } diff --git a/res/css/views/rooms/_TopUnreadMessagesBar.scss b/res/css/views/rooms/_TopUnreadMessagesBar.scss index a3916f321a..5f6f869877 100644 --- a/res/css/views/rooms/_TopUnreadMessagesBar.scss +++ b/res/css/views/rooms/_TopUnreadMessagesBar.scss @@ -56,3 +56,17 @@ limitations under the License. mask-position: 9px 13px; background: $roomtile-name-color; } + +.mx_TopUnreadMessagesBar_markAsRead { + display: block; + width: 18px; + height: 18px; + background-image: url('$(res)/img/cancel.svg'); + background-position: center; + background-size: 10px; + background-repeat: no-repeat; + background-color: $primary-bg-color; + border: 1.3px solid $roomtile-name-color; + border-radius: 99px; + margin: 5px auto; +} diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index f3ea3beb1c..371fdcaf64 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -141,15 +141,17 @@ export default class ManageEventIndexDialog extends React.Component { let crawlerState; if (this.state.currentRoom === null) { - crawlerState = _t("Not currently downloading messages for any room."); + crawlerState = _t("Not currently indexing messages for any room."); } else { crawlerState = ( - _t("Downloading mesages for %(currentRoom)s.", { currentRoom: this.state.currentRoom }) + _t("Currently indexing: %(currentRoom)s.", { currentRoom: this.state.currentRoom }) ); } const Field = sdk.getComponent('views.elements.Field'); + const doneRooms = Math.max(0, (this.state.roomCount - this.state.crawlingRoomsCount)); + const eventIndexingSettings = (
{ @@ -158,13 +160,13 @@ export default class ManageEventIndexDialog extends React.Component { ) }
+ {crawlerState}
{_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
{_t("Indexed messages:")} {formatCountLong(this.state.eventCount)}
- {_t("Indexed rooms:")} {_t("%(crawlingRooms)s out of %(totalRooms)s", { - crawlingRooms: formatCountLong(this.state.crawlingRoomsCount), + {_t("Indexed rooms:")} {_t("%(doneRooms)s out of %(totalRooms)s", { + doneRooms: formatCountLong(doneRooms), totalRooms: formatCountLong(this.state.roomCount), })}
- {crawlerState}
{ - if (request.pending) { - ToastStore.sharedInstance().addOrReplaceToast({ - key: 'verifreq_' + request.channel.transactionId, - title: _t("Verification Request"), - icon: "verification", - props: {request}, - component: sdk.getComponent("toasts.VerificationRequestToast"), - }); - } - }); - } else { - cli.on("crypto.verification.start", (verifier) => { + cli.on("crypto.verification.request", request => { + const isFlagOn = SettingsStore.isFeatureEnabled("feature_cross_signing"); + + if (!isFlagOn && !request.channel.deviceId) { + request.cancel({code: "m.invalid_message", reason: "This client has cross-signing disabled"}); + return; + } + + if (request.verifier) { const IncomingSasDialog = sdk.getComponent("views.dialogs.IncomingSasDialog"); Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, { - verifier, + verifier: request.verifier, }, null, /* priority = */ false, /* static = */ true); - }); - } + } else if (request.pending) { + ToastStore.sharedInstance().addOrReplaceToast({ + key: 'verifreq_' + request.channel.transactionId, + title: _t("Verification Request"), + icon: "verification", + props: {request}, + component: sdk.getComponent("toasts.VerificationRequestToast"), + }); + } + }); // Fire the tinter right on startup to ensure the default theme is applied // A later sync can/will correct the tint to be the right value for the user const colorScheme = SettingsStore.getValue("roomColor"); diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 20df323c10..8d25116827 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -182,6 +182,7 @@ export default class RightPanel extends React.Component { member: payload.member, event: payload.event, verificationRequest: payload.verificationRequest, + verificationRequestPromise: payload.verificationRequestPromise, }); } } @@ -231,6 +232,7 @@ export default class RightPanel extends React.Component { onClose={onClose} phase={this.state.phase} verificationRequest={this.state.verificationRequest} + verificationRequestPromise={this.state.verificationRequestPromise} />; } else { panel = { @@ -133,6 +135,11 @@ export default class MessageActionBar extends React.PureComponent { this.forceUpdate(); }; + onBeforeRedaction = () => { + // When an event is redacted, we can't edit it so update the available actions. + this.forceUpdate(); + }; + onFocusChange = (focused) => { if (!this.props.onFocusChange) { return; diff --git a/src/components/views/right_panel/EncryptionPanel.js b/src/components/views/right_panel/EncryptionPanel.js index 4723211de4..a14d4a2b7d 100644 --- a/src/components/views/right_panel/EncryptionPanel.js +++ b/src/components/views/right_panel/EncryptionPanel.js @@ -30,7 +30,7 @@ import {_t} from "../../../languageHandler"; // cancellation codes which constitute a key mismatch const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"]; -const EncryptionPanel = ({verificationRequest, member, onClose, layout}) => { +const EncryptionPanel = ({verificationRequest, verificationRequestPromise, member, onClose, layout}) => { const [request, setRequest] = useState(verificationRequest); // state to show a spinner immediately after clicking "start verification", // before we have a request @@ -43,6 +43,19 @@ const EncryptionPanel = ({verificationRequest, member, onClose, layout}) => { setPhase(verificationRequest.phase); } }, [verificationRequest]); + + useEffect(() => { + async function awaitPromise() { + setRequesting(true); + const request = await verificationRequestPromise; + setRequesting(false); + setRequest(request); + setPhase(request.phase); + } + if (verificationRequestPromise) { + awaitPromise(); + } + }, [verificationRequestPromise]); const changeHandler = useCallback(() => { // handle transitions -> cancelled for mismatches which fire a modal instead of showing a card if (request && request.cancelled && MISMATCHES.includes(request.cancellationCode)) { diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js index b8ba6968a4..17cb80492e 100644 --- a/src/components/views/right_panel/UserInfo.js +++ b/src/components/views/right_panel/UserInfo.js @@ -171,14 +171,14 @@ async function verifyDevice(userId, device) { return; } const cli = MatrixClientPeg.get(); - const verificationRequest = await cli.requestVerification( + const verificationRequestPromise = cli.requestVerification( userId, [device.deviceId], ); dis.dispatch({ action: "set_right_panel_phase", phase: RIGHT_PANEL_PHASES.EncryptionPanel, - refireParams: {member, verificationRequest}, + refireParams: {member, verificationRequestPromise}, }); }, primaryButton: _t("Done"), diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index 916ddc3c5b..f21f2e1ee9 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -880,9 +880,6 @@ export default createReactClass({ // tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers return (
-
- { readAvatars } -
{ sender }
+
+ { readAvatars } +
{ // The avatar goes after the event tile as it's absolutely positioned to be over the // event tile line, so needs to be later in the DOM so it appears on top (this avoids diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index a07c81eb21..e1624602f1 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -490,16 +490,16 @@ export default createReactClass({ height="13" alt="dm" />; + } - const { room } = this.props; - const member = room.getMember(dmUserId); - if ( - member && member.membership === "join" && room.getJoinedMemberCount() === 2 && - SettingsStore.isFeatureEnabled("feature_presence_in_room_list") - ) { - const UserOnlineDot = sdk.getComponent('rooms.UserOnlineDot'); - dmOnline = ; - } + const { room } = this.props; + const member = room.getMember(dmUserId); + if ( + member && member.membership === "join" && room.getJoinedMemberCount() === 2 && + SettingsStore.isFeatureEnabled("feature_presence_in_room_list") + ) { + const UserOnlineDot = sdk.getComponent('rooms.UserOnlineDot'); + dmOnline = ; } // The following labels are written in such a fashion to increase screen reader efficiency (speed). diff --git a/src/components/views/rooms/TopUnreadMessagesBar.js b/src/components/views/rooms/TopUnreadMessagesBar.js index 04805c799f..23d41059c4 100644 --- a/src/components/views/rooms/TopUnreadMessagesBar.js +++ b/src/components/views/rooms/TopUnreadMessagesBar.js @@ -27,6 +27,7 @@ export default createReactClass({ propTypes: { onScrollUpClick: PropTypes.func, + onCloseClick: PropTypes.func, }, render: function() { @@ -36,6 +37,10 @@ export default createReactClass({ title={_t('Jump to first unread message.')} onClick={this.props.onScrollUpClick}> + +
); }, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0bdaf8a666..57e4bcb1cc 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1145,6 +1145,7 @@ "Revoke invite": "Revoke invite", "Invited by %(sender)s": "Invited by %(sender)s", "Jump to first unread message.": "Jump to first unread message.", + "Mark all as read": "Mark all as read", "Error updating main address": "Error updating main address", "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.": "There was an error updating the room's main address. It may not be allowed by the server or a temporary failure occurred.", "Error creating alias": "Error creating alias", @@ -2134,13 +2135,13 @@ "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.", "If disabled, messages from encrypted rooms won't appear in search results.": "If disabled, messages from encrypted rooms won't appear in search results.", "Disable": "Disable", - "Not currently downloading messages for any room.": "Not currently downloading messages for any room.", - "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", + "Not currently indexing messages for any room.": "Not currently indexing messages for any room.", + "Currently indexing: %(currentRoom)s.": "Currently indexing: %(currentRoom)s.", "Riot is securely caching encrypted messages locally for them to appear in search results:": "Riot is securely caching encrypted messages locally for them to appear in search results:", "Space used:": "Space used:", "Indexed messages:": "Indexed messages:", "Indexed rooms:": "Indexed rooms:", - "%(crawlingRooms)s out of %(totalRooms)s": "%(crawlingRooms)s out of %(totalRooms)s", + "%(doneRooms)s out of %(totalRooms)s": "%(doneRooms)s out of %(totalRooms)s", "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", diff --git a/src/utils/EventUtils.js b/src/utils/EventUtils.js index 8acf5ae396..7e33aaed81 100644 --- a/src/utils/EventUtils.js +++ b/src/utils/EventUtils.js @@ -46,7 +46,7 @@ export function isContentActionable(mxEvent) { } export function canEditContent(mxEvent) { - if (mxEvent.status === EventStatus.CANCELLED || mxEvent.getType() !== "m.room.message") { + if (mxEvent.status === EventStatus.CANCELLED || mxEvent.getType() !== "m.room.message" || mxEvent.isRedacted()) { return false; } const content = mxEvent.getOriginalContent();