diff --git a/res/css/_components.scss b/res/css/_components.scss index 2617cd7c4c..ee34eeb524 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -130,6 +130,7 @@ @import "./views/settings/_IntegrationsManager.scss"; @import "./views/settings/_KeyBackupPanel.scss"; @import "./views/settings/_Notifications.scss"; +@import "./views/settings/_ProfileSettings.scss"; @import "./views/settings/tabs/_GeneralSettingsTab.scss"; @import "./views/settings/tabs/_SettingsTab.scss"; @import "./views/voip/_CallView.scss"; diff --git a/res/css/views/settings/_ProfileSettings.scss b/res/css/views/settings/_ProfileSettings.scss new file mode 100644 index 0000000000..4bec429d55 --- /dev/null +++ b/res/css/views/settings/_ProfileSettings.scss @@ -0,0 +1,107 @@ +/* +Copyright 2019 New Vector Ltd + +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_ProfileSettings_profile { + display: flex; +} + +.mx_ProfileSettings_controls { + flex-grow: 1; +} + +.mx_ProfileSettings_controls .mx_Field #profileDisplayName { + width: calc(100% - 20px); // subtract 10px padding on left and right +} + +.mx_ProfileSettings_avatar { + width: 88px; + height: 88px; + margin-left: 13px; + position: relative; + cursor: pointer; +} + +.mx_ProfileSettings_avatar > * { + display: block; + width: 88px; + height: 88px; + border-radius: 4px; +} + +.mx_ProfileSettings_avatar .mx_ProfileSettings_avatarPlaceholder { + background-color: $settings-profile-placeholder-bg-color; +} + +.mx_ProfileSettings_avatarOverlay { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: none; + text-align: center; + vertical-align: middle; + font-size: 10px; +} + +.mx_ProfileSettings_avatar:hover .mx_ProfileSettings_avatarOverlay { + display: inline-block; + opacity: 0.5 !important; + color: $settings-profile-overlay-fg-color !important; + background-color: $settings-profile-overlay-bg-color !important; +} + +.mx_ProfileSettings_avatarOverlay_show { + display: inline-block; + opacity: 1; + color: $settings-profile-overlay-placeholder-fg-color; + background-color: $settings-profile-overlay-placeholder-bg-color; +} + +.mx_ProfileSettings_avatarOverlayText { + display: block; + margin-top: 17px; + margin-bottom: 8px; +} + +.mx_ProfileSettings_avatarOverlayImgContainer { + position: relative; + width: 14px; + height: 14px; + margin: auto; +} + +.mx_ProfileSettings_avatarOverlayImg:before { + background-color: $settings-profile-overlay-placeholder-fg-color; + mask: url("$(res)/img/feather-icons/upload.svg"); + mask-repeat: no-repeat; + mask-size: 14px; + mask-position: center; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.mx_ProfileSettings_avatar:hover .mx_ProfileSettings_avatarOverlayImg:before { + background-color: $settings-profile-overlay-fg-color !important; +} + +.mx_ProfileSettings_avatarUpload { + display: none; +} diff --git a/res/css/views/settings/tabs/_GeneralSettingsTab.scss b/res/css/views/settings/tabs/_GeneralSettingsTab.scss index 097d81dab4..d1a31e37f8 100644 --- a/res/css/views/settings/tabs/_GeneralSettingsTab.scss +++ b/res/css/views/settings/tabs/_GeneralSettingsTab.scss @@ -1,94 +1,18 @@ -.mx_GeneralSettingsTab_profile { - display: flex; -} +/* +Copyright 2019 New Vector Ltd -.mx_GeneralSettingsTab_profileControls { - flex-grow: 1; -} +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 -.mx_GeneralSettingsTab_profileControls .mx_Field #profileDisplayName { - width: calc(100% - 20px); // subtract 10px padding on left and right -} + http://www.apache.org/licenses/LICENSE-2.0 -.mx_GeneralSettingsTab_profileAvatar { - width: 88px; - height: 88px; - margin-left: 13px; - position: relative; - cursor: pointer; -} - -.mx_GeneralSettingsTab_profileAvatar > * { - display: block; - width: 88px; - height: 88px; - border-radius: 4px; -} - -.mx_GeneralSettingsTab_profileAvatar .mx_GeneralSettingsTab_profileAvatarPlaceholder { - background-color: $settings-profile-placeholder-bg-color; -} - -.mx_GeneralSettingsTab_profileAvatarOverlay { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - display: none; - text-align: center; - vertical-align: middle; - font-size: 10px; -} - -.mx_GeneralSettingsTab_profileAvatar:hover .mx_GeneralSettingsTab_profileAvatarOverlay { - display: inline-block; - opacity: 0.5 !important; - color: $settings-profile-overlay-fg-color !important; - background-color: $settings-profile-overlay-bg-color !important; -} - -.mx_GeneralSettingsTab_profileAvatarOverlay_show { - display: inline-block; - opacity: 1; - color: $settings-profile-overlay-placeholder-fg-color; - background-color: $settings-profile-overlay-placeholder-bg-color; -} - -.mx_GeneralSettingsTab_profileAvatarOverlayText { - display: block; - margin-top: 17px; - margin-bottom: 8px; -} - -.mx_GeneralSettingsTab_profileAvatarOverlayImgContainer { - position: relative; - width: 14px; - height: 14px; - margin: auto; -} - -.mx_GeneralSettingsTab_profileAvatarOverlayImg:before { - background-color: $settings-profile-overlay-placeholder-fg-color; - mask: url("$(res)/img/feather-icons/upload.svg"); - mask-repeat: no-repeat; - mask-size: 14px; - mask-position: center; - content: ''; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} - -.mx_GeneralSettingsTab_profileAvatar:hover .mx_GeneralSettingsTab_profileAvatarOverlayImg:before { - background-color: $settings-profile-overlay-fg-color !important; -} - -.mx_GeneralSettingsTab_profileAvatarUpload { - display: none; -} +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_GeneralSettingsTab_changePassword { display: block; diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss index c86fb1f41e..3ea9d616ba 100644 --- a/res/css/views/settings/tabs/_SettingsTab.scss +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -1,3 +1,19 @@ +/* +Copyright 2019 New Vector Ltd + +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_SettingsTab_heading { font-size: 20px; font-weight: 600; diff --git a/src/components/views/settings/ChangePassword.js b/src/components/views/settings/ChangePassword.js index 50319850b5..ee9662ebc4 100644 --- a/src/components/views/settings/ChangePassword.js +++ b/src/components/views/settings/ChangePassword.js @@ -1,6 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd -Copyright 2018 New Vector Ltd +Copyright 2018-2019 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/components/views/settings/ProfileSettings.js b/src/components/views/settings/ProfileSettings.js new file mode 100644 index 0000000000..6bffd92f85 --- /dev/null +++ b/src/components/views/settings/ProfileSettings.js @@ -0,0 +1,155 @@ +/* +Copyright 2019 New Vector Ltd + +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. +*/ + +import React from 'react'; +import {_t} from "../../../languageHandler"; +import MatrixClientPeg from "../../../MatrixClientPeg"; +import Field from "../elements/Field"; +import AccessibleButton from "../elements/AccessibleButton"; +import classNames from 'classnames'; + +export default class ProfileSettings extends React.Component { + constructor() { + super(); + + const client = MatrixClientPeg.get(); + const user = client.getUser(client.getUserId()); + let avatarUrl = user.avatarUrl; + if (avatarUrl) avatarUrl = client.mxcUrlToHttp(avatarUrl, 96, 96, 'crop', false); + this.state = { + userId: user.userId, + originalDisplayName: user.displayName, + displayName: user.displayName, + originalAvatarUrl: avatarUrl, + avatarUrl: avatarUrl, + avatarFile: null, + enableProfileSave: false, + }; + } + + _uploadAvatar = (e) => { + e.stopPropagation(); + e.preventDefault(); + + this.refs.avatarUpload.click(); + }; + + _saveProfile = async (e) => { + e.stopPropagation(); + e.preventDefault(); + + if (!this.state.enableProfileSave) return; + this.setState({enableProfileSave: false}); + + const client = MatrixClientPeg.get(); + const newState = {}; + + // TODO: What do we do about errors? + + if (this.state.originalDisplayName !== this.state.displayName) { + await client.setDisplayName(this.state.displayName); + newState.originalDisplayName = this.state.displayName; + } + + if (this.state.avatarFile) { + const uri = await client.uploadContent(this.state.avatarFile); + await client.setAvatarUrl(uri); + newState.avatarUrl = client.mxcUrlToHttp(uri, 96, 96, 'crop', false); + newState.originalAvatarUrl = newState.avatarUrl; + newState.avatarFile = null; + } + + newState.enableProfileSave = true; + this.setState(newState); + }; + + _onDisplayNameChanged = (e) => { + this.setState({ + displayName: e.target.value, + enableProfileSave: true, + }); + }; + + _onAvatarChanged = (e) => { + if (!e.target.files || !e.target.files.length) { + this.setState({ + avatarUrl: this.state.originalAvatarUrl, + avatarFile: null, + enableProfileSave: false, + }); + return; + } + + const file = e.target.files[0]; + const reader = new FileReader(); + reader.onload = (ev) => { + this.setState({ + avatarUrl: ev.target.result, + avatarFile: file, + enableProfileSave: true, + }); + }; + reader.readAsDataURL(file); + }; + + render() { + // TODO: Why is rendering a box with an overlay so complicated? Can the DOM be reduced? + + let showOverlayAnyways = true; + let avatarElement =
; + if (this.state.avatarUrl) { + showOverlayAnyways = false; + avatarElement =