From de81c8d768b9d5e8cdd0e68190a502b0b5e84ce1 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 10:36:47 -0700 Subject: [PATCH 01/15] Template out remaining sections --- .../views/settings/tabs/GeneralSettingsTab.js | 41 +++++++++++++++++++ src/i18n/strings/en_EN.json | 13 +++--- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index c8816325c0..c248ba23dd 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -73,6 +73,7 @@ export default class GeneralSettingsTab extends React.Component { disabled={!this.state.enableProfileSave}> {_t("Save")} +
FLAIR
); @@ -84,11 +85,51 @@ export default class GeneralSettingsTab extends React.Component { ); } + _renderAccountSection() { + return ( +
+ {_t("Account")} +

ACCOUNT SECTION

+
+ ); + } + + _renderLanguageSection() { + return ( +
+ {_t("Language and region")} +

LANGUAGE SECTION

+
+ ); + } + + _renderThemeSection() { + return ( +
+ {_t("Theme")} +

THEME SECTION

+
+ ); + } + + _renderManagementSection() { + return ( +
+ {_t("Account management")} +

MANAGEMENT SECTION

+
+ ); + } + render() { return (
{_t("General")}
{this._renderProfileSection()} + {this._renderAccountSection()} + {this._renderLanguageSection()} + {this._renderThemeSection()} + {this._renderManagementSection()}
); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6bf857be07..5a85f8c4f3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -405,6 +405,10 @@ "Display Name": "Display Name", "Save": "Save", "Profile": "Profile", + "Account": "Account", + "Language and region": "Language and region", + "Theme": "Theme", + "Account management": "Account management", "General": "General", "Cannot add any more widgets": "Cannot add any more widgets", "The maximum permitted number of widgets have already been added to this room.": "The maximum permitted number of widgets have already been added to this room.", @@ -431,6 +435,7 @@ "Encrypted by an unverified device": "Encrypted by an unverified device", "Unencrypted message": "Unencrypted message", "Please select the destination room for this message": "Please select the destination room for this message", + "Scroll to bottom of page": "Scroll to bottom of page", "Blacklisted": "Blacklisted", "Verified": "Verified", "Unverified": "Unverified", @@ -1065,6 +1070,8 @@ "Set status": "Set status", "Set a new status...": "Set a new status...", "View Community": "View Community", + "Login": "Login", + "powered by Matrix": "powered by Matrix", "Robot check is currently unavailable on desktop - please use a web browser": "Robot check is currently unavailable on desktop - please use a web browser", "This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot", "Custom Server Options": "Custom Server Options", @@ -1082,7 +1089,6 @@ "Please enter the code it contains:": "Please enter the code it contains:", "Code": "Code", "Start authentication": "Start authentication", - "powered by Matrix": "powered by Matrix", "The email field must not be blank.": "The email field must not be blank.", "The user name field must not be blank.": "The user name field must not be blank.", "The phone number field must not be blank.": "The phone number field must not be blank.", @@ -1155,7 +1161,6 @@ "Couldn't load home page": "Couldn't load home page", "You are currently using Riot anonymously as a guest.": "You are currently using Riot anonymously as a guest.", "If you would like to create a Matrix account you can register now.": "If you would like to create a Matrix account you can register now.", - "Login": "Login", "Invalid configuration: Cannot supply a default homeserver URL and a default server name": "Invalid configuration: Cannot supply a default homeserver URL and a default server name", "Failed to reject invitation": "Failed to reject invitation", "This room is not public. You will not be able to rejoin without an invite.": "This room is not public. You will not be able to rejoin without an invite.", @@ -1197,7 +1202,6 @@ "Directory": "Directory", "Search for a room": "Search for a room", "#example": "#example", - "Scroll to bottom of page": "Scroll to bottom of page", "Message not sent due to unknown devices being present": "Message not sent due to unknown devices being present", "Show devices, send anyway or cancel.": "Show devices, send anyway or cancel.", "You can't send any messages until you review and agree to our terms and conditions.": "You can't send any messages until you review and agree to our terms and conditions.", @@ -1209,8 +1213,6 @@ "%(count)s Resend all or cancel all now. You can also select individual messages to resend or cancel.|one": "Resend message or cancel message now.", "Connectivity to the server has been lost.": "Connectivity to the server has been lost.", "Sent messages will be stored until your connection has returned.": "Sent messages will be stored until your connection has returned.", - "%(count)s new messages|other": "%(count)s new messages", - "%(count)s new messages|one": "%(count)s new message", "Active call": "Active call", "There's no one else here! Would you like to invite others or stop warning about the empty room?": "There's no one else here! Would you like to invite others or stop warning about the empty room?", "You seem to be uploading files, are you sure you want to quit?": "You seem to be uploading files, are you sure you want to quit?", @@ -1294,7 +1296,6 @@ "Email": "Email", "Add email address": "Add email address", "Display name": "Display name", - "Account": "Account", "To return to your account in future you need to set a password": "To return to your account in future you need to set a password", "Logged in as:": "Logged in as:", "Access Token:": "Access Token:", From f643d7a143ce1ba5e1a26c4666b3fe2b23fad9dc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 21 Jan 2019 22:39:49 -0700 Subject: [PATCH 02/15] Finish the box for displayname/avatar changes --- .../settings/tabs/_GeneralSettingsTab.scss | 70 +++++++++++++- res/img/feather-icons/upload.svg | 5 + res/themes/dharma/css/_dharma.scss | 5 + res/themes/light/css/_base.scss | 5 + .../views/settings/tabs/GeneralSettingsTab.js | 92 +++++++++++++++++-- src/i18n/strings/en_EN.json | 3 + 6 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 res/img/feather-icons/upload.svg diff --git a/res/css/views/settings/tabs/_GeneralSettingsTab.scss b/res/css/views/settings/tabs/_GeneralSettingsTab.scss index 8bc3de8689..caacd0d3c7 100644 --- a/res/css/views/settings/tabs/_GeneralSettingsTab.scss +++ b/res/css/views/settings/tabs/_GeneralSettingsTab.scss @@ -14,12 +14,78 @@ width: 88px; height: 88px; margin-left: 13px; + position: relative; + cursor: pointer; } -.mx_GeneralSettingsTab_profileAvatar div { +.mx_GeneralSettingsTab_profileAvatar > * { display: block; width: 88px; height: 88px; border-radius: 4px; - background-color: #ccc; +} + +.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; } \ No newline at end of file diff --git a/res/img/feather-icons/upload.svg b/res/img/feather-icons/upload.svg new file mode 100644 index 0000000000..8ec5d95c2c --- /dev/null +++ b/res/img/feather-icons/upload.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index 235eb02e3c..ed5620d30f 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -120,6 +120,11 @@ $blockquote-bar-color: #ddd; $blockquote-fg-color: #777; $settings-grey-fg-color: #a2a2a2; +$settings-profile-placeholder-bg-color: #e7e7e7; +$settings-profile-overlay-bg-color: #000; +$settings-profile-overlay-placeholder-bg-color: transparent; +$settings-profile-overlay-fg-color: #fff; +$settings-profile-overlay-placeholder-fg-color: #454545; $voip-decline-color: #f48080; $voip-accept-color: #80f480; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index 1522ee82a0..d7b135a74e 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -113,6 +113,11 @@ $blockquote-bar-color: #ddd; $blockquote-fg-color: #777; $settings-grey-fg-color: #a2a2a2; +$settings-profile-placeholder-bg-color: #e7e7e7; +$settings-profile-overlay-bg-color: #000; +$settings-profile-overlay-placeholder-bg-color: transparent; +$settings-profile-overlay-fg-color: #fff; +$settings-profile-overlay-placeholder-fg-color: #454545; $voip-decline-color: #f48080; $voip-accept-color: #80f480; diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index c248ba23dd..993061eaa0 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -19,19 +19,34 @@ 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 GeneralSettingsTab 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: client.getUserId(), - displayName: client.getUser(client.getUserId()).displayName, + 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(); @@ -39,12 +54,26 @@ export default class GeneralSettingsTab extends React.Component { if (!this.state.enableProfileSave) return; this.setState({enableProfileSave: false}); + const client = MatrixClientPeg.get(); + const newState = {}; + // TODO: What do we do about errors? - await MatrixClientPeg.get().setDisplayName(this.state.displayName); - // TODO: Support avatars + if (this.state.originalDisplayName !== this.state.displayName) { + await client.setDisplayName(this.state.displayName); + newState.originalDisplayName = this.state.displayName; + } - this.setState({enableProfileSave: true}); + 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) => { @@ -54,19 +83,66 @@ export default class GeneralSettingsTab extends React.Component { }); }; + _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); + }; + _renderProfileSection() { - // TODO: Ditch avatar placeholder and use the real thing + // 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 = {_t("Profile + } + + const avatarOverlayClasses = classNames({ + "mx_GeneralSettingsTab_profileAvatarOverlay": true, + "mx_GeneralSettingsTab_profileAvatarOverlay_show": showOverlayAnyways, + }); + let avatarHoverElement = ( +
+ {_t("Upload profile picture")} +
+
+
+
+ ); + const form = (
+

{this.state.userId}

-
+ {avatarElement} + {avatarHoverElement}
Date: Mon, 21 Jan 2019 23:08:01 -0700 Subject: [PATCH 03/15] Bring flair into the new settings Makes the flair options in old settings look broken (cosmetic issues), but it's fine because we're ripping that out in due time. --- res/css/views/groups/_GroupUserSettings.scss | 1 - res/css/views/settings/tabs/_SettingsTab.scss | 11 +++++++--- res/themes/dharma/css/_dharma.scss | 1 + res/themes/light/css/_base.scss | 1 + .../views/groups/GroupUserSettings.js | 11 ++++------ .../views/settings/tabs/GeneralSettingsTab.js | 21 ++++++++++++++++++- src/i18n/strings/en_EN.json | 3 +-- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/res/css/views/groups/_GroupUserSettings.scss b/res/css/views/groups/_GroupUserSettings.scss index 0c909b7cf7..b207aa2958 100644 --- a/res/css/views/groups/_GroupUserSettings.scss +++ b/res/css/views/groups/_GroupUserSettings.scss @@ -18,6 +18,5 @@ limitations under the License. height: 200px; border: 1px solid $primary-hairline-color; border-radius: 3px; - margin-right: 32px; overflow: hidden; } diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss index 0753df56af..c86fb1f41e 100644 --- a/res/css/views/settings/tabs/_SettingsTab.scss +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -10,8 +10,13 @@ font-family: $font-family-semibold; color: $primary-fg-color; margin-bottom: 10px; -} - -.mx_SettingsTab_section { margin-top: 10px; } + +.mx_SettingsTab_subsectionText { + color: $settings-subsection-fg-color; + font-size: 12px; + padding-bottom: 12px; + margin: 0; + display: block; +} diff --git a/res/themes/dharma/css/_dharma.scss b/res/themes/dharma/css/_dharma.scss index ed5620d30f..f54c058220 100644 --- a/res/themes/dharma/css/_dharma.scss +++ b/res/themes/dharma/css/_dharma.scss @@ -125,6 +125,7 @@ $settings-profile-overlay-bg-color: #000; $settings-profile-overlay-placeholder-bg-color: transparent; $settings-profile-overlay-fg-color: #fff; $settings-profile-overlay-placeholder-fg-color: #454545; +$settings-subsection-fg-color: #61708b; $voip-decline-color: #f48080; $voip-accept-color: #80f480; diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss index d7b135a74e..fce4e93112 100644 --- a/res/themes/light/css/_base.scss +++ b/res/themes/light/css/_base.scss @@ -118,6 +118,7 @@ $settings-profile-overlay-bg-color: #000; $settings-profile-overlay-placeholder-bg-color: transparent; $settings-profile-overlay-fg-color: #fff; $settings-profile-overlay-placeholder-fg-color: #454545; +$settings-subsection-fg-color: #61708b; $voip-decline-color: #f48080; $voip-accept-color: #80f480; diff --git a/src/components/views/groups/GroupUserSettings.js b/src/components/views/groups/GroupUserSettings.js index 0405d411d2..a349a34caf 100644 --- a/src/components/views/groups/GroupUserSettings.js +++ b/src/components/views/groups/GroupUserSettings.js @@ -68,15 +68,12 @@ export default React.createClass({ text = _t("You're not currently a member of any communities."); } - return
-

{ _t('Flair') }

-
-

- { text } -

+ return ( +
+

{ text }

{ scrollbox }
-
; + ); }, render() { diff --git a/src/components/views/settings/tabs/GeneralSettingsTab.js b/src/components/views/settings/tabs/GeneralSettingsTab.js index 993061eaa0..f57609625f 100644 --- a/src/components/views/settings/tabs/GeneralSettingsTab.js +++ b/src/components/views/settings/tabs/GeneralSettingsTab.js @@ -20,8 +20,16 @@ import MatrixClientPeg from "../../../../MatrixClientPeg"; import Field from "../../elements/Field"; import AccessibleButton from "../../elements/AccessibleButton"; import classNames from 'classnames'; +import GroupUserSettings from "../../groups/GroupUserSettings"; +import PropTypes from "prop-types"; +import {MatrixClient} from "matrix-js-sdk"; +import { DragDropContext } from 'react-beautiful-dnd'; export default class GeneralSettingsTab extends React.Component { + static childContextTypes = { + matrixClient: PropTypes.instanceOf(MatrixClient), + }; + constructor() { super(); @@ -40,6 +48,12 @@ export default class GeneralSettingsTab extends React.Component { }; } + getChildContext() { + return { + matrixClient: MatrixClientPeg.get(), + }; + } + _uploadAvatar = (e) => { e.stopPropagation(); e.preventDefault(); @@ -149,14 +163,19 @@ export default class GeneralSettingsTab extends React.Component { disabled={!this.state.enableProfileSave}> {_t("Save")} -
FLAIR
); + // HACK/TODO: Using DragDropContext feels wrong, but we need it. return (
{_t("Profile")} {form} + + {_t("Flair")} + + +
); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c61c806830..42046cba19 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -404,10 +404,10 @@ "Noisy": "Noisy", "Profile picture": "Profile picture", "Upload profile picture": "Upload profile picture", - "Upload": "Upload", "Display Name": "Display Name", "Save": "Save", "Profile": "Profile", + "Flair": "Flair", "Account": "Account", "Language and region": "Language and region", "Theme": "Theme", @@ -680,7 +680,6 @@ "New address (e.g. #foo:%(localDomain)s)": "New address (e.g. #foo:%(localDomain)s)", "Invalid community ID": "Invalid community ID", "'%(groupId)s' is not a valid community ID": "'%(groupId)s' is not a valid community ID", - "Flair": "Flair", "Showing flair for these communities:": "Showing flair for these communities:", "This room is not showing flair for any communities": "This room is not showing flair for any communities", "New community ID (e.g. +foo:%(localDomain)s)": "New community ID (e.g. +foo:%(localDomain)s)", From 19de6694ca642f6d066c077ca5df3744585619bd Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 22 Jan 2019 13:09:40 -0700 Subject: [PATCH 04/15] Bring in the change password section This also changes the layout slightly in the user settings, but nothing detrimental. --- .../settings/tabs/_GeneralSettingsTab.scss | 18 +++++++ src/components/structures/UserSettings.js | 4 +- .../views/dialogs/SetPasswordDialog.js | 5 +- src/components/views/elements/Field.js | 5 ++ .../views/settings/ChangePassword.js | 39 +++++--------- .../views/settings/tabs/GeneralSettingsTab.js | 52 ++++++++++++++++++- src/i18n/strings/en_EN.json | 7 +-- 7 files changed, 94 insertions(+), 36 deletions(-) diff --git a/res/css/views/settings/tabs/_GeneralSettingsTab.scss b/res/css/views/settings/tabs/_GeneralSettingsTab.scss index caacd0d3c7..097d81dab4 100644 --- a/res/css/views/settings/tabs/_GeneralSettingsTab.scss +++ b/res/css/views/settings/tabs/_GeneralSettingsTab.scss @@ -88,4 +88,22 @@ .mx_GeneralSettingsTab_profileAvatarUpload { display: none; +} + +.mx_GeneralSettingsTab_changePassword { + display: block; +} + +.mx_GeneralSettingsTab_changePassword .mx_Field { + display: block; + margin-right: 100px; // Align with the other fields on the page +} + +.mx_GeneralSettingsTab_changePassword .mx_Field input { + display: block; + width: calc(100% - 20px); // subtract 10px padding on left and right +} + +.mx_GeneralSettingsTab_changePassword .mx_Field:first-child { + margin-top: 0; } \ No newline at end of file diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 65e1897137..f8d9e2dd84 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -1268,9 +1268,7 @@ module.exports = React.createClass({ ); diff --git a/src/components/views/dialogs/SetPasswordDialog.js b/src/components/views/dialogs/SetPasswordDialog.js index 42c35ad187..fe3a2216f4 100644 --- a/src/components/views/dialogs/SetPasswordDialog.js +++ b/src/components/views/dialogs/SetPasswordDialog.js @@ -116,9 +116,8 @@ export default React.createClass({