From 210616c737bdc93fd421c75ec8e554779f4af7fb Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 24 Jan 2020 11:45:39 +0000 Subject: [PATCH] Phase 1, split out UserInfo into a generic Pane, use for EncInfo --- res/css/views/right_panel/_UserInfo.scss | 17 +- src/components/structures/RightPanel.js | 13 +- .../views/right_panel/EncryptionInfo.js | 18 +- .../views/right_panel/EncryptionPanel.js | 25 +- src/components/views/right_panel/UserInfo.js | 248 +++++++++--------- src/i18n/strings/en_EN.json | 3 +- 6 files changed, 191 insertions(+), 133 deletions(-) diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss index d2d9d12c6d..57ffd4982e 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 { @@ -204,10 +209,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; @@ -264,3 +268,10 @@ limitations under the License. margin: 16px 0; } } + +.mx_UserInfo.mx_UserInfo_smallAvatar { + .mx_UserInfo_avatar > div { + max-width: 72px; + margin: 0 auto; + } +} diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index dca89d0c35..c01a3709e7 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -238,7 +238,18 @@ export default class RightPanel extends React.Component { } else if (this.state.phase === RIGHT_PANEL_PHASES.FilePanel) { panel = ; } else if (this.state.phase === RIGHT_PANEL_PHASES.EncryptionPanel) { - panel = ; + const onClose = () => { + dis.dispatch({ + action: "view_user", + member: this.state.member, + }); + }; + panel = ( + + ); } const classes = classNames("mx_RightPanel", "mx_fadable", { diff --git a/src/components/views/right_panel/EncryptionInfo.js b/src/components/views/right_panel/EncryptionInfo.js index 5770e9b086..2d265967ae 100644 --- a/src/components/views/right_panel/EncryptionInfo.js +++ b/src/components/views/right_panel/EncryptionInfo.js @@ -21,11 +21,17 @@ import {_t} from "../../../languageHandler"; export default class EncryptionInfo extends React.PureComponent { render() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - return (
-

{_t("Verify User")}

-

{_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("Start Verification")} -
); + return ( +
+

{_t("Verify User")}

+
+

{_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("Start Verification")} + +
+
+ ); } } diff --git a/src/components/views/right_panel/EncryptionPanel.js b/src/components/views/right_panel/EncryptionPanel.js index 4b3473935a..a1008543e4 100644 --- a/src/components/views/right_panel/EncryptionPanel.js +++ b/src/components/views/right_panel/EncryptionPanel.js @@ -1,5 +1,5 @@ /* -Copyright 2019 The Matrix.org Foundation C.I.C. +Copyright 2019, 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. @@ -19,6 +19,8 @@ import EncryptionInfo from "./EncryptionInfo"; import VerificationPanel from "./VerificationPanel"; import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {ensureDMExists} from "../../../createRoom"; +import {UserInfoPane} from "./UserInfo"; +import {_t} from "../../../languageHandler"; export default class EncryptionPanel extends React.PureComponent { constructor(props) { @@ -27,15 +29,30 @@ export default class EncryptionPanel extends React.PureComponent { } render() { + let content; const request = this.props.verificationRequest || this.state.verificationRequest; const {member} = this.props; if (request) { - return ; + content = ; } else if (member) { - return ; + content = ; } else { - return

Not a member nor request, not sure what to render

; + content =

Not a member nor request, not sure what to render

; } + + return ( + +
+

{_t("Encryption")}

+
+

{_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.")}

+
+
+ + { content } +
+ ); } _onStartVerification = async () => { diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js index 051f92cc9c..a31e9a6ce0 100644 --- a/src/components/views/right_panel/UserInfo.js +++ b/src/components/views/right_panel/UserInfo.js @@ -59,7 +59,7 @@ const _disambiguateDevices = (devices) => { } }; -const _getE2EStatus = (cli, userId, devices) => { +export const getE2EStatus = (cli, userId, devices) => { if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) { const hasUnverifiedDevice = devices.some((device) => device.isUnverified()); return hasUnverifiedDevice ? "warning" : "verified"; @@ -1047,6 +1047,117 @@ const PowerLevelEditor = ({user, room, roomPermissions, onFinished}) => { ); }; +export const UserInfoPane = ({children, className, onClose, e2eStatus, member}) => { + const cli = useContext(MatrixClientContext); + + let closeButton; + if (onClose) { + closeButton = +
+ ; + } + + let presenceState; + let presenceLastActiveAgo; + let presenceCurrentlyActive; + let statusMessage; + + if (member instanceof RoomMember && member.user) { + presenceState = member.user.presence; + presenceLastActiveAgo = member.user.lastActiveAgo; + presenceCurrentlyActive = member.user.currentlyActive; + + if (SettingsStore.isFeatureEnabled("feature_custom_status")) { + statusMessage = member.user._unstable_statusMessage; + } + } + + const enablePresenceByHsUrl = SdkConfig.get()["enable_presence_by_hs_url"]; + let showPresence = true; + if (enablePresenceByHsUrl && enablePresenceByHsUrl[cli.baseUrl] !== undefined) { + showPresence = enablePresenceByHsUrl[cli.baseUrl]; + } + + let presenceLabel = null; + if (showPresence) { + const PresenceLabel = sdk.getComponent('rooms.PresenceLabel'); + presenceLabel = ; + } + + let statusLabel = null; + if (statusMessage) { + statusLabel = { statusMessage }; + } + + const onMemberAvatarClick = useCallback(() => { + const avatarUrl = member.getMxcAvatarUrl ? member.getMxcAvatarUrl() : member.avatarUrl; + if (!avatarUrl) return; + + const httpUrl = cli.mxcUrlToHttp(avatarUrl); + const ImageView = sdk.getComponent("elements.ImageView"); + const params = { + src: httpUrl, + name: member.name, + }; + + Modal.createDialog(ImageView, params, "mx_Dialog_lightbox"); + }, [cli, member]); + + const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); + const avatarElement = ( +
+
+
+ +
+
+
+ ); + + let e2eIcon; + if (e2eStatus) { + e2eIcon = ; + } + + const displayName = member.name || member.displayname; + + return ( +
+ + { closeButton } + { avatarElement } + +
+
+
+

+ { e2eIcon } + { displayName } +

+
+
{ member.userId }
+
+ {presenceLabel} + {statusLabel} +
+
+
+ + { children } +
+
+ ); +}; + const UserInfo = ({user, groupId, roomId, onClose}) => { const cli = useContext(MatrixClientContext); @@ -1117,20 +1228,6 @@ const UserInfo = ({user, groupId, roomId, onClose}) => { } }, [cli, user.userId]); - const onMemberAvatarClick = useCallback(() => { - const avatarUrl = member.getMxcAvatarUrl ? member.getMxcAvatarUrl() : member.avatarUrl; - if (!avatarUrl) return; - - const httpUrl = cli.mxcUrlToHttp(avatarUrl); - const ImageView = sdk.getComponent("elements.ImageView"); - const params = { - src: httpUrl, - name: member.name, - }; - - Modal.createDialog(ImageView, params, "mx_Dialog_lightbox"); - }, [cli, member]); - let synapseDeactivateButton; let spinner; @@ -1180,68 +1277,6 @@ const UserInfo = ({user, groupId, roomId, onClose}) => { spinner = ; } - const displayName = member.name || member.displayname; - - let presenceState; - let presenceLastActiveAgo; - let presenceCurrentlyActive; - let statusMessage; - - if (member instanceof RoomMember && member.user) { - presenceState = member.user.presence; - presenceLastActiveAgo = member.user.lastActiveAgo; - presenceCurrentlyActive = member.user.currentlyActive; - - if (SettingsStore.isFeatureEnabled("feature_custom_status")) { - statusMessage = member.user._unstable_statusMessage; - } - } - - const enablePresenceByHsUrl = SdkConfig.get()["enable_presence_by_hs_url"]; - let showPresence = true; - if (enablePresenceByHsUrl && enablePresenceByHsUrl[cli.baseUrl] !== undefined) { - showPresence = enablePresenceByHsUrl[cli.baseUrl]; - } - - let presenceLabel = null; - if (showPresence) { - const PresenceLabel = sdk.getComponent('rooms.PresenceLabel'); - presenceLabel = ; - } - - let statusLabel = null; - if (statusMessage) { - statusLabel = { statusMessage }; - } - - // const avatarUrl = user.getMxcAvatarUrl ? user.getMxcAvatarUrl() : user.avatarUrl; - const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); - const avatarElement = ( -
-
-
- -
-
-
- ); - - let closeButton; - if (onClose) { - closeButton = -
- ; - } - const memberDetails = ( {
); - let e2eIcon; + let e2eStatus; if (isRoomEncrypted && devices) { - const e2eStatus = _getE2EStatus(cli, user.userId, devices); - e2eIcon = ; + e2eStatus = getE2EStatus(cli, user.userId, devices); } - return ( -
- - { closeButton } - { avatarElement } + return + { memberDetails && +
+
+ { memberDetails } +
+
} -
-
-
-

- { e2eIcon } - { displayName } -

-
-
{ user.userId }
-
- {presenceLabel} - {statusLabel} -
-
-
+ { securitySection } + - { memberDetails &&
-
- { memberDetails } -
-
} + { adminToolsContainer } - { securitySection } - - - { adminToolsContainer } - - { spinner } -
-
- ); + { spinner } + ; }; UserInfo.propTypes = { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 099b64dd49..c99b22f421 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1128,6 +1128,8 @@ "For extra security, verify this user by checking a one-time code on both of your devices.": "For extra security, verify this user by checking a one-time code on both of your devices.", "For maximum security, do this in person.": "For maximum security, do this in person.", "Start Verification": "Start Verification", + "Messages in this room are end-to-end encrypted.": "Messages in this room are end-to-end encrypted.", + "Your messages are secured and only you and the recipient have the unique keys to unlock them.": "Your messages are secured and only you and the recipient have the unique keys to unlock them.", "Members": "Members", "Files": "Files", "Trusted": "Trusted", @@ -1144,7 +1146,6 @@ "%(role)s in %(roomName)s": "%(role)s in %(roomName)s", "This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.", "Messages in this room are not end-to-end encrypted.": "Messages in this room are not end-to-end encrypted.", - "Messages in this room are end-to-end encrypted.": "Messages in this room are end-to-end encrypted.", "Security": "Security", "Sunday": "Sunday", "Monday": "Monday",