From 88c5a5e07450d8ad2350856cb7790aee4e0073c0 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 17 Nov 2015 02:14:06 +0000 Subject: [PATCH 1/3] missing copyright --- src/Resend.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Resend.js b/src/Resend.js index 52b7c93654..5d7d7815ce 100644 --- a/src/Resend.js +++ b/src/Resend.js @@ -1,3 +1,19 @@ +/* +Copyright 2015 OpenMarket 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. +*/ + var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var dis = require('matrix-react-sdk/lib/dispatcher'); From 7b3eea0b5845501237b0d8028401eb89170dfb4e Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 17 Nov 2015 02:15:55 +0000 Subject: [PATCH 2/3] experiment with trying to turn UserSettings into a controller-less 'wiring component' which wires together a series of smaller components (in this case, so small they're mainly --- src/skins/vector/css/molecules/RoomHeader.css | 9 + .../vector/css/organisms/UserSettings.css | 98 +++++++ .../vector/views/molecules/RoomHeader.js | 5 + .../vector/views/organisms/UserSettings.js | 271 ++++++++++++++---- src/skins/vector/views/pages/MatrixChat.js | 2 +- 5 files changed, 334 insertions(+), 51 deletions(-) diff --git a/src/skins/vector/css/molecules/RoomHeader.css b/src/skins/vector/css/molecules/RoomHeader.css index 5519c14de5..e033d735cd 100644 --- a/src/skins/vector/css/molecules/RoomHeader.css +++ b/src/skins/vector/css/molecules/RoomHeader.css @@ -94,7 +94,16 @@ limitations under the License. font-size: 24px; font-weight: bold; overflow: hidden; + margin-left: 63px; text-overflow: ellipsis; + width: 100%; +} + +.mx_RoomHeader_simpleHeaderCancel { + float: right; + margin-top: 8px; + padding: 24px; + cursor: pointer; } .mx_RoomHeader_name { diff --git a/src/skins/vector/css/organisms/UserSettings.css b/src/skins/vector/css/organisms/UserSettings.css index 2b0aca3d0f..6511439cac 100644 --- a/src/skins/vector/css/organisms/UserSettings.css +++ b/src/skins/vector/css/organisms/UserSettings.css @@ -19,3 +19,101 @@ limitations under the License. margin-left: auto; margin-right: auto; } + +.mx_UserSettings_spinner { + display: inline-block; + vertical-align: middle; + margin-right: 12px; + width: 32px; + height: 32px; +} + +.mx_UserSettings_button { + display: inline; + vertical-align: middle; + border: 0px; + height: 36px; + border-radius: 36px; + font-weight: 400; + font-size: 16px; + color: #fff; + background-color: #76cfa6; + width: auto; + margin: auto; + padding: 7px; + padding-left: 1.5em; + padding-right: 1.5em; + cursor: pointer; +} + +.mx_UserSettings h2 { + clear: both; + margin-top: 32px; + margin-bottom: 8px; + margin-left: 63px; + padding-bottom: 6px; + border-bottom: 1px solid #eee; +} + +.mx_UserSettings_section { + margin-left: 63px; + margin-top: 28px; + margin-bottom: 28px; +} + +.mx_UserSettings_profileTable, +.mx_UserSettings_notifTable +{ + display: table; +} + +.mx_UserSettings_profileTableRow, +.mx_UserSettings_notifTableRow +{ + display: table-row; +} + +.mx_UserSettings_profileLabelCell +{ + padding-bottom: 21px; + display: table-cell; + font-weight: bold; + padding-right: 24px; +} + +.mx_UserSettings_profileInputCell { + display: table-cell; + padding-bottom: 21px; + width: 240px; +} + +.mx_UserSettings_profileInputCell input { + border: 0px; + border-bottom: 1px solid rgba(151, 151, 151, 0.5); + padding: 0px; + width: 240px; + color: rgba(74, 74, 74, 0.9); + font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif; + font-size: 16px; +} + +.mx_UserSettings_notifInputCell { + display: table-cell; + padding-bottom: 21px; + padding-right: 8px; + width: 16px; +} + +.mx_UserSettings_notifLabelCell +{ + padding-bottom: 21px; + width: 270px; + display: table-cell; +} + +.mx_UserSettings_logout, +.mx_UserSettings_save { + float: right; + margin-right: 24px; + margin-bottom: 24px; +} \ No newline at end of file diff --git a/src/skins/vector/views/molecules/RoomHeader.js b/src/skins/vector/views/molecules/RoomHeader.js index cc43b1cd01..47ac9cbeaf 100644 --- a/src/skins/vector/views/molecules/RoomHeader.js +++ b/src/skins/vector/views/molecules/RoomHeader.js @@ -48,10 +48,15 @@ module.exports = React.createClass({ var header; if (this.props.simpleHeader) { + var cancel; + if (this.props.onCancelClick) { + cancel = Close + } header =
{ this.props.simpleHeader } + { cancel }
} diff --git a/src/skins/vector/views/organisms/UserSettings.js b/src/skins/vector/views/organisms/UserSettings.js index ab376ea476..5e1574f185 100644 --- a/src/skins/vector/views/organisms/UserSettings.js +++ b/src/skins/vector/views/organisms/UserSettings.js @@ -15,15 +15,142 @@ limitations under the License. var React = require('react'); var sdk = require('matrix-react-sdk') +var dis = require('matrix-react-sdk/lib/dispatcher') var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); +var q = require('q'); -var UserSettingsController = require('matrix-react-sdk/lib/controllers/organisms/UserSettings') +var version = require('../../../../../package.json').version; var Modal = require('matrix-react-sdk/lib/Modal'); +var UserSettingsStore = require('matrix-react-sdk/lib/UserSettingsStore'); module.exports = React.createClass({ displayName: 'UserSettings', - mixins: [UserSettingsController], + + Phases: { + Loading: "loading", + Saving: "saving", + Display: "display", + }, + + getInitialState: function() { + return { + avatarUrl: null, + displayName: null, + threePids: [], + clientVersion: version, + phase: this.Phases.Loading, + }; + }, + + componentWillMount: function() { + var self = this; + + var profilePromise = UserSettingsStore.loadProfileInfo(); + var threepidPromise = UserSettingsStore.loadThreePids(); + + q.all([profilePromise, threepidPromise]).then( + function(resps) { + self.setState({ + avatarUrl: resps[0].avatar_url, + displayName: resps[0].displayname, + threepids: resps[1].threepids, + phase: self.Phases.Display, + }); + + // keep a copy of the original state in order to track changes + self.setState({ + originalState: self.state + }); + }, + function(error) { + var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Can't load user settings", + description: error.toString() + }); + } + ); + }, + + componentDidMount: function() { + this.dispatcherRef = dis.register(this.onAction); + }, + + componentWillUnmount: function() { + dis.unregister(this.dispatcherRef); + }, + + onSaveClicked: function(ev) { + var self = this; + var savePromises = []; + + // XXX: this is managed in ChangeAvatar.js, although could be moved out here in order + // to allow for the change to be staged alongside the rest of the form. + // + // if (this.state.originalState.avatarUrl !== this.state.avatarUrl) { + // savePromises.push( UserSettingsStore.saveAvatarUrl(this.state.avatarUrl) ); + // } + + if (this.state.originalState.displayName !== this.state.displayName) { + savePromises.push( UserSettingsStore.saveDisplayName(this.state.displayName) ); + } + + if (this.state.originalState.threepids.length !== this.state.threepids.length || + this.state.originalState.threepids.every(function(element, index) { + return element === this.state.threepids[index]; + })) + { + savePromises.push( UserSettingsStore.saveThreePids(this.state.threepids) ); + } + + self.setState({ + phase: self.Phases.Saving, + }); + + q.all(savePromises).then( + function(resps) { + self.setState({ + phase: self.Phases.Display, + }); + self.onClose(); + }, + function(error) { + self.setState({ + phase: self.Phases.Display, + }); + var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Can't save user settings", + description: error.toString() + }); + } + ); + }, + + onClose: function(ev) { + // XXX: use browser history instead to find the previous room? + if (this.props.roomId) { + dis.dispatch({ + action: 'view_room', + room_id: this.props.roomId, + }); + } + else { + dis.dispatch({ + action: 'view_indexed_room', + roomIndex: 0, + }); + } + }, + + onAction: function(payload) { + if (payload.action === "notifier_enabled") { + this.setState({ + enableNotifications : UserSettingsStore.getEnableNotifications() + }); + } + }, editAvatar: function() { var url = MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl); @@ -39,20 +166,11 @@ module.exports = React.createClass({ this.avatarDialog = Modal.createDialogWithElement(avatarDialog); }, - addEmail: function() { - + onAvatarDialogCancel: function() { + this.avatarDialog.close(); }, - editDisplayName: function() { - this.refs.displayname.edit(); - }, - - changePassword: function() { - var ChangePassword = sdk.getComponent('molecules.ChangePassword'); - Modal.createDialog(ChangePassword); - }, - - onLogoutClicked: function(ev) { + onLogoutClicked: function(event) { var LogoutPrompt = sdk.getComponent('organisms.LogoutPrompt'); this.logoutModal = Modal.createDialog(LogoutPrompt, {onCancel: this.onLogoutPromptCancel}); }, @@ -61,62 +179,115 @@ module.exports = React.createClass({ this.logoutModal.closeDialog(); }, - onAvatarDialogCancel: function() { - this.avatarDialog.close(); + onDisplayNameChange: function(event) { + this.setState({ displayName: event.target.value }); + }, + + onEnableNotificationsChange: function(event) { + // don't bother waiting for Save to be clicked, as that'd be silly + UserSettingsStore.setEnableNotifications( this.refs.enableNotifications.value ); + + this.setState({ + enableNotifications : UserSettingsStore.getEnableNotifications() + }); }, render: function() { - var Loader = sdk.getComponent("atoms.Spinner"); + var Loader = sdk.getComponent("atoms.Spinner"); + var saving; switch (this.state.phase) { case this.Phases.Loading: return + case this.Phases.Saving: + saving = case this.Phases.Display: - var ChangeDisplayName = sdk.getComponent('molecules.ChangeDisplayName'); - var EnableNotificationsButton = sdk.getComponent('atoms.EnableNotificationsButton'); + var RoomHeader = sdk.getComponent('molecules.RoomHeader'); return (
-
-

User Settings

-
-
-
-
Profile Photo
-
Edit
+ + +

Profile

+ +
+
+
+
+ +
+
+ +
-
- -
Edit
+ {this.state.threepids.map(function(val) { + var id = "email-" + val.address; + return ( +
+
+ +
+
+ +
+
+ ); + })} + +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
-
- {this.state.threepids.map(function(val) { - return
{val.address}
; - })} -
+
-
Add email
+
+
-
-

Global Settings

-
-
-
- Change Password -
-
- Version {this.state.clientVersion} -
-
- -
-
- +
+
Log out
+
+ +

Notifications

+ +
+
+
+
+ +
+
+ +
+ +

Advanced

+ +
+
+ Version {this.state.clientVersion} +
+
+ +
+
{ saving }
+
Save and close
+
); } diff --git a/src/skins/vector/views/pages/MatrixChat.js b/src/skins/vector/views/pages/MatrixChat.js index 0553c25a1c..8083902ce7 100644 --- a/src/skins/vector/views/pages/MatrixChat.js +++ b/src/skins/vector/views/pages/MatrixChat.js @@ -111,7 +111,7 @@ module.exports = React.createClass({ right_panel = break; case this.PageTypes.UserSettings: - page_element = + page_element = right_panel = break; case this.PageTypes.CreateRoom: From 79e39429b7efe9475a9c887ec7bdb7e0dc24baea Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 17 Nov 2015 02:40:19 +0000 Subject: [PATCH 3/3] add todo --- src/skins/vector/views/organisms/UserSettings.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/skins/vector/views/organisms/UserSettings.js b/src/skins/vector/views/organisms/UserSettings.js index 5e1574f185..ea38c1bc85 100644 --- a/src/skins/vector/views/organisms/UserSettings.js +++ b/src/skins/vector/views/organisms/UserSettings.js @@ -104,6 +104,8 @@ module.exports = React.createClass({ savePromises.push( UserSettingsStore.saveThreePids(this.state.threepids) ); } + // TODO: do the password check + self.setState({ phase: self.Phases.Saving, });