diff --git a/src/Avatar.js b/src/Avatar.js new file mode 100644 index 0000000000..02025a9384 --- /dev/null +++ b/src/Avatar.js @@ -0,0 +1,53 @@ +/* +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. +*/ + +'use strict'; + +var MatrixClientPeg = require('./MatrixClientPeg'); + +module.exports = { + avatarUrlForMember: function(member, width, height, resizeMethod) { + var url = member.getAvatarUrl( + MatrixClientPeg.get().getHomeserverUrl(), + width, + height, + resizeMethod + ); + if (!url) { + // member can be null here currently since on invites, the JS SDK + // does not have enough info to build a RoomMember object for + // the inviter. + url = this.defaultAvatarUrlForString(member ? member.userId : ''); + } + return url; + }, + + defaultAvatarUrlForString: function(s) { + var total = 0; + for (var i = 0; i < s.length; ++i) { + total += s.charCodeAt(i); + } + switch (total % 3) { + case 0: + return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9QjNbxSKP4eagAFnTseHFErFYLBaLxWKxWCwWi8Vi8cX4CzAABSwCRWJw31gAAAAASUVORK5CYII="; + case 1: + return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9chOaxgCP4eagAFk9seHFErFYLBaLxWKxWCwWi8Vi8cX4CzAAtKMCks/JG8MAAAAASUVORK5CYII="; + case 2: + return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9YzNayQCP4eagADldseHFErFYLBaLxWKxWCwWi8Vi8cX4CzAAyiACeHwPiu4AAAAASUVORK5CYII="; + } + } +} + diff --git a/src/controllers/atoms/MemberAvatar.js b/src/components/views/avatars/MemberAvatar.js similarity index 56% rename from src/controllers/atoms/MemberAvatar.js rename to src/components/views/avatars/MemberAvatar.js index e170d2e04c..f65f11256b 100644 --- a/src/controllers/atoms/MemberAvatar.js +++ b/src/components/views/avatars/MemberAvatar.js @@ -17,9 +17,12 @@ limitations under the License. 'use strict'; var React = require('react'); -var MatrixClientPeg = require('../../MatrixClientPeg'); +var Avatar = require('../../../Avatar'); +var MatrixClientPeg = require('../../../MatrixClientPeg'); + +module.exports = React.createClass({ + displayName: 'MemberAvatar', -module.exports = { propTypes: { member: React.PropTypes.object.isRequired, width: React.PropTypes.number, @@ -87,5 +90,53 @@ module.exports = { return { imageUrl: this._computeUrl() }; + }, + + + /////////////// + + + avatarUrlForMember: function(member) { + return Avatar.avatarUrlForMember( + member, + this.props.member, + this.props.width, + this.props.height, + this.props.resizeMethod + ); + }, + + skinnedDefaultAvatarUrl: function(member, width, height, resizeMethod) { + return Avatar.defaultAvatarUrlForString(member.userId); + }, + + render: function() { + // XXX: recalculates default avatar url constantly + if (this.state.imageUrl === this.defaultAvatarUrl(this.props.member)) { + var initial; + if (this.props.member.name[0]) + initial = this.props.member.name[0].toUpperCase(); + if (initial === '@' && this.props.member.name[1]) + initial = this.props.member.name[1].toUpperCase(); + + return ( + + + + + ); + } + return ( + + ); } -}; +}); diff --git a/src/controllers/atoms/RoomAvatar.js b/src/components/views/avatars/RoomAvatar.js similarity index 65% rename from src/controllers/atoms/RoomAvatar.js rename to src/components/views/avatars/RoomAvatar.js index 57c9a71842..55f0e92cc1 100644 --- a/src/controllers/atoms/RoomAvatar.js +++ b/src/components/views/avatars/RoomAvatar.js @@ -13,18 +13,12 @@ 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 React = require('react'); +var MatrixClientPeg = require('../../../MatrixClientPeg'); -'use strict'; +module.exports = React.createClass({ + displayName: 'RoomAvatar', -var MatrixClientPeg = require('../../MatrixClientPeg'); - -/* - * View class should provide: - * - getUrlList() returning an array of URLs to try for the room avatar - in order of preference from the most preferred at index 0. null entries - in the array will be skipped over. - */ -module.exports = { getDefaultProps: function() { return { width: 36, @@ -124,5 +118,58 @@ module.exports = { this.setState({ imageUrl: this._nextUrl() }); + }, + + + + //////////// + + + getUrlList: function() { + return [ + this.roomAvatarUrl(), + this.getOneToOneAvatar(), + this.getFallbackAvatar() + ]; + }, + + getFallbackAvatar: function() { + var images = [ '76cfa6', '50e2c2', 'f4c371' ]; + var total = 0; + for (var i = 0; i < this.props.room.roomId.length; ++i) { + total += this.props.room.roomId.charCodeAt(i); + } + return 'img/' + images[total % images.length] + '.png'; + }, + + render: function() { + var style = { + width: this.props.width, + height: this.props.height, + }; + + // XXX: recalculates fallback avatar constantly + if (this.state.imageUrl === this.getFallbackAvatar()) { + var initial; + if (this.props.room.name[0]) + initial = this.props.room.name[0].toUpperCase(); + if ((initial === '@' || initial === '#') && this.props.room.name[1]) + initial = this.props.room.name[1].toUpperCase(); + + return ( + + + + + ); + } + else { + return + } } -}; +}); diff --git a/src/components/login/CaptchaForm.js b/src/components/views/login/CaptchaForm.js similarity index 100% rename from src/components/login/CaptchaForm.js rename to src/components/views/login/CaptchaForm.js diff --git a/src/components/login/CasLogin.js b/src/components/views/login/CasLogin.js similarity index 95% rename from src/components/login/CasLogin.js rename to src/components/views/login/CasLogin.js index 8a45fa0643..9380db9788 100644 --- a/src/components/login/CasLogin.js +++ b/src/components/views/login/CasLogin.js @@ -16,7 +16,7 @@ limitations under the License. 'use strict'; -var MatrixClientPeg = require("../../MatrixClientPeg"); +var MatrixClientPeg = require("../../../MatrixClientPeg"); var React = require('react'); var url = require("url"); diff --git a/src/components/login/PasswordLogin.js b/src/components/views/login/PasswordLogin.js similarity index 100% rename from src/components/login/PasswordLogin.js rename to src/components/views/login/PasswordLogin.js diff --git a/src/controllers/atoms/UserSettingsButton.js b/src/controllers/atoms/UserSettingsButton.js deleted file mode 100644 index 5138111ef8..0000000000 --- a/src/controllers/atoms/UserSettingsButton.js +++ /dev/null @@ -1,27 +0,0 @@ -/* -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. -*/ - -'use strict'; - -var dis = require("../../dispatcher"); - -module.exports = { - onClick: function() { - dis.dispatch({ - action: 'view_user_settings' - }); - }, -};