diff --git a/res/css/_components.scss b/res/css/_components.scss index 51087eba62..22c9b73dca 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -143,7 +143,9 @@ @import "./views/messages/_TextualEvent.scss"; @import "./views/messages/_UnknownBody.scss"; @import "./views/messages/_ViewSourceEvent.scss"; +@import "./views/right_panel/_EncryptionInfo.scss"; @import "./views/right_panel/_UserInfo.scss"; +@import "./views/right_panel/_VerificationPanel.scss"; @import "./views/room_settings/_AliasSettings.scss"; @import "./views/room_settings/_ColorSettings.scss"; @import "./views/rooms/_AppsDrawer.scss"; diff --git a/res/css/views/right_panel/_EncryptionInfo.scss b/res/css/views/right_panel/_EncryptionInfo.scss new file mode 100644 index 0000000000..e13b1b6802 --- /dev/null +++ b/res/css/views/right_panel/_EncryptionInfo.scss @@ -0,0 +1,26 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_UserInfo { + .mx_EncryptionInfo_spinner { + .mx_Spinner { + margin-top: 25px; + margin-bottom: 15px; + } + + text-align: center; + } +} diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss index ad6254f57c..9ce524c5ac 100644 --- a/res/css/views/right_panel/_UserInfo.scss +++ b/res/css/views/right_panel/_UserInfo.scss @@ -49,12 +49,17 @@ limitations under the License. } .mx_UserInfo_container { - padding: 0 16px 16px 16px; + padding: 8px 16px; + } + + .mx_UserInfo_separator { border-bottom: 1px solid lightgray; } .mx_UserInfo_memberDetailsContainer { + padding-top: 0; padding-bottom: 0; + margin-bottom: 8px; } .mx_RoomTile_nameContainer { @@ -76,6 +81,7 @@ limitations under the License. .mx_UserInfo_avatar > div { max-width: 30vh; margin: 0 auto; + transition: 0.5s; } .mx_UserInfo_avatar > div > div { @@ -105,6 +111,7 @@ limitations under the License. // override the calculated sizes so that the letter isn't HUGE font-size: 56px !important; width: 100% !important; + transition: font-size 0.5s; } .mx_UserInfo_avatar .mx_BaseAvatar.mx_BaseAvatar_image { @@ -204,10 +211,9 @@ limitations under the License. padding-bottom: 16px; } - .mx_UserInfo_scrollContainer .mx_UserInfo_container { + .mx_UserInfo_scrollContainer:not(.mx_UserInfo_separator) { padding-top: 16px; padding-bottom: 0; - border-bottom: none; > :not(h3) { margin-left: 8px; @@ -256,11 +262,17 @@ limitations under the License. .mx_UserInfo_verify { display: block; - background-color: $accent-color; - color: $accent-fg-color; - border-radius: 4px; - padding: 7px 1.5em; - text-align: center; margin: 16px 0; } } + +.mx_UserInfo.mx_UserInfo_smallAvatar { + .mx_UserInfo_avatar > div { + max-width: 72px; + margin: 0 auto; + } + + .mx_UserInfo_avatar .mx_BaseAvatar_initial { + font-size: 40px !important; // override the other override because here the avatar is smaller + } +} diff --git a/res/css/views/right_panel/_VerificationPanel.scss b/res/css/views/right_panel/_VerificationPanel.scss new file mode 100644 index 0000000000..75b469cef9 --- /dev/null +++ b/res/css/views/right_panel/_VerificationPanel.scss @@ -0,0 +1,37 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_UserInfo { + .mx_VerificationPanel_verified_section .mx_E2EIcon { + margin: 0 auto; + } + + .mx_VerificationPanel_qrCode { + padding: 4px 4px 0 4px; + background: white; + border-radius: 4px; + width: max-content; + max-width: 100%; + margin: 0 auto; + + canvas { + // override height and width which are set on the element directly + height: auto !important; + width: 100% !important; + max-width: 240px; + } + } +} diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index dca89d0c35..be10ead7ca 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -169,7 +169,6 @@ export default class RightPanel extends React.Component { const MemberList = sdk.getComponent('rooms.MemberList'); const MemberInfo = sdk.getComponent('rooms.MemberInfo'); const UserInfo = sdk.getComponent('right_panel.UserInfo'); - const EncryptionPanel = sdk.getComponent('right_panel.EncryptionPanel'); const ThirdPartyMemberInfo = sdk.getComponent('rooms.ThirdPartyMemberInfo'); const NotificationPanel = sdk.getComponent('structures.NotificationPanel'); const FilePanel = sdk.getComponent('structures.FilePanel'); @@ -181,64 +180,82 @@ export default class RightPanel extends React.Component { let panel =
; - if (this.props.roomId && this.state.phase === RIGHT_PANEL_PHASES.RoomMemberList) { - panel ={_t("For extra security, verify this user by checking a one-time code on both of your devices.")}
-{_t("For maximum security, do this in person.")}
-{_t("Messages in this room are end-to-end encrypted.")}
+{_t("Your messages are secured and only you and the recipient have the unique keys to unlock them.")}
+{_t("For extra security, verify this user by checking a one-time code on both of your devices.")}
+{_t("For maximum security, do this in person.")}
+ { content } +Not a member nor request, not sure what to render
; +const EncryptionPanel = ({verificationRequest, member, onClose}) => { + const [request, setRequest] = useState(verificationRequest); + useEffect(() => { + setRequest(verificationRequest); + }, [verificationRequest]); + + const [phase, setPhase] = useState(false); + 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)) { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createTrackedDialog("Verification failed", "insecure", ErrorDialog, { + headerImage: require("../../../../res/img/e2e/warning.svg"), + title: _t("Your messages are not secure"), + description:{ text }
+ { verifyButton } + { devicesSection } +{ text }
- { verifyButton } - { devicesSection } -{_t("Verify by comparing unique emoji.")}
+ + { button } +{_t("Ask %(displayName)s to scan your code:", { + displayName: member.displayName || member.name || member.userId, + })}
+ +{_t("If you can't scan the code above, verify by comparing unique emoji.")}
+ + { button } +{_t("You've successfully verified %(displayName)s!", { + displayName: member.displayName || member.name || member.userId, + })}
+Verify all users in a room to ensure it's secure.
- if (request.requested) { - return (Waiting for {request.otherUserId} to accept ...
{request.otherUserId} is ready, start {verifyButton} or have them scan: {qrCode}
); - } + renderCancelledPhase() { + const {member, request} = this.props; - return ({request.otherUserId} is ready, start {verifyButton}
); - } else if (request.started) { - if (this.state.sasWaitingForOtherParty) { - returnWaiting for {request.otherUserId} to confirm ...
; - } else if (this.state.sasEvent) { - const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); - return (Setting up SAS verification...
); - } - } else if (request.done) { - returnverified {request.otherUserId}!!
; - } else if (request.cancelled) { - returncancelled by {request.cancellingUserId}!
; + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + + let text; + if (request.cancellationCode === "m.timeout") { + text = _t("Verification timed out. Start verification again from their profile."); + } else if (request.cancellingUserId === request.otherUserId) { + text = _t("%(displayName)s cancelled verification. Start verification again from their profile.", { + displayName: member.displayName || member.name || member.userId, + }); + } else { + text = _t("You cancelled verification. Start verification again from their profile."); } + + return ( +{ text }
+ +{sasCaption}
-{_t( - "For maximum security, we recommend you do this in person or use another " + - "trusted means of communication.", - )}
+{_t("For ultimate security, do this in person or use another way to communicate.")}
{sasDisplay} -