Merge branch 'develop' of github.com:vector-im/riot-web into t3chguy/devtools-118247

pull/5718/head
Michael Telatynski 2018-01-25 20:59:31 +00:00
commit 04bca93e0d
No known key found for this signature in database
GPG Key ID: 3F879DA5AD802A5E
84 changed files with 670 additions and 465 deletions

View File

@ -1,3 +1,5 @@
<!-- Please report security issues by email to security@matrix.org -->
<!-- This is a bug report template. By following the instructions below and <!-- This is a bug report template. By following the instructions below and
filling out the sections with your information, you will help the us to get all filling out the sections with your information, you will help the us to get all
the necessary data to fix your issue. the necessary data to fix your issue.

View File

@ -3,7 +3,10 @@ dist: trusty
# we don't need sudo, so can run in a container, which makes startup much # we don't need sudo, so can run in a container, which makes startup much
# quicker. # quicker.
sudo: false #
# unfortunately we do temporarily require sudo as a workaround for
# https://github.com/travis-ci/travis-ci/issues/8836
sudo: required
language: node_js language: node_js
node_js: node_js:

View File

@ -13,3 +13,6 @@ include:
* Michael Telatynski (https://github.com/t3chguy) * Michael Telatynski (https://github.com/t3chguy)
Improved consistency of inverted elements in dark theme across browsers Improved consistency of inverted elements in dark theme across browsers
* Alexandr Korsak (https://github.com/oivoodoo)
Improved multiple file uploading

View File

@ -1,3 +1,17 @@
Changes in [0.13.4](https://github.com/vector-im/riot-web/releases/tag/v0.13.4) (2018-01-03)
============================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.13.3...v0.13.4)
* Change config of riot.im electron build to fix some widgets not working. This only affects
electron builds using the riot.im config - for all other builds, this is identical to
v0.13.3.
Changes in [0.13.3](https://github.com/vector-im/riot-web/releases/tag/v0.13.3) (2017-12-04)
============================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.13.2...v0.13.3)
* Bump js-sdk, react-sdk version to pull in fix for [setting room publicity in a group](https://github.com/matrix-org/matrix-js-sdk/commit/aa3201ebb0fff5af2fb733080aa65ed1f7213de6).
Changes in [0.13.2](https://github.com/vector-im/riot-web/releases/tag/v0.13.2) (2017-11-28) Changes in [0.13.2](https://github.com/vector-im/riot-web/releases/tag/v0.13.2) (2017-11-28)
============================================================================================ ============================================================================================
[Full Changelog](https://github.com/vector-im/riot-web/compare/v0.13.1...v0.13.2) [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.13.1...v0.13.2)

View File

@ -128,8 +128,13 @@ You can configure the app by copying `config.sample.json` to
1. `cross_origin_renderer_url`: URL to a static HTML page hosting code to help display 1. `cross_origin_renderer_url`: URL to a static HTML page hosting code to help display
encrypted file attachments. This MUST be hosted on a completely separate domain to encrypted file attachments. This MUST be hosted on a completely separate domain to
anything else since it is used to isolate the privileges of file attachments to this anything else since it is used to isolate the privileges of file attachments to this
domain. Default: `usercontent.riot.im`. This needs to contain v1.html from domain. Default: `https://usercontent.riot.im/v1.html`. This needs to contain v1.html from
https://github.com/matrix-org/usercontent/blob/master/v1.html https://github.com/matrix-org/usercontent/blob/master/v1.html
1. `piwik`: an object containing the following properties:
1. `url`: The URL of the Piwik instance to use for collecting Analytics
1. `whitelistedHSUrls`: a list of HS URLs to not redact from the Analytics
1. `whitelistedISUrls`: a list of IS URLs to not redact from the Analytics
1. `siteId`: The Piwik Site ID to use when sending Analytics to the Piwik server configured above
Running as a Desktop app Running as a Desktop app
======================== ========================
@ -314,31 +319,51 @@ For a developer guide, see the [translating dev doc](docs/translating-dev.md).
Triaging issues Triaging issues
=============== ===============
Issues will be triaged by the core team using the following primary set of tags: Issues will be triaged by the core team using the below set of tags.
priority: Tags are meant to be used in combination - e.g.:
* P1 critical bug == really urgent stuff that should be next in the bugfixing todo list
* "release blocker" == stuff which is blocking us from cutting the next release.
* P1 feature type:voip == what VoIP features should we be working on next?
* P1: top priority; typically blocks releases priority: **compulsory**
* P1: top priority - i.e. pool of stuff which we should be working on next
* P2: still need to fix, but lower than P1 * P2: still need to fix, but lower than P1
* P3: non-urgent * P3: non-urgent
* P4: intereseting idea - bluesky some day * P4: interesting idea - bluesky some day
* P5: recorded for posterity/to avoid duplicates. No intention to resolves right now. * P5: recorded for posterity/to avoid duplicates. No intention to resolves right now.
bug or feature: bug or feature: **compulsory**
* bug * bug
* feature * feature
bug severity: bug severity: **compulsory, if bug**
* cosmetic - feature works functionally but UI/UX is broken
* critical - whole app doesn't work * critical - whole app doesn't work
* major - entire feature doesn't work * major - entire feature doesn't work
* minor - partially broken feature (but still usable) * minor - partially broken feature (but still usable)
* cosmetic - feature works functionally but UI/UX is broken
additional categories: types
* type:* - refers to a particular part of the app; used to filter bugs
on a given topic - e.g. VOIP, signup, timeline, etc.
additional categories (self-explanatory):
* release blocker * release blocker
* ui/ux (think of this as cosmetic) * ui/ux (think of this as cosmetic)
* network (specific to network conditions) * network (specific to network conditions)
* platform (platform specific) * platform specific
* accessibility
* maintenance
* performance
* i18n
* blocked - whether this issue currently can't be progressed due to outside factors
community engagement
* easy
* hacktoberfest
* bounty? - proposal to be included in a bounty programme
* bounty - included in Status Open Bounty

View File

@ -24,6 +24,8 @@
"welcomeUserId": "@riot-bot:matrix.org", "welcomeUserId": "@riot-bot:matrix.org",
"piwik": { "piwik": {
"url": "https://piwik.riot.im/", "url": "https://piwik.riot.im/",
"whitelistedHSUrls": ["https://matrix.org"],
"whitelistedISUrls": ["https://vector.im", "https://matrix.org"],
"siteId": 1 "siteId": 1
} }
} }

View File

@ -2,7 +2,7 @@
"name": "riot-web", "name": "riot-web",
"productName": "Riot", "productName": "Riot",
"main": "src/electron-main.js", "main": "src/electron-main.js",
"version": "0.13.2", "version": "0.13.4",
"description": "A feature-rich client for Matrix.org", "description": "A feature-rich client for Matrix.org",
"author": "Vector Creations Ltd.", "author": "Vector Creations Ltd.",
"dependencies": { "dependencies": {

View File

@ -5,6 +5,10 @@
"brand": "Riot", "brand": "Riot",
"integrations_ui_url": "https://scalar.vector.im/", "integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api", "integrations_rest_url": "https://scalar.vector.im/api",
"integrations_widgets_urls": [
"https://scalar-staging.riot.im/scalar/api",
"https://scalar.vector.im/api"
],
"bug_report_endpoint_url": "https://riot.im/bugreports/submit", "bug_report_endpoint_url": "https://riot.im/bugreports/submit",
"welcomeUserId": "@riot-bot:matrix.org", "welcomeUserId": "@riot-bot:matrix.org",
"roomDirectory": { "roomDirectory": {

View File

@ -2,9 +2,9 @@
"name": "riot-web", "name": "riot-web",
"productName": "Riot", "productName": "Riot",
"main": "electron_app/src/electron-main.js", "main": "electron_app/src/electron-main.js",
"version": "0.13.2", "version": "0.13.4",
"description": "A feature-rich client for Matrix.org", "description": "A feature-rich client for Matrix.org",
"author": "Vector Creations Ltd.", "author": "New Vector Ltd.",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/vector-im/riot-web" "url": "https://github.com/vector-im/riot-web"
@ -68,14 +68,13 @@
"gfm.css": "^1.1.1", "gfm.css": "^1.1.1",
"highlight.js": "^9.0.0", "highlight.js": "^9.0.0",
"linkifyjs": "^2.1.3", "linkifyjs": "^2.1.3",
"matrix-js-sdk": "0.9.1", "matrix-js-sdk": "0.9.2",
"matrix-react-sdk": "0.11.2", "matrix-react-sdk": "0.11.3",
"modernizr": "^3.1.0", "modernizr": "^3.1.0",
"pako": "^1.0.5", "pako": "^1.0.5",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"react": "^15.6.0", "react": "^15.6.0",
"react-dnd": "^2.1.4", "react-beautiful-dnd": "^4.0.1",
"react-dnd-html5-backend": "^2.1.2",
"react-dom": "^15.6.0", "react-dom": "^15.6.0",
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef", "react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
"sanitize-html": "^1.11.1", "sanitize-html": "^1.11.1",

View File

@ -16,7 +16,7 @@ const INCLUDE_LANGS = [
{'value': 'el', 'label': 'Ελληνικά'}, {'value': 'el', 'label': 'Ελληνικά'},
{'value': 'eo', 'label': 'Esperanto'}, {'value': 'eo', 'label': 'Esperanto'},
{'value': 'es', 'label': 'Español'}, {'value': 'es', 'label': 'Español'},
{'value': 'eu', 'label': 'Euskal'}, {'value': 'eu', 'label': 'Euskara'},
{'value': 'fi', 'label': 'Suomi'}, {'value': 'fi', 'label': 'Suomi'},
{'value': 'fr', 'label': 'Français'}, {'value': 'fr', 'label': 'Français'},
{'value': 'hu', 'label': 'Magyar'}, {'value': 'hu', 'label': 'Magyar'},

View File

@ -17,10 +17,8 @@ limitations under the License.
'use strict'; 'use strict';
import React from 'react'; import React from 'react';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import classNames from 'classnames'; import classNames from 'classnames';
import KeyCode from 'matrix-react-sdk/lib/KeyCode'; import { KeyCode } from 'matrix-react-sdk/lib/Keyboard';
import sdk from 'matrix-react-sdk'; import sdk from 'matrix-react-sdk';
import dis from 'matrix-react-sdk/lib/dispatcher'; import dis from 'matrix-react-sdk/lib/dispatcher';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
@ -199,4 +197,4 @@ var LeftPanel = React.createClass({
} }
}); });
module.exports = DragDropContext(HTML5Backend)(LeftPanel); module.exports = LeftPanel;

View File

@ -24,7 +24,7 @@ import sdk from 'matrix-react-sdk';
import dis from 'matrix-react-sdk/lib/dispatcher'; import dis from 'matrix-react-sdk/lib/dispatcher';
import { MatrixClient } from 'matrix-js-sdk'; import { MatrixClient } from 'matrix-js-sdk';
import Analytics from 'matrix-react-sdk/lib/Analytics'; import Analytics from 'matrix-react-sdk/lib/Analytics';
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc'; import RateLimitedFunc from 'matrix-react-sdk/lib/ratelimitedfunc';
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton'; import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
import { showGroupInviteDialog, showGroupAddRoomDialog } from 'matrix-react-sdk/lib/GroupAddressPicker'; import { showGroupInviteDialog, showGroupAddRoomDialog } from 'matrix-react-sdk/lib/GroupAddressPicker';
import GroupStoreCache from 'matrix-react-sdk/lib/stores/GroupStoreCache'; import GroupStoreCache from 'matrix-react-sdk/lib/stores/GroupStoreCache';
@ -58,8 +58,8 @@ class HeaderButton extends React.Component {
<div className="mx_RightPanel_headerButton_badge"> <div className="mx_RightPanel_headerButton_badge">
{ this.props.badge ? this.props.badge : <span>&nbsp;</span> } { this.props.badge ? this.props.badge : <span>&nbsp;</span> }
</div> </div>
<TintableSvg src={this.props.iconSrc} width="25" height="25"/> <TintableSvg src={this.props.iconSrc} width="25" height="25" />
{ this.props.isHighlighted ? <div className="mx_RightPanel_headerButton_highlight"></div> : <div/> } { this.props.isHighlighted ? <div className="mx_RightPanel_headerButton_highlight" /> : <div /> }
</AccessibleButton>; </AccessibleButton>;
} }
@ -184,18 +184,17 @@ module.exports = React.createClass({
onRoomStateMember: function(ev, state, member) { onRoomStateMember: function(ev, state, member) {
// redraw the badge on the membership list // redraw the badge on the membership list
if (this.state.phase == this.Phase.RoomMemberList && member.roomId === this.props.roomId) { if (this.state.phase === this.Phase.RoomMemberList && member.roomId === this.props.roomId) {
this._delayedUpdate(); this._delayedUpdate();
} } else if (this.state.phase === this.Phase.RoomMemberInfo && member.roomId === this.props.roomId &&
else if (this.state.phase === this.Phase.RoomMemberInfo && member.roomId === this.props.roomId &&
member.userId === this.state.member.userId) { member.userId === this.state.member.userId) {
// refresh the member info (e.g. new power level) // refresh the member info (e.g. new power level)
this._delayedUpdate(); this._delayedUpdate();
} }
}, },
_delayedUpdate: new rate_limited_func(function() { _delayedUpdate: new RateLimitedFunc(function() {
this.forceUpdate(); this.forceUpdate(); // eslint-disable-line babel/no-invalid-this
}, 500), }, 500),
onAction: function(payload) { onAction: function(payload) {
@ -266,22 +265,23 @@ module.exports = React.createClass({
let inviteGroup; let inviteGroup;
let membersBadge; let membersBadge;
if ((this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) let membersTitle = _t('Members');
if ((this.state.phase === this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo)
&& this.props.roomId && this.props.roomId
) { ) {
const cli = this.context.matrixClient; const cli = this.context.matrixClient;
const room = cli.getRoom(this.props.roomId); const room = cli.getRoom(this.props.roomId);
let userIsInRoom; let isUserInRoom;
if (room) { if (room) {
membersBadge = formatCount(room.getJoinedMembers().length); const numMembers = room.getJoinedMembers().length;
userIsInRoom = room.hasMembershipState( membersTitle = _t('%(count)s Members', { count: numMembers });
this.context.matrixClient.credentials.userId, 'join', membersBadge = <div title={membersTitle}>{ formatCount(numMembers) }</div>;
); isUserInRoom = room.hasMembershipState(this.context.matrixClient.credentials.userId, 'join');
} }
if (userIsInRoom) { if (isUserInRoom) {
inviteGroup = inviteGroup =
<AccessibleButton className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } > <AccessibleButton className="mx_RightPanel_invite" onClick={this.onInviteButtonClick}>
<div className="mx_RightPanel_icon" > <div className="mx_RightPanel_icon" >
<TintableSvg src="img/icon-invite-people.svg" width="35" height="35" /> <TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />
</div> </div>
@ -292,13 +292,13 @@ module.exports = React.createClass({
const isPhaseGroup = [ const isPhaseGroup = [
this.Phase.GroupMemberInfo, this.Phase.GroupMemberInfo,
this.Phase.GroupMemberList this.Phase.GroupMemberList,
].includes(this.state.phase); ].includes(this.state.phase);
let headerButtons = []; let headerButtons = [];
if (this.props.roomId) { if (this.props.roomId) {
headerButtons = [ headerButtons = [
<HeaderButton key="_membersButton" title={_t('Members')} iconSrc="img/icons-people.svg" <HeaderButton key="_membersButton" title={membersTitle} iconSrc="img/icons-people.svg"
isHighlighted={[this.Phase.RoomMemberList, this.Phase.RoomMemberInfo].includes(this.state.phase)} isHighlighted={[this.Phase.RoomMemberList, this.Phase.RoomMemberInfo].includes(this.state.phase)}
clickPhase={this.Phase.RoomMemberList} clickPhase={this.Phase.RoomMemberList}
badge={membersBadge} badge={membersBadge}
@ -336,54 +336,54 @@ module.exports = React.createClass({
// button on these 2 screens or you won't be able to re-expand the panel. // button on these 2 screens or you won't be able to re-expand the panel.
headerButtons.push( headerButtons.push(
<div className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" key="_minimizeButton" <div className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" key="_minimizeButton"
title={ _t("Hide panel") } aria-label={ _t("Hide panel") } onClick={ this.onCollapseClick } title={_t("Hide panel")} aria-label={_t("Hide panel")} onClick={this.onCollapseClick}
> >
<TintableSvg src="img/minimise.svg" width="10" height="16"/> <TintableSvg src="img/minimise.svg" width="10" height="16" />
</div>, </div>,
); );
} }
let panel = <div />; let panel = <div />;
if (!this.props.collapsed) { if (!this.props.collapsed) {
if (this.props.roomId && this.state.phase == this.Phase.RoomMemberList) { if (this.props.roomId && this.state.phase === this.Phase.RoomMemberList) {
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />; panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />;
} else if (this.props.groupId && this.state.phase == this.Phase.GroupMemberList) { } else if (this.props.groupId && this.state.phase === this.Phase.GroupMemberList) {
panel = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />; panel = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />;
} else if (this.state.phase === this.Phase.GroupRoomList) { } else if (this.state.phase === this.Phase.GroupRoomList) {
panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />; panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
} else if (this.state.phase == this.Phase.RoomMemberInfo) { } else if (this.state.phase === this.Phase.RoomMemberInfo) {
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />; panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />;
} else if (this.state.phase == this.Phase.GroupMemberInfo) { } else if (this.state.phase === this.Phase.GroupMemberInfo) {
panel = <GroupMemberInfo panel = <GroupMemberInfo
groupMember={this.state.member} groupMember={this.state.member}
groupId={this.props.groupId} groupId={this.props.groupId}
key={this.state.member.user_id} />; key={this.state.member.user_id} />;
} else if (this.state.phase == this.Phase.GroupRoomInfo) { } else if (this.state.phase === this.Phase.GroupRoomInfo) {
panel = <GroupRoomInfo panel = <GroupRoomInfo
groupRoomId={this.state.groupRoomId} groupRoomId={this.state.groupRoomId}
groupId={this.props.groupId} groupId={this.props.groupId}
key={this.state.groupRoomId} />; key={this.state.groupRoomId} />;
} else if (this.state.phase == this.Phase.NotificationPanel) { } else if (this.state.phase === this.Phase.NotificationPanel) {
panel = <NotificationPanel />; panel = <NotificationPanel />;
} else if (this.state.phase == this.Phase.FilePanel) { } else if (this.state.phase === this.Phase.FilePanel) {
panel = <FilePanel roomId={this.props.roomId} />; panel = <FilePanel roomId={this.props.roomId} />;
} }
} }
if (!panel) { if (!panel) {
panel = <div className="mx_RightPanel_blank"></div>; panel = <div className="mx_RightPanel_blank" />;
} }
if (this.props.groupId && this.state.isUserPrivilegedInGroup) { if (this.props.groupId && this.state.isUserPrivilegedInGroup) {
inviteGroup = isPhaseGroup ? ( inviteGroup = isPhaseGroup ? (
<AccessibleButton className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } > <AccessibleButton className="mx_RightPanel_invite" onClick={this.onInviteButtonClick}>
<div className="mx_RightPanel_icon" > <div className="mx_RightPanel_icon" >
<TintableSvg src="img/icon-invite-people.svg" width="35" height="35" /> <TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />
</div> </div>
<div className="mx_RightPanel_message">{ _t('Invite to this community') }</div> <div className="mx_RightPanel_message">{ _t('Invite to this community') }</div>
</AccessibleButton> </AccessibleButton>
) : ( ) : (
<AccessibleButton className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } > <AccessibleButton className="mx_RightPanel_invite" onClick={this.onInviteButtonClick}>
<div className="mx_RightPanel_icon" > <div className="mx_RightPanel_icon" >
<TintableSvg src="img/icons-room-add.svg" width="35" height="35" /> <TintableSvg src="img/icons-room-add.svg" width="35" height="35" />
</div> </div>
@ -392,19 +392,16 @@ module.exports = React.createClass({
); );
} }
let classes = classNames( const classes = classNames("mx_RightPanel", "mx_fadable", {
"mx_RightPanel", "mx_fadable", "collapsed": this.props.collapsed,
{ "mx_fadable_faded": this.props.disabled,
"collapsed": this.props.collapsed, });
"mx_fadable_faded": this.props.disabled,
}
);
return ( return (
<aside className={classes}> <aside className={classes}>
<div className="mx_RightPanel_header"> <div className="mx_RightPanel_header">
<div className="mx_RightPanel_headerButtonGroup"> <div className="mx_RightPanel_headerButtonGroup">
{headerButtons} { headerButtons }
</div> </div>
</div> </div>
{ panel } { panel }

View File

@ -20,8 +20,8 @@ limitations under the License.
var React = require('react'); var React = require('react');
var ReactDOM = require('react-dom'); var ReactDOM = require('react-dom');
var classNames = require('classnames'); var classNames = require('classnames');
var DropTarget = require('react-dnd').DropTarget;
var sdk = require('matrix-react-sdk'); var sdk = require('matrix-react-sdk');
import { Droppable } from 'react-beautiful-dnd';
import { _t } from 'matrix-react-sdk/lib/languageHandler'; import { _t } from 'matrix-react-sdk/lib/languageHandler';
var dis = require('matrix-react-sdk/lib/dispatcher'); var dis = require('matrix-react-sdk/lib/dispatcher');
var Unread = require('matrix-react-sdk/lib/Unread'); var Unread = require('matrix-react-sdk/lib/Unread');
@ -30,7 +30,8 @@ var RoomNotifs = require('matrix-react-sdk/lib/RoomNotifs');
var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils'); var FormattingUtils = require('matrix-react-sdk/lib/utils/FormattingUtils');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
import Modal from 'matrix-react-sdk/lib/Modal'; import Modal from 'matrix-react-sdk/lib/Modal';
import KeyCode from 'matrix-react-sdk/lib/KeyCode'; import { KeyCode } from 'matrix-react-sdk/lib/Keyboard';
// turn this on for drop & drag console debugging galore // turn this on for drop & drag console debugging galore
var debug = false; var debug = false;
@ -326,44 +327,45 @@ var RoomSubList = React.createClass({
}); });
}, },
calcManualOrderTagData: function(room) { calcManualOrderTagData: function(index) {
var index = this.state.sortedList.indexOf(room);
// we sort rooms by the lexicographic ordering of the 'order' metadata on their tags. // we sort rooms by the lexicographic ordering of the 'order' metadata on their tags.
// for convenience, we calculate this for now a floating point number between 0.0 and 1.0. // for convenience, we calculate this for now a floating point number between 0.0 and 1.0.
var orderA = 0.0; // by default we're next to the beginning of the list let orderA = 0.0; // by default we're next to the beginning of the list
if (index > 0) { if (index > 0) {
var prevTag = this.state.sortedList[index - 1].tags[this.props.tagName]; const prevTag = this.state.sortedList[index - 1].tags[this.props.tagName];
if (!prevTag) { if (!prevTag) {
console.error("Previous room in sublist is not tagged to be in this list. This should never happen.") console.error("Previous room in sublist is not tagged to be in this list. This should never happen.");
} } else if (prevTag.order === undefined) {
else if (prevTag.order === undefined) {
console.error("Previous room in sublist has no ordering metadata. This should never happen."); console.error("Previous room in sublist has no ordering metadata. This should never happen.");
} } else {
else {
orderA = prevTag.order; orderA = prevTag.order;
} }
} }
var orderB = 1.0; // by default we're next to the end of the list too let orderB = 1.0; // by default we're next to the end of the list too
if (index < this.state.sortedList.length - 1) { if (index < this.state.sortedList.length - 1) {
var nextTag = this.state.sortedList[index + 1].tags[this.props.tagName]; const nextTag = this.state.sortedList[index + 1].tags[this.props.tagName];
if (!nextTag) { if (!nextTag) {
console.error("Next room in sublist is not tagged to be in this list. This should never happen.") console.error("Next room in sublist is not tagged to be in this list. This should never happen.");
} } else if (nextTag.order === undefined) {
else if (nextTag.order === undefined) {
console.error("Next room in sublist has no ordering metadata. This should never happen."); console.error("Next room in sublist has no ordering metadata. This should never happen.");
} } else {
else {
orderB = nextTag.order; orderB = nextTag.order;
} }
} }
var order = (orderA + orderB) / 2.0; const order = (orderA + orderB) / 2.0;
if (order === orderA || order === orderB) { if (order === orderA || order === orderB) {
console.error("Cannot describe new list position. This should be incredibly unlikely."); console.error("Cannot describe new list position. This should be incredibly unlikely.");
// TODO: renumber the list this.state.sortedList.forEach((room, index) => {
MatrixClientPeg.get().setRoomTag(
room.roomId, this.props.tagName,
{order: index / this.state.sortedList.length},
);
});
return index / this.state.sortedList.length;
} }
return order; return order;
@ -372,12 +374,14 @@ var RoomSubList = React.createClass({
makeRoomTiles: function() { makeRoomTiles: function() {
var self = this; var self = this;
var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile"); var DNDRoomTile = sdk.getComponent("rooms.DNDRoomTile");
return this.state.sortedList.map(function(room) { return this.state.sortedList.map(function(room, index) {
// XXX: is it evil to pass in self as a prop to RoomTile? // XXX: is it evil to pass in self as a prop to RoomTile?
return ( return (
<DNDRoomTile <DNDRoomTile
index={index} // For DND
room={ room } room={ room }
roomSubList={ self } roomSubList={ self }
tagName={self.props.tagName}
key={ room.roomId } key={ room.roomId }
collapsed={ self.props.collapsed || false} collapsed={ self.props.collapsed || false}
unread={ Unread.doesRoomHaveUnreadMessages(room) } unread={ Unread.doesRoomHaveUnreadMessages(room) }
@ -563,12 +567,18 @@ var RoomSubList = React.createClass({
</TruncatedList>; </TruncatedList>;
} }
return connectDropTarget( const subListContent = <div>
<div> { this._getHeaderJsx() }
{ this._getHeaderJsx() } { subList }
{ subList } </div>;
</div>
); return this.props.editable ? <Droppable droppableId={"room-sub-list-droppable_" + this.props.tagName}>
{ (provided, snapshot) => (
<div ref={provided.innerRef}>
{ subListContent }
</div>
) }
</Droppable> : subListContent;
} }
else { else {
var Loader = sdk.getComponent("elements.Spinner"); var Loader = sdk.getComponent("elements.Spinner");
@ -582,11 +592,4 @@ var RoomSubList = React.createClass({
} }
}); });
// Export the wrapped version, inlining the 'collect' functions module.exports = RoomSubList;
// to more closely resemble the ES7
module.exports =
DropTarget('RoomTile', roomListTarget, function(connect) {
return {
connectDropTarget: connect.dropTarget(),
}
})(RoomSubList);

View File

@ -18,7 +18,7 @@ limitations under the License.
import React from 'react'; import React from 'react';
import { _t } from 'matrix-react-sdk/lib/languageHandler'; import { _t } from 'matrix-react-sdk/lib/languageHandler';
import KeyCode from 'matrix-react-sdk/lib/KeyCode'; import { KeyCode } from 'matrix-react-sdk/lib/Keyboard';
import sdk from 'matrix-react-sdk'; import sdk from 'matrix-react-sdk';
import dis from 'matrix-react-sdk/lib/dispatcher'; import dis from 'matrix-react-sdk/lib/dispatcher';
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc'; import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';

View File

@ -16,14 +16,17 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); import React from 'react';
import PropTypes from 'prop-types';
import SyntaxHighlight from '../views/elements/SyntaxHighlight';
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'ViewSource', displayName: 'ViewSource',
propTypes: { propTypes: {
content: React.PropTypes.object.isRequired, content: PropTypes.object.isRequired,
onFinished: React.PropTypes.func.isRequired, onFinished: PropTypes.func.isRequired,
}, },
componentDidMount: function() { componentDidMount: function() {
@ -45,9 +48,9 @@ module.exports = React.createClass({
render: function() { render: function() {
return ( return (
<div className="mx_ViewSource"> <div className="mx_ViewSource">
<pre> <SyntaxHighlight className="json">
{JSON.stringify(this.props.content, null, 2)} { JSON.stringify(this.props.content, null, 2) }
</pre> </SyntaxHighlight>
</div> </div>
); );
} }

View File

@ -16,15 +16,16 @@ limitations under the License.
'use strict'; 'use strict';
const React = require('react'); import React from 'react';
const MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
const dis = require('matrix-react-sdk/lib/dispatcher'); import dis from 'matrix-react-sdk/lib/dispatcher';
const sdk = require('matrix-react-sdk'); import sdk from 'matrix-react-sdk';
import { _t } from 'matrix-react-sdk/lib/languageHandler'; import { _t } from 'matrix-react-sdk/lib/languageHandler';
const Modal = require('matrix-react-sdk/lib/Modal'); import Modal from 'matrix-react-sdk/lib/Modal';
const Resend = require("matrix-react-sdk/lib/Resend"); import Resend from "matrix-react-sdk/lib/Resend";
import SettingsStore from "matrix-react-sdk/lib/settings/SettingsStore"; import SettingsStore from "matrix-react-sdk/lib/settings/SettingsStore";
import {makeEventPermalink} from 'matrix-react-sdk/lib/matrix-to';
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'MessageContextMenu', displayName: 'MessageContextMenu',
@ -107,15 +108,14 @@ module.exports = React.createClass({
onFinished: (proceed) => { onFinished: (proceed) => {
if (!proceed) return; if (!proceed) return;
MatrixClientPeg.get().redactEvent( const cli = MatrixClientPeg.get();
this.props.mxEvent.getRoomId(), this.props.mxEvent.getId() cli.redactEvent(this.props.mxEvent.getRoomId(), this.props.mxEvent.getId()).catch(function(e) {
).catch(function(e) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
// display error message stating you couldn't delete this. // display error message stating you couldn't delete this.
const code = e.errcode || e.statusCode; const code = e.errcode || e.statusCode;
Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, { Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, {
title: _t('Error'), title: _t('Error'),
description: _t('You cannot delete this message. (%(code)s)', {code: code}) description: _t('You cannot delete this message. (%(code)s)', {code}),
}); });
}).done(); }).done();
}, },
@ -138,12 +138,12 @@ module.exports = React.createClass({
onPinClick: function() { onPinClick: function() {
MatrixClientPeg.get().getStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', '') MatrixClientPeg.get().getStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', '')
.catch(e => { .catch((e) => {
// Intercept the Event Not Found error and fall through the promise chain with no event. // Intercept the Event Not Found error and fall through the promise chain with no event.
if (e.errcode === "M_NOT_FOUND") return null; if (e.errcode === "M_NOT_FOUND") return null;
throw e; throw e;
}) })
.then(event => { .then((event) => {
const eventIds = (event ? event.pinned : []) || []; const eventIds = (event ? event.pinned : []) || [];
if (!eventIds.includes(this.props.mxEvent.getId())) { if (!eventIds.includes(this.props.mxEvent.getId())) {
// Not pinned - add // Not pinned - add
@ -153,7 +153,8 @@ module.exports = React.createClass({
eventIds.splice(eventIds.indexOf(this.props.mxEvent.getId()), 1); eventIds.splice(eventIds.indexOf(this.props.mxEvent.getId()), 1);
} }
MatrixClientPeg.get().sendStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', {pinned: eventIds}, ''); const cli = MatrixClientPeg.get();
cli.sendStateEvent(this.props.mxEvent.getRoomId(), 'm.room.pinned_events', {pinned: eventIds}, '');
}); });
this.closeMenu(); this.closeMenu();
}, },
@ -177,6 +178,14 @@ module.exports = React.createClass({
this.closeMenu(); this.closeMenu();
}, },
onReplyClick: function() {
dis.dispatch({
action: 'quote_event',
event: this.props.mxEvent,
});
this.closeMenu();
},
render: function() { render: function() {
const eventStatus = this.props.mxEvent.status; const eventStatus = this.props.mxEvent.status;
let resendButton; let resendButton;
@ -184,12 +193,11 @@ module.exports = React.createClass({
let cancelButton; let cancelButton;
let forwardButton; let forwardButton;
let pinButton; let pinButton;
let viewSourceButton;
let viewClearSourceButton; let viewClearSourceButton;
let unhidePreviewButton; let unhidePreviewButton;
let permalinkButton;
let externalURLButton; let externalURLButton;
let quoteButton; let quoteButton;
let replyButton;
if (eventStatus === 'not_sent') { if (eventStatus === 'not_sent') {
resendButton = ( resendButton = (
@ -224,17 +232,25 @@ module.exports = React.createClass({
</div> </div>
); );
if (SettingsStore.isFeatureEnabled("feature_rich_quoting")) {
replyButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onReplyClick}>
{ _t('Reply') }
</div>
);
}
if (this.state.canPin) { if (this.state.canPin) {
pinButton = ( pinButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onPinClick}> <div className="mx_MessageContextMenu_field" onClick={this.onPinClick}>
{this._isPinned() ? _t('Unpin Message') : _t('Pin Message')} { this._isPinned() ? _t('Unpin Message') : _t('Pin Message') }
</div> </div>
); );
} }
} }
} }
viewSourceButton = ( const viewSourceButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onViewSourceClick}> <div className="mx_MessageContextMenu_field" onClick={this.onViewSourceClick}>
{ _t('View Source') } { _t('View Source') }
</div> </div>
@ -259,10 +275,10 @@ module.exports = React.createClass({
} }
// XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID) // XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID)
permalinkButton = ( const permalinkButton = (
<div className="mx_MessageContextMenu_field"> <div className="mx_MessageContextMenu_field">
<a href={ "https://matrix.to/#/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId() } <a href={makeEventPermalink(this.props.mxEvent.getRoomId(), this.props.mxEvent.getId())}
target="_blank" rel="noopener" onClick={ this.closeMenu }>{ _t('Permalink') }</a> target="_blank" rel="noopener" onClick={this.closeMenu}>{ _t('Permalink') }</a>
</div> </div>
); );
@ -275,29 +291,30 @@ module.exports = React.createClass({
} }
// Bridges can provide a 'external_url' to link back to the source. // Bridges can provide a 'external_url' to link back to the source.
if( typeof(this.props.mxEvent.event.content.external_url) === "string") { if (typeof(this.props.mxEvent.event.content.external_url) === "string") {
externalURLButton = ( externalURLButton = (
<div className="mx_MessageContextMenu_field"> <div className="mx_MessageContextMenu_field">
<a href={ this.props.mxEvent.event.content.external_url } <a href={this.props.mxEvent.event.content.external_url}
rel="noopener" target="_blank" onClick={ this.closeMenu }>{ _t('Source URL') }</a> rel="noopener" target="_blank" onClick={this.closeMenu}>{ _t('Source URL') }</a>
</div> </div>
); );
} }
return ( return (
<div> <div>
{resendButton} { resendButton }
{redactButton} { redactButton }
{cancelButton} { cancelButton }
{forwardButton} { forwardButton }
{pinButton} { pinButton }
{viewSourceButton} { viewSourceButton }
{viewClearSourceButton} { viewClearSourceButton }
{unhidePreviewButton} { unhidePreviewButton }
{permalinkButton} { permalinkButton }
{quoteButton} { quoteButton }
{externalURLButton} { replyButton }
{ externalURLButton }
</div> </div>
); );
}, },

View File

@ -275,7 +275,7 @@ module.exports = React.createClass({
<div className={ alertMeClasses } onClick={this._onClickAlertMe} > <div className={ alertMeClasses } onClick={this._onClickAlertMe} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" /> <img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off-copy.svg" width="16" height="12" /> <img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off-copy.svg" width="16" height="12" />
{ _t('All messages (loud)') } { _t('All messages (noisy)') }
</div> </div>
<div className={ allNotifsClasses } onClick={this._onClickAllNotifs} > <div className={ allNotifsClasses } onClick={this._onClickAllNotifs} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" /> <img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />

View File

@ -17,6 +17,7 @@ limitations under the License.
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import sdk from 'matrix-react-sdk'; import sdk from 'matrix-react-sdk';
import SyntaxHighlight from '../elements/SyntaxHighlight';
import { _t } from 'matrix-react-sdk/lib/languageHandler'; import { _t } from 'matrix-react-sdk/lib/languageHandler';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
@ -60,7 +61,7 @@ class GenericEditor extends DevtoolsComponent {
<label htmlFor={id}>{ label }</label> <label htmlFor={id}>{ label }</label>
</div> </div>
<div className="mx_DevTools_inputCell"> <div className="mx_DevTools_inputCell">
<input id={id} onChange={this._onChange} value={this.state[id]} size="32" /> <input id={id} className="mx_TextInputDialog_input" onChange={this._onChange} value={this.state[id]} size="32" />
</div> </div>
</div>; </div>;
} }
@ -363,7 +364,9 @@ class RoomStateExplorer extends DevtoolsComponent {
return <div className="mx_ViewSource"> return <div className="mx_ViewSource">
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
<pre>{ JSON.stringify(this.state.event.event, null, 2) }</pre> <SyntaxHighlight className="json">
{ JSON.stringify(this.state.event.event, null, 2) }
</SyntaxHighlight>
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button onClick={this.onBack}>{ _t('Back') }</button> <button onClick={this.onBack}>{ _t('Back') }</button>
@ -492,7 +495,9 @@ class AccountDataExplorer extends DevtoolsComponent {
return <div className="mx_ViewSource"> return <div className="mx_ViewSource">
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
<pre>{ JSON.stringify(this.state.event.event, null, 2) }</pre> <SyntaxHighlight className="json">
{ JSON.stringify(this.state.event.event, null, 2) }
</SyntaxHighlight>
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button onClick={this.onBack}>{ _t('Back') }</button> <button onClick={this.onBack}>{ _t('Back') }</button>

View File

@ -20,7 +20,7 @@ var React = require('react');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var DateUtils = require('matrix-react-sdk/lib/DateUtils'); import {formatDate} from 'matrix-react-sdk/lib/DateUtils';
var filesize = require('filesize'); var filesize = require('filesize');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
const Modal = require('matrix-react-sdk/lib/Modal'); const Modal = require('matrix-react-sdk/lib/Modal');
@ -159,7 +159,7 @@ module.exports = React.createClass({
} }
eventMeta = (<div className="mx_ImageView_metadata"> eventMeta = (<div className="mx_ImageView_metadata">
{ _t('Uploaded on %(date)s by %(user)s', {date: DateUtils.formatDate(new Date(this.props.mxEvent.getTs())), user: sender}) } { _t('Uploaded on %(date)s by %(user)s', {date: formatDate(new Date(this.props.mxEvent.getTs())), user: sender}) }
</div>); </div>);
} }

View File

@ -0,0 +1,53 @@
/*
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
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 PropTypes from 'prop-types';
import {highlightBlock} from 'highlight.js';
export default class SyntaxHighlight extends React.Component {
static propTypes = {
className: PropTypes.string,
children: PropTypes.node,
};
constructor(props, context) {
super(props, context);
this._ref = this._ref.bind(this);
}
// componentDidUpdate used here for reusability
// componentWillReceiveProps fires too early to call highlightBlock on.
componentDidUpdate() {
if (this._el) highlightBlock(this._el);
}
// call componentDidUpdate because _ref is fired on initial render
// which does not fire componentDidUpdate
_ref(el) {
this._el = el;
this.componentDidUpdate();
}
render() {
const { className, children } = this.props;
return <pre className={`${className} mx_SyntaxHighlight`} ref={this._ref}>
<code>{ children }</code>
</pre>;
}
}

View File

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -15,8 +16,9 @@ limitations under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import { _t } from 'matrix-react-sdk/lib/languageHandler'; import { _t } from 'matrix-react-sdk/lib/languageHandler';
import DateUtils from 'matrix-react-sdk/lib/DateUtils'; import {formatFullDateNoTime} from 'matrix-react-sdk/lib/DateUtils';
function getdaysArray() { function getdaysArray() {
return [ return [
@ -30,30 +32,30 @@ function getdaysArray() {
]; ];
} }
module.exports = React.createClass({ export default class DateSeparator extends React.Component {
displayName: 'DateSeparator', static propTypes = {
render: function() { ts: PropTypes.number.isRequired,
var date = new Date(this.props.ts); };
var today = new Date();
var yesterday = new Date();
var days = getdaysArray();
yesterday.setDate(today.getDate() - 1);
var label;
if (date.toDateString() === today.toDateString()) {
label = _t('Today');
}
else if (date.toDateString() === yesterday.toDateString()) {
label = _t('Yesterday');
}
else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
label = days[date.getDay()];
}
else {
label = DateUtils.formatFullDate(date, this.props.showTwelveHour);
}
return ( getLabel() {
<h2 className="mx_DateSeparator">{ label }</h2> const date = new Date(this.props.ts);
); const today = new Date();
const yesterday = new Date();
const days = getdaysArray();
yesterday.setDate(today.getDate() - 1);
if (date.toDateString() === today.toDateString()) {
return _t('Today');
} else if (date.toDateString() === yesterday.toDateString()) {
return _t('Yesterday');
} else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
return days[date.getDay()];
} else {
return formatFullDateNoTime(date);
}
} }
});
render() {
return <h2 className="mx_DateSeparator">{ this.getLabel() }</h2>;
}
}

View File

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -14,24 +15,22 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
'use strict';
import React from 'react'; import React from 'react';
import DateUtils from 'matrix-react-sdk/lib/DateUtils'; import PropTypes from 'prop-types';
import {formatFullDate, formatTime} from 'matrix-react-sdk/lib/DateUtils';
module.exports = React.createClass({ export default class MessageTimestamp extends React.Component {
displayName: 'MessageTimestamp', static propTypes = {
ts: PropTypes.number.isRequired,
showTwelveHour: PropTypes.bool,
};
propTypes: { render() {
showTwelveHour: React.PropTypes.bool,
},
render: function() {
const date = new Date(this.props.ts); const date = new Date(this.props.ts);
return ( return (
<span className="mx_MessageTimestamp" title={ DateUtils.formatFullDate(date, this.props.showTwelveHour) }> <span className="mx_MessageTimestamp" title={formatFullDate(date, this.props.showTwelveHour)}>
{ DateUtils.formatTime(date, this.props.showTwelveHour) } { formatTime(date, this.props.showTwelveHour) }
</span> </span>
); );
}, }
}); }

View File

@ -14,227 +14,51 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
'use strict';
import React from 'react'; import React from 'react';
import {DragSource} from 'react-dnd'; import { Draggable } from 'react-beautiful-dnd';
import {DropTarget} from 'react-dnd';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import sdk from 'matrix-react-sdk';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
import RoomTile from 'matrix-react-sdk/lib/components/views/rooms/RoomTile'; import RoomTile from 'matrix-react-sdk/lib/components/views/rooms/RoomTile';
import * as Rooms from 'matrix-react-sdk/lib/Rooms';
import Modal from 'matrix-react-sdk/lib/Modal';
/** import classNames from 'classnames';
* Defines a new Component, DNDRoomTile that wraps RoomTile, making it draggable.
* Requires extra props:
* roomSubList: React.PropTypes.object.isRequired,
* refreshSubList: React.PropTypes.func.isRequired,
*/
/** export default class DNDRoomTile extends React.Component {
* Specifies the drag source contract. constructor() {
* Only `beginDrag` function is required. super();
*/ this.getClassName = this.getClassName.bind(this);
var roomTileSource = {
canDrag: function(props, monitor) {
return props.roomSubList.props.editable;
},
beginDrag: function (props) {
// Return the data describing the dragged item
var item = {
room: props.room,
originalList: props.roomSubList,
originalIndex: props.roomSubList.findRoomTile(props.room).index,
targetList: props.roomSubList, // at first target is same as original
// lastTargetRoom: null,
// lastYOffset: null,
// lastYDelta: null,
};
if (props.roomSubList.debug) console.log("roomTile beginDrag for " + item.room.roomId);
// doing this 'correctly' with state causes react-dnd to break seemingly due to the state transitions
props.room._dragging = true;
return item;
},
endDrag: function (props, monitor, component) {
var item = monitor.getItem();
if (props.roomSubList.debug) console.log("roomTile endDrag for " + item.room.roomId + " with didDrop=" + monitor.didDrop());
props.room._dragging = false;
if (monitor.didDrop()) {
if (props.roomSubList.debug) console.log("force updating component " + item.targetList.props.label);
item.targetList.forceUpdate(); // as we're not using state
}
const prevTag = item.originalList.props.tagName;
const newTag = item.targetList.props.tagName;
if (monitor.didDrop() && item.targetList.props.editable) {
// Evil hack to get DMs behaving
if ((prevTag === undefined && newTag === 'im.vector.fake.direct') ||
(prevTag === 'im.vector.fake.direct' && newTag === undefined)
) {
Rooms.guessAndSetDMRoom(
item.room, newTag === 'im.vector.fake.direct',
).done(() => {
item.originalList.removeRoomTile(item.room);
}, (err) => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to set direct chat tag " + err);
Modal.createTrackedDialog('Failed to set direct chat tag', '', ErrorDialog, {
title: _t('Failed to set direct chat tag'),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
});
return;
}
// More evilness: We will still be dealing with moving to favourites/low prio,
// but we avoid ever doing a request with 'im.vector.fake.direct`.
// if we moved lists, remove the old tag
if (prevTag && prevTag !== 'im.vector.fake.direct' &&
item.targetList !== item.originalList
) {
// commented out attempts to set a spinner on our target component as component is actually
// the original source component being dragged, not our target. To fix we just need to
// move all of this to endDrop in the target instead. FIXME later.
//component.state.set({ spinner: component.state.spinner ? component.state.spinner++ : 1 });
MatrixClientPeg.get().deleteRoomTag(item.room.roomId, prevTag).finally(function() {
//component.state.set({ spinner: component.state.spinner-- });
}).catch(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to remove tag " + prevTag + " from room: " + err);
Modal.createTrackedDialog('Failed to remove tag from room', '', ErrorDialog, {
title: _t('Failed to remove tag %(tagName)s from room', {tagName: prevTag}),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
});
}
var newOrder= {};
if (item.targetList.props.order === 'manual') {
newOrder['order'] = item.targetList.calcManualOrderTagData(item.room);
}
// if we moved lists or the ordering changed, add the new tag
if (newTag && newTag !== 'im.vector.fake.direct' &&
(item.targetList !== item.originalList || newOrder)
) {
MatrixClientPeg.get().setRoomTag(item.room.roomId, newTag, newOrder).catch(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to add tag " + newTag + " to room: " + err);
Modal.createTrackedDialog('Failed to add tag to room', '', ErrorDialog, {
title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}),
description: ((err && err.message) ? err.message : _t('Operation failed')),
});
});
}
}
else {
// cancel the drop and reset our original position
if (props.roomSubList.debug) console.log("cancelling drop & drag");
props.roomSubList.moveRoomTile(item.room, item.originalIndex);
if (item.targetList && item.targetList !== item.originalList) {
item.targetList.removeRoomTile(item.room);
}
}
} }
};
var roomTileTarget = { getClassName(isDragging) {
canDrop: function() { return classNames({
return false; "mx_DNDRoomTile": true,
}, "mx_DNDRoomTile_dragging": isDragging,
});
hover: function(props, monitor) {
var item = monitor.getItem();
//var off = monitor.getClientOffset();
// console.log("hovering on room " + props.room.roomId + ", isOver=" + monitor.isOver());
//console.log("item.targetList=" + item.targetList + ", roomSubList=" + props.roomSubList);
var switchedTarget = false;
if (item.targetList !== props.roomSubList) {
// we've switched target, so remove the tile from the previous target.
// n.b. the previous target might actually be the source list.
if (props.roomSubList.debug) console.log("switched target sublist");
switchedTarget = true;
item.targetList.removeRoomTile(item.room);
item.targetList = props.roomSubList;
}
if (!item.targetList.props.editable) return;
if (item.targetList.props.order === 'manual') {
if (item.room.roomId !== props.room.roomId && props.room !== item.lastTargetRoom) {
// find the offset of the target tile in the list.
var roomTile = props.roomSubList.findRoomTile(props.room);
// shuffle the list to add our tile to that position.
props.roomSubList.moveRoomTile(item.room, roomTile.index);
}
// stop us from flickering between our droptarget and the previous room.
// whenever the cursor changes direction we have to reset the flicker-damping.
/*
var yDelta = off.y - item.lastYOffset;
if ((yDelta > 0 && item.lastYDelta < 0) ||
(yDelta < 0 && item.lastYDelta > 0))
{
// the cursor changed direction - forget our previous room
item.lastTargetRoom = null;
}
else {
// track the last room we were hovering over so we can stop
// bouncing back and forth if the droptarget is narrower than
// the other list items. The other way to do this would be
// to reduce the size of the hittarget on the list items, but
// can't see an easy way to do that.
item.lastTargetRoom = props.room;
}
if (yDelta) item.lastYDelta = yDelta;
item.lastYOffset = off.y;
*/
}
else if (switchedTarget) {
if (!props.roomSubList.findRoomTile(item.room).room) {
// add to the list in the right place
props.roomSubList.moveRoomTile(item.room, 0);
}
// we have to sort the list whatever to recalculate it
props.roomSubList.sortList();
}
},
};
// Export the wrapped version, inlining the 'collect' functions
// to more closely resemble the ES7
module.exports =
DropTarget('RoomTile', roomTileTarget, function(connect, monitor) {
return {
// Call this function inside render()
// to let React DnD handle the drag events:
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
} }
})(
DragSource('RoomTile', roomTileSource, function(connect, monitor) { render() {
return { const props = this.props;
// Call this function inside render()
// to let React DnD handle the drag events: return <div>
connectDragSource: connect.dragSource(), <Draggable
// You can ask the monitor about the current drag state: key={props.room.roomId}
isDragging: monitor.isDragging() draggableId={props.tagName + '_' + props.room.roomId}
}; index={props.index}
})(RoomTile)); >
{ (provided, snapshot) => {
return (
<div>
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<div className={this.getClassName(snapshot.isDragging)}>
<RoomTile {...props} />
</div>
</div>
{ provided.placeholder }
</div>
);
} }
</Draggable>
</div>;
}
}

View File

@ -8,7 +8,7 @@
"All Rooms": "كل الغُرف", "All Rooms": "كل الغُرف",
"<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">متصفح سافاري</a> و <a href=\"http://opera.com\">متصفح أوبرا</a> يعملان أيضاً.", "<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">متصفح سافاري</a> و <a href=\"http://opera.com\">متصفح أوبرا</a> يعملان أيضاً.",
"Add an email address above to configure email notifications": "أضف بريداً إلكترونياً أعلاه من أجل تعديل إعدادت تنبيهات البريد الإلكتروني", "Add an email address above to configure email notifications": "أضف بريداً إلكترونياً أعلاه من أجل تعديل إعدادت تنبيهات البريد الإلكتروني",
"All messages (loud)": "كل الرسائل (صوت مرتفع)", "All messages (noisy)": "كل الرسائل (صوت مرتفع)",
"All notifications are currently disabled for all targets.": "كل التنبيهات غير مفعلة حالياً للجميع.", "All notifications are currently disabled for all targets.": "كل التنبيهات غير مفعلة حالياً للجميع.",
"An error occurred whilst saving your email notification preferences.": "حدث خطأ ما خلال حفظ إعدادات التنبيهات للبريد الإلكتروني.", "An error occurred whilst saving your email notification preferences.": "حدث خطأ ما خلال حفظ إعدادات التنبيهات للبريد الإلكتروني.",
"Call invitation": "دعوة لمحادثة", "Call invitation": "دعوة لمحادثة",

View File

@ -1,7 +1,7 @@
{ {
"Add an email address above to configure email notifications": "Дадайце адрас электроннай пошты вышэй, каб наладзіць апавяшчэнні", "Add an email address above to configure email notifications": "Дадайце адрас электроннай пошты вышэй, каб наладзіць апавяшчэнні",
"All messages": "Усе паведамленні", "All messages": "Усе паведамленні",
"All messages (loud)": "Усе паведамленні (гучна)", "All messages (noisy)": "Усе паведамленні (гучна)",
"All notifications are currently disabled for all targets.": "Усе апавяшчэнні ў цяперашні час адключаныя для ўсіх мэтаў.", "All notifications are currently disabled for all targets.": "Усе апавяшчэнні ў цяперашні час адключаныя для ўсіх мэтаў.",
"An error occurred whilst saving your email notification preferences.": "Адбылася памылка падчас захавання налады апавяшчэнняў па электроннай пошце.", "An error occurred whilst saving your email notification preferences.": "Адбылася памылка падчас захавання налады апавяшчэнняў па электроннай пошце.",
"Cancel Sending": "Адмяніць адпраўку", "Cancel Sending": "Адмяніць адпраўку",

View File

@ -14,7 +14,7 @@
"Failed to remove tag %(tagName)s from room": "No s'ha pogut esborrar l'etiqueta %(tagName)s de la sala", "Failed to remove tag %(tagName)s from room": "No s'ha pogut esborrar l'etiqueta %(tagName)s de la sala",
"Filter room names": "Filtra els noms de les sales", "Filter room names": "Filtra els noms de les sales",
"Couldn't load home page": "No s'ha pogut carregar la pàgina d'inici", "Couldn't load home page": "No s'ha pogut carregar la pàgina d'inici",
"All messages (loud)": "Tots els missatges (sorollós)", "All messages (noisy)": "Tots els missatges (sorollós)",
"Mentions only": "Només mencions", "Mentions only": "Només mencions",
"Mute": "Silenciat", "Mute": "Silenciat",
"Direct Chat": "Xat directe", "Direct Chat": "Xat directe",

View File

@ -42,7 +42,7 @@
"Messages sent by bot": "Zprávy poslané robotem", "Messages sent by bot": "Zprávy poslané robotem",
"more": "více", "more": "více",
"Mute": "Ztlumit", "Mute": "Ztlumit",
"All messages (loud)": "Všechny zprávy (hlasitě)", "All messages (noisy)": "Všechny zprávy (hlasitě)",
"Couldn't load home page": "Nepodařilo se nahrát úvodní stránku", "Couldn't load home page": "Nepodařilo se nahrát úvodní stránku",
"All notifications are currently disabled for all targets.": "Veškeré notifikace jsou aktuálně pro všechny cíle vypnuty.", "All notifications are currently disabled for all targets.": "Veškeré notifikace jsou aktuálně pro všechny cíle vypnuty.",
"Cancel Sending": "Zrušit odesílání", "Cancel Sending": "Zrušit odesílání",

View File

@ -62,7 +62,7 @@
"On": "An", "On": "An",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Du hast sie eventuell auf einem anderen Matrix-Client und nicht in Riot konfiguriert. Sie können in Riot nicht verändert werden, gelten aber trotzdem", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Du hast sie eventuell auf einem anderen Matrix-Client und nicht in Riot konfiguriert. Sie können in Riot nicht verändert werden, gelten aber trotzdem",
"All messages": "Alle Nachrichten", "All messages": "Alle Nachrichten",
"All messages (loud)": "Alle Nachrichten (laut)", "All messages (noisy)": "Alle Nachrichten (laut)",
"Cancel Sending": "Senden abbrechen", "Cancel Sending": "Senden abbrechen",
"Close": "Schließen", "Close": "Schließen",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Soll der Raum-Alias %(alias)s gelöscht und der %(name)s aus dem Verzeichnis entfernt werden?", "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Soll der Raum-Alias %(alias)s gelöscht und der %(name)s aus dem Verzeichnis entfernt werden?",

View File

@ -29,7 +29,7 @@
"Collecting app version information": "Συγκέντρωση πληροφοριών σχετικά με την έκδοση της εφαρμογής", "Collecting app version information": "Συγκέντρωση πληροφοριών σχετικά με την έκδοση της εφαρμογής",
"customServer_text": "Μπορείτε να χρησιμοποιήσετε τις προσαρμοσμένες ρυθμίσεις για να εισέλθετε σε άλλους διακομιστές Matrix επιλέγοντας μια διαφορετική διεύθυνση για το διακομιστή.<br/> Αυτό σας επιτρέπει να χρησιμοποιήσετε την εφαρμογή Riot με έναν υπάρχοντα λογαριασμό σε διαφορετικό διακομιστή.<br/><br/>Επίσης μπορείτε να επιλέξετε ένα διαφορετικό διακομιστή ταυτότητας αλλά δεν θα έχετε τη δυνατότητα να προσκαλέσετε άλλους χρήστες ή να σας προσκαλέσουν μέσω μηνυμάτων ηλεκτρονικής αλληλογραφίας.", "customServer_text": "Μπορείτε να χρησιμοποιήσετε τις προσαρμοσμένες ρυθμίσεις για να εισέλθετε σε άλλους διακομιστές Matrix επιλέγοντας μια διαφορετική διεύθυνση για το διακομιστή.<br/> Αυτό σας επιτρέπει να χρησιμοποιήσετε την εφαρμογή Riot με έναν υπάρχοντα λογαριασμό σε διαφορετικό διακομιστή.<br/><br/>Επίσης μπορείτε να επιλέξετε ένα διαφορετικό διακομιστή ταυτότητας αλλά δεν θα έχετε τη δυνατότητα να προσκαλέσετε άλλους χρήστες ή να σας προσκαλέσουν μέσω μηνυμάτων ηλεκτρονικής αλληλογραφίας.",
"%(appName)s via %(browserName)s on %(osName)s": "%(appName)s μέσω %(browserName)s σε %(osName)s", "%(appName)s via %(browserName)s on %(osName)s": "%(appName)s μέσω %(browserName)s σε %(osName)s",
"All messages (loud)": "Όλα τα μηνύματα (δυνατά)", "All messages (noisy)": "Όλα τα μηνύματα (δυνατά)",
"delete the alias.": "διέγραψε το ψευδώνυμο.", "delete the alias.": "διέγραψε το ψευδώνυμο.",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Διαγραφή του ψευδώνυμου %(alias)s και αφαίρεση του %(name)s από το ευρετήριο;", "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Διαγραφή του ψευδώνυμου %(alias)s και αφαίρεση του %(name)s από το ευρετήριο;",
"Dismiss": "Απόρριψη", "Dismiss": "Απόρριψη",

View File

@ -137,7 +137,7 @@
"Failed to set Direct Message status of room": "Failed to set Direct Message status of room", "Failed to set Direct Message status of room": "Failed to set Direct Message status of room",
"unknown error code": "unknown error code", "unknown error code": "unknown error code",
"Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s", "Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
"All messages (loud)": "All messages (loud)", "All messages (noisy)": "All messages (noisy)",
"All messages": "All messages", "All messages": "All messages",
"Mentions only": "Mentions only", "Mentions only": "Mentions only",
"Mute": "Mute", "Mute": "Mute",
@ -158,6 +158,8 @@
"Register": "Register", "Register": "Register",
"Invite to this room": "Invite to this room", "Invite to this room": "Invite to this room",
"Members": "Members", "Members": "Members",
"%(count)s Members|other": "%(count)s Members",
"%(count)s Members|one": "%(count)s Member",
"Files": "Files", "Files": "Files",
"Notifications": "Notifications", "Notifications": "Notifications",
"Rooms": "Rooms", "Rooms": "Rooms",
@ -217,5 +219,6 @@
"Contributing code to Matrix and Riot": "Contributing code to Matrix and Riot", "Contributing code to Matrix and Riot": "Contributing code to Matrix and Riot",
"Dev chat for the Riot/Web dev team": "Dev chat for the Riot/Web dev team", "Dev chat for the Riot/Web dev team": "Dev chat for the Riot/Web dev team",
"Dev chat for the Dendrite dev team": "Dev chat for the Dendrite dev team", "Dev chat for the Dendrite dev team": "Dev chat for the Dendrite dev team",
"Co-ordination for Riot/Web translators": "Co-ordination for Riot/Web translators" "Co-ordination for Riot/Web translators": "Co-ordination for Riot/Web translators",
"Reply": "Reply"
} }

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Add an email address above to configure email notifications", "Add an email address above to configure email notifications": "Add an email address above to configure email notifications",
"Advanced notification settings": "Advanced notification settings", "Advanced notification settings": "Advanced notification settings",
"All messages": "All messages", "All messages": "All messages",
"All messages (loud)": "All messages (loud)", "All messages (noisy)": "All messages (noisy)",
"All Rooms": "All Rooms", "All Rooms": "All Rooms",
"All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.", "All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.",
"An error occurred whilst saving your email notification preferences.": "An error occurred while saving your email notification preferences.", "An error occurred whilst saving your email notification preferences.": "An error occurred while saving your email notification preferences.",

View File

@ -1,7 +1,7 @@
{ {
"A new version of Riot is available.": "Nova versio de \"Riot\" haveblas.", "A new version of Riot is available.": "Nova versio de \"Riot\" haveblas.",
"All messages": "Ĉiuj mesaĝoj", "All messages": "Ĉiuj mesaĝoj",
"All messages (loud)": "Ĉiuj mesaĝoj (lauta)", "All messages (noisy)": "Ĉiuj mesaĝoj (lauta)",
"All Rooms": "Ĉiuj babilejoj", "All Rooms": "Ĉiuj babilejoj",
"Cancel": "Nuligi", "Cancel": "Nuligi",
"delete the alias.": "Forviŝi la kromnomon.", "delete the alias.": "Forviŝi la kromnomon.",

View File

@ -135,7 +135,7 @@
"You have successfully set a password and an email address!": "¡Ha establecido exitosamente la contraseña y la dirección de email!", "You have successfully set a password and an email address!": "¡Ha establecido exitosamente la contraseña y la dirección de email!",
"You have successfully set a password!": "¡Ha establecido exitosamente una contraseña!", "You have successfully set a password!": "¡Ha establecido exitosamente una contraseña!",
"%(appName)s via %(browserName)s on %(osName)s": "%(appName)s via %(browserName)s en %(osName)s", "%(appName)s via %(browserName)s on %(osName)s": "%(appName)s via %(browserName)s en %(osName)s",
"All messages (loud)": "Todos los mensajes (ruidoso)", "All messages (noisy)": "Todos los mensajes (ruidoso)",
"All notifications are currently disabled for all targets.": "Las notificaciones estan desactivadas para todos los objetivos.", "All notifications are currently disabled for all targets.": "Las notificaciones estan desactivadas para todos los objetivos.",
"Collecting app version information": "Recolectando información de la versión de la aplicación", "Collecting app version information": "Recolectando información de la versión de la aplicación",
"Collecting logs": "Recolectando registros", "Collecting logs": "Recolectando registros",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Gehitu e-mail helbide bat goian e-mail bidezko jakinarazpenak konfiguratzeko", "Add an email address above to configure email notifications": "Gehitu e-mail helbide bat goian e-mail bidezko jakinarazpenak konfiguratzeko",
"Advanced notification settings": "Jakinarazpen aurreratuen ezarpenak", "Advanced notification settings": "Jakinarazpen aurreratuen ezarpenak",
"All messages": "Mezu guztiak", "All messages": "Mezu guztiak",
"All messages (loud)": "Mezu guztiak (ozen)", "All messages (noisy)": "Mezu guztiak (ozen)",
"All Rooms": "Gela guztiak", "All Rooms": "Gela guztiak",
"All notifications are currently disabled for all targets.": "Une honetan jakinarazpen guztiak helburu guztietarako desgaituta daude.", "All notifications are currently disabled for all targets.": "Une honetan jakinarazpen guztiak helburu guztietarako desgaituta daude.",
"An error occurred whilst saving your email notification preferences.": "Errore bat gertatu da zure e-mail bidezko jakinarazpenen hobespenak gordetzean.", "An error occurred whilst saving your email notification preferences.": "Errore bat gertatu da zure e-mail bidezko jakinarazpenen hobespenak gordetzean.",

View File

@ -1,7 +1,7 @@
{ {
"A new version of Riot is available.": "نسخه‌ی جدید از رایوت موجود است.", "A new version of Riot is available.": "نسخه‌ی جدید از رایوت موجود است.",
"All messages": "همه‌ی پیام‌ها", "All messages": "همه‌ی پیام‌ها",
"All messages (loud)": "همه‌ی پیام‌ها(بلند)", "All messages (noisy)": "همه‌ی پیام‌ها(بلند)",
"All Rooms": "همه‌ی گپ‌ها", "All Rooms": "همه‌ی گپ‌ها",
"Cancel Sending": "فرستادن را لغو کن", "Cancel Sending": "فرستادن را لغو کن",
"Changelog": "تغییراتِ به‌وجودآمده", "Changelog": "تغییراتِ به‌وجودآمده",

View File

@ -4,7 +4,7 @@
"Add an email address above to configure email notifications": "Lisää sähköpostiosoite yllä saadaksesi ilmoituksia sähköpostiisi", "Add an email address above to configure email notifications": "Lisää sähköpostiosoite yllä saadaksesi ilmoituksia sähköpostiisi",
"Advanced notification settings": "Lisäasetukset ilmoituksille", "Advanced notification settings": "Lisäasetukset ilmoituksille",
"All messages": "Kaikki viestit", "All messages": "Kaikki viestit",
"All messages (loud)": "Kaikki viestit (äänekkäästi)", "All messages (noisy)": "Kaikki viestit (äänekkäästi)",
"All Rooms": "Kaikki huoneet", "All Rooms": "Kaikki huoneet",
"All notifications are currently disabled for all targets.": "Kaikki ilmoitukset on kytketty pois kaikilta kohteilta.", "All notifications are currently disabled for all targets.": "Kaikki ilmoitukset on kytketty pois kaikilta kohteilta.",
"An error occurred whilst saving your email notification preferences.": "Sähköposti-ilmoitusasetuksia tallettaessa tapahtui virhe.", "An error occurred whilst saving your email notification preferences.": "Sähköposti-ilmoitusasetuksia tallettaessa tapahtui virhe.",

View File

@ -1,7 +1,7 @@
{ {
"Add an email address above to configure email notifications": "Ajouter une adresse e-mail pour la configuration des notifications par e-mail", "Add an email address above to configure email notifications": "Ajouter une adresse e-mail pour la configuration des notifications par e-mail",
"All messages": "Tous les messages", "All messages": "Tous les messages",
"All messages (loud)": "Tous les messages (fort)", "All messages (noisy)": "Tous les messages (fort)",
"All notifications are currently disabled for all targets.": "Toutes les notifications sont désactivées pour tous les appareils.", "All notifications are currently disabled for all targets.": "Toutes les notifications sont désactivées pour tous les appareils.",
"An error occurred whilst saving your email notification preferences.": "Une erreur est survenue lors de la sauvegarde de vos préférences de notification par e-mail.", "An error occurred whilst saving your email notification preferences.": "Une erreur est survenue lors de la sauvegarde de vos préférences de notification par e-mail.",
"Cancel Sending": "Annuler l'envoi", "Cancel Sending": "Annuler l'envoi",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Engada un enderezo de correo electrónico para configurar as notificacións", "Add an email address above to configure email notifications": "Engada un enderezo de correo electrónico para configurar as notificacións",
"Advanced notification settings": "Axustes avanzados de notificación", "Advanced notification settings": "Axustes avanzados de notificación",
"All messages": "Todas as mensaxes", "All messages": "Todas as mensaxes",
"All messages (loud)": "Todas as mensaxes (alto)", "All messages (noisy)": "Todas as mensaxes (alto)",
"All Rooms": "Todas as Salas", "All Rooms": "Todas as Salas",
"All notifications are currently disabled for all targets.": "Todas as notificacións están deshabilitadas para todos os destinos.", "All notifications are currently disabled for all targets.": "Todas as notificacións están deshabilitadas para todos os destinos.",
"An error occurred whilst saving your email notification preferences.": "Algo fallou mentras se gardaban as súas preferencias de notificaicón.", "An error occurred whilst saving your email notification preferences.": "Algo fallou mentras se gardaban as súas preferencias de notificaicón.",

View File

@ -3,7 +3,7 @@
"Add an email address above to configure email notifications": "הוסף כתובת דואר אלקטורני למעלה בכדי להגדיר התראות", "Add an email address above to configure email notifications": "הוסף כתובת דואר אלקטורני למעלה בכדי להגדיר התראות",
"Advanced notification settings": "הגדרות מתקדמות להתראות", "Advanced notification settings": "הגדרות מתקדמות להתראות",
"All messages": "כל ההודעות", "All messages": "כל ההודעות",
"All messages (loud)": "כל ההודעות (צעקה)", "All messages (noisy)": "כל ההודעות (צעקה)",
"All Rooms": "כל החדרים", "All Rooms": "כל החדרים",
"All notifications are currently disabled for all targets.": "התראות מנוטרלות לכלל המערכת.", "All notifications are currently disabled for all targets.": "התראות מנוטרלות לכלל המערכת.",
"An error occurred whilst saving your email notification preferences.": "קרתה שגיאה בזמן שמירת הגדרות התראה באמצעות הדואר האלקטרוני.", "An error occurred whilst saving your email notification preferences.": "קרתה שגיאה בזמן שמירת הגדרות התראה באמצעות הדואר האלקטרוני.",

View File

@ -2,7 +2,7 @@
"Add an email address above to configure email notifications": "E-mail értesítés beállításához írd be az e-mail címed", "Add an email address above to configure email notifications": "E-mail értesítés beállításához írd be az e-mail címed",
"Advanced notification settings": "Haladó értesítési beállítások", "Advanced notification settings": "Haladó értesítési beállítások",
"All messages": "Minden üzenet", "All messages": "Minden üzenet",
"All messages (loud)": "Minden üzenet (hangos)", "All messages (noisy)": "Minden üzenet (hangos)",
"All notifications are currently disabled for all targets.": "Minden céleszközön minden értesítés tiltva van.", "All notifications are currently disabled for all targets.": "Minden céleszközön minden értesítés tiltva van.",
"An error occurred whilst saving your email notification preferences.": "Hiba történt az e-mail értesítés beállításánál.", "An error occurred whilst saving your email notification preferences.": "Hiba történt az e-mail értesítés beállításánál.",
"Call invitation": "Hívás meghívó", "Call invitation": "Hívás meghívó",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Tambahkan alamat email di atas untuk konfigurasi notifikasi email", "Add an email address above to configure email notifications": "Tambahkan alamat email di atas untuk konfigurasi notifikasi email",
"Advanced notification settings": "Pengaturan notifikasi lanjutan", "Advanced notification settings": "Pengaturan notifikasi lanjutan",
"All messages": "Semua pesan", "All messages": "Semua pesan",
"All messages (loud)": "Semua pesan (keras)", "All messages (noisy)": "Semua pesan (keras)",
"All Rooms": "Semua Ruang", "All Rooms": "Semua Ruang",
"All notifications are currently disabled for all targets.": "Semua notifikasi saat ini dinonaktifkan untuk semua target.", "All notifications are currently disabled for all targets.": "Semua notifikasi saat ini dinonaktifkan untuk semua target.",
"An error occurred whilst saving your email notification preferences.": "Terjadi kesalahan saat menyimpan preferensi notifikasi email Anda.", "An error occurred whilst saving your email notification preferences.": "Terjadi kesalahan saat menyimpan preferensi notifikasi email Anda.",

View File

@ -4,7 +4,7 @@
"Add an email address above to configure email notifications": "Aggiungi un indirizzo email sopra per configurare le notifiche via email", "Add an email address above to configure email notifications": "Aggiungi un indirizzo email sopra per configurare le notifiche via email",
"Advanced notification settings": "Impostazioni di notifica avanzate", "Advanced notification settings": "Impostazioni di notifica avanzate",
"All messages": "Tutti i messaggi", "All messages": "Tutti i messaggi",
"All messages (loud)": "Tutti i messaggi (rumoroso)", "All messages (noisy)": "Tutti i messaggi (rumoroso)",
"All Rooms": "Tutte le stanze", "All Rooms": "Tutte le stanze",
"An error occurred whilst saving your email notification preferences.": "Si è verificato un errore durante il salvataggio delle tue preferenze sulle notifiche email.", "An error occurred whilst saving your email notification preferences.": "Si è verificato un errore durante il salvataggio delle tue preferenze sulle notifiche email.",
"Call invitation": "Invito ad una chiamata", "Call invitation": "Invito ad una chiamata",

View File

@ -1,6 +1,6 @@
{ {
"All messages": "全ての発言", "All messages": "全ての発言",
"All messages (loud)": "全ての発言(通知音あり)", "All messages (noisy)": "全ての発言(通知音あり)",
"Cancel": "取消", "Cancel": "取消",
"Close": "閉じる", "Close": "閉じる",
"Direct Chat": "対話", "Direct Chat": "対話",

View File

@ -3,7 +3,7 @@
"Add an email address above to configure email notifications": "이메일 알림을 설정하기 위해 이메일 주소를 추가해주세요", "Add an email address above to configure email notifications": "이메일 알림을 설정하기 위해 이메일 주소를 추가해주세요",
"Advanced notification settings": "고급 알림 설정", "Advanced notification settings": "고급 알림 설정",
"All messages": "모든 메시지", "All messages": "모든 메시지",
"All messages (loud)": "모든 메시지 (크게)", "All messages (noisy)": "모든 메시지 (크게)",
"All Rooms": "모든 방", "All Rooms": "모든 방",
"All notifications are currently disabled for all targets.": "현재 모든 알림이 모든 상대에게서 꺼졌어요.", "All notifications are currently disabled for all targets.": "현재 모든 알림이 모든 상대에게서 꺼졌어요.",
"An error occurred whilst saving your email notification preferences.": "이메일 알림을 설정하다가 오류가 일어났어요.", "An error occurred whilst saving your email notification preferences.": "이메일 알림을 설정하다가 오류가 일어났어요.",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Pievieno augšā epasta adresi, lai konfigurētu epasta notifikāciju paziņojumus", "Add an email address above to configure email notifications": "Pievieno augšā epasta adresi, lai konfigurētu epasta notifikāciju paziņojumus",
"Advanced notification settings": "Īpašie notifikāciju uzstādījumi", "Advanced notification settings": "Īpašie notifikāciju uzstādījumi",
"All messages": "Visas ziņas", "All messages": "Visas ziņas",
"All messages (loud)": "Visas ziņas (skaļi)", "All messages (noisy)": "Visas ziņas (skaļi)",
"All Rooms": "Visas istabas", "All Rooms": "Visas istabas",
"All notifications are currently disabled for all targets.": "Visi notifikāciju paziņojumi ir atspējoti visiem saņēmējiem.", "All notifications are currently disabled for all targets.": "Visi notifikāciju paziņojumi ir atspējoti visiem saņēmējiem.",
"An error occurred whilst saving your email notification preferences.": "Radās kļūda saglabājot tavus epasta notifikāciju ziņu uzstādījumus.", "An error occurred whilst saving your email notification preferences.": "Radās kļūda saglabājot tavus epasta notifikāciju ziņu uzstādījumus.",

View File

@ -1,7 +1,7 @@
{ {
"Add an email address above to configure email notifications": "ഇ മെയില്‍ അറിയിപ്പുകൾ ലഭിക്കാന്‍ മുകളില്‍ ഇ-മെയില്‍ വിലാസം നല്‍കൂ", "Add an email address above to configure email notifications": "ഇ മെയില്‍ അറിയിപ്പുകൾ ലഭിക്കാന്‍ മുകളില്‍ ഇ-മെയില്‍ വിലാസം നല്‍കൂ",
"All messages": "എല്ലാ സന്ദേശങ്ങളും", "All messages": "എല്ലാ സന്ദേശങ്ങളും",
"All messages (loud)": "എല്ലാ സന്ദേശങ്ങളും (ഉച്ചത്തിൽ)", "All messages (noisy)": "എല്ലാ സന്ദേശങ്ങളും (ഉച്ചത്തിൽ)",
"%(appName)s via %(browserName)s on %(osName)s": "%(osName)sല് %(browserName)s വഴി %(appName)s", "%(appName)s via %(browserName)s on %(osName)s": "%(osName)sല് %(browserName)s വഴി %(appName)s",
"<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">സഫാരിയിലും</a>പിന്നെ <a href=\"http://opera.com\">ഓപ്പേറയിലും</a>പ്രവര്‍ത്തിക്കുന്നു.", "<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">സഫാരിയിലും</a>പിന്നെ <a href=\"http://opera.com\">ഓപ്പേറയിലും</a>പ്രവര്‍ത്തിക്കുന്നു.",
"A new version of Riot is available.": "റയട്ടിന്റെ ഒരു പുതിയ പതിപ്പ് ലഭ്യമാണ്.", "A new version of Riot is available.": "റയട്ടിന്റെ ഒരു പുതിയ പതിപ്പ് ലഭ്യമാണ്.",

View File

@ -2,7 +2,7 @@
"Add an email address above to configure email notifications": "Legg til en epost adresse for å sette opp epost varsling", "Add an email address above to configure email notifications": "Legg til en epost adresse for å sette opp epost varsling",
"Advanced notification settings": "Avanserte varslingsinnstillinger", "Advanced notification settings": "Avanserte varslingsinnstillinger",
"All messages": "Alle meldinger", "All messages": "Alle meldinger",
"All messages (loud)": "Alle meldinger (høy)", "All messages (noisy)": "Alle meldinger (høy)",
"All notifications are currently disabled for all targets.": "Alle varsler er deaktivert for alle mottakere.", "All notifications are currently disabled for all targets.": "Alle varsler er deaktivert for alle mottakere.",
"An error occurred whilst saving your email notification preferences.": "En feil oppsto i forbindelse med lagring av epost varsel innstillinger.", "An error occurred whilst saving your email notification preferences.": "En feil oppsto i forbindelse med lagring av epost varsel innstillinger.",
"Cancel Sending": "Avbryt sending", "Cancel Sending": "Avbryt sending",

View File

@ -2,7 +2,7 @@
"Add an email address above to configure email notifications": "Voeg een e-mailadres toe om e-mailmeldingen te ontvangen", "Add an email address above to configure email notifications": "Voeg een e-mailadres toe om e-mailmeldingen te ontvangen",
"Advanced notification settings": "Geavanceerde meldingsinstellingen", "Advanced notification settings": "Geavanceerde meldingsinstellingen",
"All messages": "Alle berichten", "All messages": "Alle berichten",
"All messages (loud)": "Alle berichten (luid)", "All messages (noisy)": "Alle berichten (luid)",
"All notifications are currently disabled for all targets.": "Alle meldingen zijn momenteel uitgeschakeld voor alle doelen.", "All notifications are currently disabled for all targets.": "Alle meldingen zijn momenteel uitgeschakeld voor alle doelen.",
"An error occurred whilst saving your email notification preferences.": "Er is een fout opgetreden tijdens het opslaan van uw e-mailmeldingsvoorkeuren.", "An error occurred whilst saving your email notification preferences.": "Er is een fout opgetreden tijdens het opslaan van uw e-mailmeldingsvoorkeuren.",
"Call invitation": "Oproep-uitnodiging", "Call invitation": "Oproep-uitnodiging",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "Dodaj adres e-mail powyżej, aby skonfigurować powiadomienia e-mailowe", "Add an email address above to configure email notifications": "Dodaj adres e-mail powyżej, aby skonfigurować powiadomienia e-mailowe",
"Advanced notification settings": "Zaawansowane ustawienia powiadomień", "Advanced notification settings": "Zaawansowane ustawienia powiadomień",
"All messages": "Wszystkie wiadomości", "All messages": "Wszystkie wiadomości",
"All messages (loud)": "Wszystkie wiadomości (głośno)", "All messages (noisy)": "Wszystkie wiadomości (głośno)",
"All Rooms": "Wszystkie pokoje", "All Rooms": "Wszystkie pokoje",
"All notifications are currently disabled for all targets.": "Wszystkie powiadomienia są obecnie wyłączone dla wszystkich celów.", "All notifications are currently disabled for all targets.": "Wszystkie powiadomienia są obecnie wyłączone dla wszystkich celów.",
"An error occurred whilst saving your email notification preferences.": "Podczas zapisywania ustawień powiadomień e-mail wystąpił błąd.", "An error occurred whilst saving your email notification preferences.": "Podczas zapisywania ustawień powiadomień e-mail wystąpił błąd.",

View File

@ -1,7 +1,7 @@
{ {
"Add an email address above to configure email notifications": "Insira um endereço de email no campo acima para configurar as notificações por email", "Add an email address above to configure email notifications": "Insira um endereço de email no campo acima para configurar as notificações por email",
"All messages": "Todas as mensagens", "All messages": "Todas as mensagens",
"All messages (loud)": "Todas as mensagens (alto)", "All messages (noisy)": "Todas as mensagens (alto)",
"An error occurred whilst saving your email notification preferences.": "Ocorreu um erro ao guardar as suas preferências de notificação por email.", "An error occurred whilst saving your email notification preferences.": "Ocorreu um erro ao guardar as suas preferências de notificação por email.",
"Call invitation": "Convite para chamada", "Call invitation": "Convite para chamada",
"Cancel Sending": "Cancelar o envio", "Cancel Sending": "Cancelar o envio",

View File

@ -1,7 +1,7 @@
{ {
"Add an email address above to configure email notifications": "Insira um endereço de email no campo acima para configurar suas notificações por email", "Add an email address above to configure email notifications": "Insira um endereço de email no campo acima para configurar suas notificações por email",
"All messages": "Todas as mensagens", "All messages": "Todas as mensagens",
"All messages (loud)": "Todas as mensagens (alto)", "All messages (noisy)": "Todas as mensagens (alto)",
"An error occurred whilst saving your email notification preferences.": "Um erro ocorreu enquanto o sistema estava salvando suas preferências de notificação por email.", "An error occurred whilst saving your email notification preferences.": "Um erro ocorreu enquanto o sistema estava salvando suas preferências de notificação por email.",
"Call invitation": "Convite para chamada", "Call invitation": "Convite para chamada",
"Cancel Sending": "Cancelar o envio", "Cancel Sending": "Cancelar o envio",

View File

@ -63,7 +63,7 @@
"You are not receiving desktop notifications": "Вы не получаете уведомления на рабочем столе", "You are not receiving desktop notifications": "Вы не получаете уведомления на рабочем столе",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Возможно вы настроили их не в Riot, а в другом Matrix-клиенте. Настроить их в Riot не удастся, но они будут в нем применяться", "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Возможно вы настроили их не в Riot, а в другом Matrix-клиенте. Настроить их в Riot не удастся, но они будут в нем применяться",
"All messages": "Все сообщения", "All messages": "Все сообщения",
"All messages (loud)": "Все сообщения (со звуком)", "All messages (noisy)": "Все сообщения (со звуком)",
"Cancel Sending": "Отменить отправку", "Cancel Sending": "Отменить отправку",
"Close": "Закрыть", "Close": "Закрыть",
"Download this file": "Скачать этот файл", "Download this file": "Скачать этот файл",

View File

@ -135,7 +135,7 @@
"Failed to set Direct Message status of room": "Nepodarilo sa nastaviť stav miestnosti priama konverzácia", "Failed to set Direct Message status of room": "Nepodarilo sa nastaviť stav miestnosti priama konverzácia",
"unknown error code": "neznámy kód chyby", "unknown error code": "neznámy kód chyby",
"Failed to forget room %(errCode)s": "Nepodarilo sa zabudnuť miestnosť %(errCode)s", "Failed to forget room %(errCode)s": "Nepodarilo sa zabudnuť miestnosť %(errCode)s",
"All messages (loud)": "Všetky správy (hlučné)", "All messages (noisy)": "Všetky správy (hlučné)",
"All messages": "Všetky správy", "All messages": "Všetky správy",
"Mentions only": "Len zmienky", "Mentions only": "Len zmienky",
"Mute": "Umlčať", "Mute": "Umlčať",

View File

@ -2,7 +2,7 @@
"Add an email address above to configure email notifications": "Lägg till en epostadress här för att konfigurera epostaviseringar", "Add an email address above to configure email notifications": "Lägg till en epostadress här för att konfigurera epostaviseringar",
"Advanced notification settings": "Avancerade aviseringsinställingar", "Advanced notification settings": "Avancerade aviseringsinställingar",
"All messages": "Alla meddelanden", "All messages": "Alla meddelanden",
"All messages (loud)": "Alla meddelanden (högljudd)", "All messages (noisy)": "Alla meddelanden (högljudd)",
"All notifications are currently disabled for all targets.": "Alla aviseringar är för tillfället avstängda för alla mål.", "All notifications are currently disabled for all targets.": "Alla aviseringar är för tillfället avstängda för alla mål.",
"An error occurred whilst saving your email notification preferences.": "Ett fel uppstod då epostaviseringsinställningarna sparades.", "An error occurred whilst saving your email notification preferences.": "Ett fel uppstod då epostaviseringsinställningarna sparades.",
"Call invitation": "Inbjudan till samtal", "Call invitation": "Inbjudan till samtal",

View File

@ -4,7 +4,7 @@
"Add an email address above to configure email notifications": "மின்னஞ்சல் மூலம் அறிவிப்புகளை பெற உங்கள் மின்னஞ்சல் முகவரியை மேலே இணைக்கவும்", "Add an email address above to configure email notifications": "மின்னஞ்சல் மூலம் அறிவிப்புகளை பெற உங்கள் மின்னஞ்சல் முகவரியை மேலே இணைக்கவும்",
"Advanced notification settings": "மேம்பட்ட அறிவிப்பிற்கான அமைப்புகள்", "Advanced notification settings": "மேம்பட்ட அறிவிப்பிற்கான அமைப்புகள்",
"All messages": "அனைத்து செய்திகள்", "All messages": "அனைத்து செய்திகள்",
"All messages (loud)": "அனைத்து செய்திகள் (உரக்க)", "All messages (noisy)": "அனைத்து செய்திகள் (உரக்க)",
"All Rooms": "அனைத்து அறைகள்", "All Rooms": "அனைத்து அறைகள்",
"All notifications are currently disabled for all targets.": "அனைத்து இலக்குகளுக்கான அனைத்து அறிவுப்புகளும் தற்போது முடக்கி வைக்கப்பட்டுள்ளது.", "All notifications are currently disabled for all targets.": "அனைத்து இலக்குகளுக்கான அனைத்து அறிவுப்புகளும் தற்போது முடக்கி வைக்கப்பட்டுள்ளது.",
"An error occurred whilst saving your email notification preferences.": "உங்கள் மின்னஞ்சல் அறிவிப்பு விருப்பங்களை சேமிப்பதில் ஏதோ பிழை ஏற்பட்டுள்ளது.", "An error occurred whilst saving your email notification preferences.": "உங்கள் மின்னஞ்சல் அறிவிப்பு விருப்பங்களை சேமிப்பதில் ஏதோ பிழை ஏற்பட்டுள்ளது.",

View File

@ -16,7 +16,7 @@
"Add an email address above to configure email notifications": "ఇమెయిల్ ప్రకటనలను రూపశిల్పం చేయడానికి ఎగువ ఇమెయిల్ చిరునామాను జోడించండి", "Add an email address above to configure email notifications": "ఇమెయిల్ ప్రకటనలను రూపశిల్పం చేయడానికి ఎగువ ఇమెయిల్ చిరునామాను జోడించండి",
"Advanced notification settings": "ఆధునిక తాఖీదు అమరిక", "Advanced notification settings": "ఆధునిక తాఖీదు అమరిక",
"All messages": "అన్ని సందేశాలు", "All messages": "అన్ని సందేశాలు",
"All messages (loud)": "అన్ని సందేశాలు (గట్టిగ)", "All messages (noisy)": "అన్ని సందేశాలు (గట్టిగ)",
"All Rooms": "అన్ని గదులు", "All Rooms": "అన్ని గదులు",
"Call invitation": "మాట్లాడడానికి ఆహ్వానం", "Call invitation": "మాట్లాడడానికి ఆహ్వానం",
"Cancel Sending": "పంపడాన్ని ఆపేయండి", "Cancel Sending": "పంపడాన్ని ఆపేయండి",

View File

@ -81,7 +81,7 @@
"Riot is not supported on mobile web. Install the app?": "Riot ไม่รองรับเว็บบนอุปกรณ์พกพา ติดตั้งแอป?", "Riot is not supported on mobile web. Install the app?": "Riot ไม่รองรับเว็บบนอุปกรณ์พกพา ติดตั้งแอป?",
"Riot does not know how to join a room on this network": "Riot ไม่รู้วิธีเข้าร่วมห้องในเครือข่ายนี้", "Riot does not know how to join a room on this network": "Riot ไม่รู้วิธีเข้าร่วมห้องในเครือข่ายนี้",
"Direct Chat": "แชทโดยตรง", "Direct Chat": "แชทโดยตรง",
"All messages (loud)": "ทุกข้อความ (เสียงดัง)", "All messages (noisy)": "ทุกข้อความ (เสียงดัง)",
"Custom Server Options": "กำหนดเซิร์ฟเวอร์เอง", "Custom Server Options": "กำหนดเซิร์ฟเวอร์เอง",
"Directory": "ไดเรกทอรี", "Directory": "ไดเรกทอรี",
"Enable audible notifications in web client": "เปิดใช้งานเสียงแจ้งเตือนบนเว็บไคลเอนต์", "Enable audible notifications in web client": "เปิดใช้งานเสียงแจ้งเตือนบนเว็บไคลเอนต์",

View File

@ -5,7 +5,7 @@
"Add an email address above to configure email notifications": "E-posta bildirimlerini yapılandırmak için yukarıya bir e-posta adresi ekleyin", "Add an email address above to configure email notifications": "E-posta bildirimlerini yapılandırmak için yukarıya bir e-posta adresi ekleyin",
"Advanced notification settings": "Gelişmiş bildirim ayarları", "Advanced notification settings": "Gelişmiş bildirim ayarları",
"All messages": "Tüm mesajlar", "All messages": "Tüm mesajlar",
"All messages (loud)": "Tüm mesajlar (uzun)", "All messages (noisy)": "Tüm mesajlar (uzun)",
"All Rooms": "Tüm Odalar", "All Rooms": "Tüm Odalar",
"All notifications are currently disabled for all targets.": "Tüm bildirimler şu anda tüm hedefler için devre dışı bırakılmıştır.", "All notifications are currently disabled for all targets.": "Tüm bildirimler şu anda tüm hedefler için devre dışı bırakılmıştır.",
"An error occurred whilst saving your email notification preferences.": "E-posta bildirim tercihlerinizi kaydetme işlemi sırasında bir hata oluştu.", "An error occurred whilst saving your email notification preferences.": "E-posta bildirim tercihlerinizi kaydetme işlemi sırasında bir hata oluştu.",

View File

@ -1,7 +1,7 @@
{ {
"A new version of Riot is available.": "Доступне оновлення для Riot.", "A new version of Riot is available.": "Доступне оновлення для Riot.",
"All messages": "Усі повідомлення", "All messages": "Усі повідомлення",
"All messages (loud)": "Усі повідомлення (гучно)", "All messages (noisy)": "Усі повідомлення (гучно)",
"All Rooms": "Усі кімнати", "All Rooms": "Усі кімнати",
"All notifications are currently disabled for all targets.": "Сповіщення для усіх цілей на даний момент вимкнені.", "All notifications are currently disabled for all targets.": "Сповіщення для усіх цілей на даний момент вимкнені.",
"An error occurred whilst saving your email notification preferences.": "Під час збереження налаштувань сповіщень е-поштою трапилася помилка.", "An error occurred whilst saving your email notification preferences.": "Під час збереження налаштувань сповіщень е-поштою трапилася помилка.",

View File

@ -10,7 +10,7 @@
"Add an email address above to configure email notifications": "请在上方输入电子邮件地址以接收邮件通知", "Add an email address above to configure email notifications": "请在上方输入电子邮件地址以接收邮件通知",
"Advanced notification settings": "通知高级设置", "Advanced notification settings": "通知高级设置",
"All messages": "全部消息", "All messages": "全部消息",
"All messages (loud)": "全部消息(高亮)", "All messages (noisy)": "全部消息(高亮)",
"All Rooms": "全部聊天室", "All Rooms": "全部聊天室",
"All notifications are currently disabled for all targets.": "当前所有目标的通知均已禁用。", "All notifications are currently disabled for all targets.": "当前所有目标的通知均已禁用。",
"An error occurred whilst saving your email notification preferences.": "保存邮件通知首选项设定时出现错误。", "An error occurred whilst saving your email notification preferences.": "保存邮件通知首选项设定时出现错误。",

View File

@ -8,7 +8,7 @@
"<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">Safari</a> 與 <a href=\"http://opera.com\">Opera</a> 也能使用。", "<a href=\"http://apple.com/safari\">Safari</a> and <a href=\"http://opera.com\">Opera</a> work too.": "<a href=\"http://apple.com/safari\">Safari</a> 與 <a href=\"http://opera.com\">Opera</a> 也能使用。",
"Advanced notification settings": "進階通知設定", "Advanced notification settings": "進階通知設定",
"All messages": "所有訊息", "All messages": "所有訊息",
"All messages (loud)": "所有訊息(吵鬧)", "All messages (noisy)": "所有訊息(吵鬧)",
"All Rooms": "所有的聊天室", "All Rooms": "所有的聊天室",
"Call invitation": "通話邀請", "Call invitation": "通話邀請",
"Cancel": "取消", "Cancel": "取消",

View File

@ -11,6 +11,7 @@
@import "./matrix-react-sdk/structures/_RoomStatusBar.scss"; @import "./matrix-react-sdk/structures/_RoomStatusBar.scss";
@import "./matrix-react-sdk/structures/_RoomView.scss"; @import "./matrix-react-sdk/structures/_RoomView.scss";
@import "./matrix-react-sdk/structures/_SearchBox.scss"; @import "./matrix-react-sdk/structures/_SearchBox.scss";
@import "./matrix-react-sdk/structures/_TagPanel.scss";
@import "./matrix-react-sdk/structures/_UploadBar.scss"; @import "./matrix-react-sdk/structures/_UploadBar.scss";
@import "./matrix-react-sdk/structures/_UserSettings.scss"; @import "./matrix-react-sdk/structures/_UserSettings.scss";
@import "./matrix-react-sdk/structures/login/_Login.scss"; @import "./matrix-react-sdk/structures/login/_Login.scss";
@ -38,6 +39,7 @@
@import "./matrix-react-sdk/views/elements/_RichText.scss"; @import "./matrix-react-sdk/views/elements/_RichText.scss";
@import "./matrix-react-sdk/views/elements/_RoleButton.scss"; @import "./matrix-react-sdk/views/elements/_RoleButton.scss";
@import "./matrix-react-sdk/views/elements/_ToolTipButton.scss"; @import "./matrix-react-sdk/views/elements/_ToolTipButton.scss";
@import "./matrix-react-sdk/views/elements/_Quote.scss";
@import "./matrix-react-sdk/views/groups/_GroupPublicityToggle.scss"; @import "./matrix-react-sdk/views/groups/_GroupPublicityToggle.scss";
@import "./matrix-react-sdk/views/groups/_GroupRoomList.scss"; @import "./matrix-react-sdk/views/groups/_GroupRoomList.scss";
@import "./matrix-react-sdk/views/groups/_GroupUserSettings.scss"; @import "./matrix-react-sdk/views/groups/_GroupUserSettings.scss";
@ -69,6 +71,7 @@
@import "./matrix-react-sdk/views/rooms/_RoomTile.scss"; @import "./matrix-react-sdk/views/rooms/_RoomTile.scss";
@import "./matrix-react-sdk/views/rooms/_SearchableEntityList.scss"; @import "./matrix-react-sdk/views/rooms/_SearchableEntityList.scss";
@import "./matrix-react-sdk/views/rooms/_TopUnreadMessagesBar.scss"; @import "./matrix-react-sdk/views/rooms/_TopUnreadMessagesBar.scss";
@import "./matrix-react-sdk/views/rooms/_QuotePreview.scss";
@import "./matrix-react-sdk/views/settings/_DevicesPanel.scss"; @import "./matrix-react-sdk/views/settings/_DevicesPanel.scss";
@import "./matrix-react-sdk/views/settings/_IntegrationsManager.scss"; @import "./matrix-react-sdk/views/settings/_IntegrationsManager.scss";
@import "./matrix-react-sdk/views/voip/_CallView.scss"; @import "./matrix-react-sdk/views/voip/_CallView.scss";
@ -93,6 +96,7 @@
@import "./vector-web/views/elements/_ImageView.scss"; @import "./vector-web/views/elements/_ImageView.scss";
@import "./vector-web/views/elements/_InlineSpinner.scss"; @import "./vector-web/views/elements/_InlineSpinner.scss";
@import "./vector-web/views/elements/_Spinner.scss"; @import "./vector-web/views/elements/_Spinner.scss";
@import "./vector-web/views/elements/_SyntaxHighlight.scss";
@import "./vector-web/views/globals/_MatrixToolbar.scss"; @import "./vector-web/views/globals/_MatrixToolbar.scss";
@import "./vector-web/views/messages/_DateSeparator.scss"; @import "./vector-web/views/messages/_DateSeparator.scss";
@import "./vector-web/views/messages/_MessageTimestamp.scss"; @import "./vector-web/views/messages/_MessageTimestamp.scss";

View File

@ -21,6 +21,8 @@ limitations under the License.
padding-top: 24px; padding-top: 24px;
padding-bottom: 22px; padding-bottom: 22px;
border-bottom: 1px solid $panel-divider-color;
display: flex; display: flex;
} }

View File

@ -0,0 +1,79 @@
/*
Copyright 2017 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_TagPanel {
width: 60px;
background-color: $tertiary-accent-color;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.mx_TagPanel .mx_TagPanel_tagTileContainer {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 65px;
flex-grow: 1;
}
.mx_TagPanel .mx_TagTile {
padding: 6px 3px;
opacity: 0.5;
}
.mx_TagPanel .mx_TagTile:focus,
.mx_TagPanel .mx_TagTile:hover,
.mx_TagPanel .mx_TagTile.mx_TagTile_selected {
opacity: 1;
}
.mx_TagPanel .mx_TagTile.mx_TagTile_selected {
/* To offset border of mx_TagTile_avatar */
padding: 3px 0px;
}
.mx_TagPanel .mx_TagTile.mx_TagTile_selected .mx_TagTile_avatar {
border: 3px solid $accent-color;
border-radius: 60px;
}
.mx_TagPanel .mx_TagTile.mx_AccessibleButton:focus {
filter: none;
}
.mx_TagTile_tooltip {
position: relative;
top: -30px;
left: 5px;
}
.mx_TagPanel_createGroupButton {
opacity: 0.5;
margin-bottom: 17px;
height: 25px;
}
.mx_TagPanel_createGroupButton:hover {
opacity: 1;
}
.mx_TagPanel_createGroupButton object {
pointer-events: none;
}

View File

@ -0,0 +1,26 @@
/*
Copyright 2017 Vector Creations 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_Quote .mx_DateSeparator {
font-size: 1em !important;
margin-bottom: 0;
padding-bottom: 1px;
bottom: -5px;
}
.mx_Quote_show {
cursor: pointer;
}

View File

@ -19,4 +19,5 @@ limitations under the License.
border: 1px solid $primary-hairline-color; border: 1px solid $primary-hairline-color;
border-radius: 3px; border-radius: 3px;
margin-right: 32px; margin-right: 32px;
overflow: hidden;
} }

View File

@ -85,6 +85,14 @@ limitations under the License.
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
cursor: pointer;
}
.mx_AppTileMenuBarTitle {
display: flex;
flex-direction: row;
align-items: center;
pointer-events: none;
} }
.mx_AppTileMenuBarWidgets { .mx_AppTileMenuBarWidgets {
@ -93,6 +101,7 @@ limitations under the License.
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
} }
.mx_AppTileMenuBarWidget { .mx_AppTileMenuBarWidget {
// pointer-events: none; // pointer-events: none;
cursor: pointer; cursor: pointer;

View File

@ -1,7 +1,7 @@
.mx_Autocomplete { .mx_Autocomplete {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
z-index: 1000; z-index: 1001;
width: 100%; width: 100%;
border: 1px solid $primary-hairline-color; border: 1px solid $primary-hairline-color;
background: $primary-bg-color; background: $primary-bg-color;
@ -90,3 +90,4 @@
.mx_Autocomplete_Completion_description { .mx_Autocomplete_Completion_description {
color: gray; color: gray;
} }

View File

@ -96,6 +96,10 @@ limitations under the License.
line-height: 22px; line-height: 22px;
} }
.mx_EventTile_quote {
margin-right: 10px;
}
.mx_EventTile_info .mx_EventTile_line { .mx_EventTile_info .mx_EventTile_line {
padding-left: 83px; padding-left: 83px;
} }
@ -109,13 +113,13 @@ limitations under the License.
/* this is used for the tile for the event which is selected via the URL. /* this is used for the tile for the event which is selected via the URL.
* TODO: ultimately we probably want some transition on here. * TODO: ultimately we probably want some transition on here.
*/ */
.mx_EventTile_selected .mx_EventTile_line { .mx_EventTile_selected > .mx_EventTile_line {
border-left: $accent-color 5px solid; border-left: $accent-color 5px solid;
padding-left: 60px; padding-left: 60px;
background-color: $event-selected-color; background-color: $event-selected-color;
} }
.mx_EventTile:hover .mx_EventTile_line, .mx_EventTile:hover .mx_EventTile_line:not(.mx_EventTile_quote),
.mx_EventTile.menu .mx_EventTile_line .mx_EventTile.menu .mx_EventTile_line
{ {
background-color: $event-selected-color; background-color: $event-selected-color;
@ -209,7 +213,7 @@ limitations under the License.
visibility: visible; visibility: visible;
} }
.mx_EventTile_selected .mx_MessageTimestamp { .mx_EventTile_selected > div > a > .mx_MessageTimestamp {
left: 3px; left: 3px;
width: auto; width: auto;
} }
@ -224,6 +228,10 @@ limitations under the License.
width: 19px; width: 19px;
height: 19px; height: 19px;
background-image: url($edit-button-url); background-image: url($edit-button-url);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
} }
.mx_EventTile:hover .mx_EventTile_editButton, .mx_EventTile:hover .mx_EventTile_editButton,

View File

@ -98,6 +98,9 @@ limitations under the License.
width: 100%; width: 100%;
flex: 1; flex: 1;
word-break: break-word; word-break: break-word;
max-height: 120px;
min-height: 21px;
overflow: auto;
} }
.mx_MessageComposer_input .DraftEditor-root .DraftEditor-editorContainer { .mx_MessageComposer_input .DraftEditor-root .DraftEditor-editorContainer {
@ -105,12 +108,6 @@ limitations under the License.
padding-top: 2px; padding-top: 2px;
} }
.mx_MessageComposer_input .public-DraftEditor-content {
max-height: 120px;
min-height: 21px;
overflow: auto;
}
.mx_MessageComposer_input blockquote { .mx_MessageComposer_input blockquote {
color: $blockquote-fg-color; color: $blockquote-fg-color;
margin: 0 0 16px; margin: 0 0 16px;

View File

@ -0,0 +1,36 @@
.mx_QuotePreview {
position: absolute;
bottom: 0;
z-index: 1000;
width: 100%;
border: 1px solid $primary-hairline-color;
background: $primary-bg-color;
border-bottom: none;
border-radius: 4px 4px 0 0;
max-height: 50vh;
overflow: auto
}
.mx_QuotePreview_section {
border-bottom: 1px solid $primary-hairline-color;
}
.mx_QuotePreview_header {
margin: 12px;
color: $primary-fg-color;
font-weight: 400;
opacity: 0.4;
}
.mx_QuotePreview_title {
float: left;
}
.mx_QuotePreview_cancel {
float: right;
cursor: pointer;
}
.mx_QuotePreview_clear {
clear: both;
}

View File

@ -20,6 +20,8 @@ limitations under the License.
font-size: 13px; font-size: 13px;
display: block; display: block;
height: 34px; height: 34px;
background-color: $secondary-accent-color;
} }
.mx_RoomTile_tooltip { .mx_RoomTile_tooltip {
@ -155,6 +157,15 @@ limitations under the License.
background-color: $roomtile-selected-bg-color; background-color: $roomtile-selected-bg-color;
} }
.mx_DNDRoomTile {
transform: none;
transition: transform 0.2s;
}
.mx_DNDRoomTile_dragging {
transform: scale(1.05, 1.05);
}
.mx_RoomTile:focus { .mx_RoomTile:focus {
filter: none ! important; filter: none ! important;
background-color: $roomtile-focused-bg-color; background-color: $roomtile-focused-bg-color;

View File

@ -40,6 +40,7 @@ $preview-bar-bg-color: #f7f7f7;
// left-panel style muted accent color // left-panel style muted accent color
$secondary-accent-color: #eaf5f0; $secondary-accent-color: #eaf5f0;
$tertiary-accent-color: #d3efe1;
// used by RoomDirectory permissions // used by RoomDirectory permissions
$plinth-bg-color: $secondary-accent-color; $plinth-bg-color: $secondary-accent-color;
@ -48,7 +49,7 @@ $plinth-bg-color: $secondary-accent-color;
$droptarget-bg-color: rgba(255,255,255,0.5); $droptarget-bg-color: rgba(255,255,255,0.5);
// used by AddressSelector // used by AddressSelector
$selected-color: #eaf5f0; $selected-color: $secondary-accent-color;
// selected for hoverover & selected event tiles // selected for hoverover & selected event tiles
$event-selected-color: #f7f7f7; $event-selected-color: #f7f7f7;
@ -103,15 +104,16 @@ $roomtile-name-color: rgba(69, 69, 69, 0.8);
$roomtile-selected-bg-color: rgba(255, 255, 255, 0.8); $roomtile-selected-bg-color: rgba(255, 255, 255, 0.8);
$roomtile-focused-bg-color: rgba(255, 255, 255, 0.9); $roomtile-focused-bg-color: rgba(255, 255, 255, 0.9);
$roomsublist-background: #badece;
$roomsublist-label-fg-color: $h3-color; $roomsublist-label-fg-color: $h3-color;
$roomsublist-label-bg-color: #d3efe1; $roomsublist-label-bg-color: $tertiary-accent-color;
$roomsublist-chevron-color: $accent-color; $roomsublist-chevron-color: $accent-color;
$panel-divider-color: rgba(118, 207, 166, 0.2); $panel-divider-color: rgba(118, 207, 166, 0.2);
// ******************** // ********************
$widget-menu-bar-bg-color: #d3efe1; $widget-menu-bar-bg-color: $tertiary-accent-color;
// ******************** // ********************

View File

@ -29,12 +29,13 @@ $preview-bar-bg-color: #333;
// left-panel style muted accent color // left-panel style muted accent color
$secondary-accent-color: $primary-bg-color; $secondary-accent-color: $primary-bg-color;
$tertiary-accent-color: #454545;
// stop the tinter trying to change the secondary accent color // stop the tinter trying to change the secondary accent color
// by overriding the key to something untintable // by overriding the key to something untintable
// XXX: this is a bit of a hack. // XXX: this is a bit of a hack.
#mx_theme_secondaryAccentColor { #mx_theme_secondaryAccentColor {
color: #c0ff33 ! important; // deliberately off by one color: #c0ffee ! important;
} }
#mx_theme_tertiaryAccentColor { #mx_theme_tertiaryAccentColor {
@ -99,18 +100,19 @@ $rte-code-bg-color: #000;
// ******************** // ********************
$roomtile-name-color: rgba(186, 186, 186, 0.8); $roomtile-name-color: rgba(186, 186, 186, 0.8);
$roomtile-selected-bg-color: rgba(255, 255, 255, 0.05); $roomtile-selected-bg-color: #333;
$roomtile-focused-bg-color: rgba(255, 255, 255, 0.2); $roomtile-focused-bg-color: rgba(255, 255, 255, 0.2);
$roomsublist-background: #222;
$roomsublist-label-fg-color: $h3-color; $roomsublist-label-fg-color: $h3-color;
$roomsublist-label-bg-color: #454545; $roomsublist-label-bg-color: $tertiary-accent-color;
$roomsublist-chevron-color: $accent-color; $roomsublist-chevron-color: $accent-color;
$panel-divider-color: rgba(118, 207, 166, 0.2); $panel-divider-color: rgba(118, 207, 166, 0.2);
// ******************** // ********************
$widget-menu-bar-bg-color: #454545; $widget-menu-bar-bg-color: $tertiary-accent-color;
// ******************** // ********************

View File

@ -44,6 +44,7 @@ limitations under the License.
.mx_LeftPanel.collapsed .mx_BottomLeftMenu { .mx_LeftPanel.collapsed .mx_BottomLeftMenu {
flex: 0 0 160px; flex: 0 0 160px;
margin-bottom: 9px;
} }
.mx_LeftPanel .mx_BottomLeftMenu { .mx_LeftPanel .mx_BottomLeftMenu {
@ -77,6 +78,7 @@ limitations under the License.
.mx_BottomLeftMenu_options .mx_RoleButton { .mx_BottomLeftMenu_options .mx_RoleButton {
margin-left: 0px; margin-left: 0px;
margin-right: 10px; margin-right: 10px;
height: 30px;
} }
.mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings { .mx_BottomLeftMenu_options .mx_BottomLeftMenu_settings {

View File

@ -18,6 +18,8 @@ limitations under the License.
display: table; display: table;
table-layout: fixed; table-layout: fixed;
width: 100%; width: 100%;
background-color: $roomsublist-background;
} }
.mx_RoomSubList_labelContainer { .mx_RoomSubList_labelContainer {
@ -33,14 +35,13 @@ limitations under the License.
font-weight: 600; font-weight: 600;
font-size: 12px; font-size: 12px;
width: 203px; /* padding + width = LHS Panel width */ width: 203px; /* padding + width = LHS Panel width */
height: 17px; /* padding + height = 29px, same as mx_RoomSubList_stickyContainer */ height: 19px; /* height + padding = 31px = mx_RoomSubList_label height */
padding-left: 16px; /* gutter */ padding-left: 16px; /* gutter */
padding-right: 16px; /* gutter */ padding-right: 16px; /* gutter */
padding-top: 6px; padding-top: 6px;
padding-bottom: 6px; padding-bottom: 6px;
cursor: pointer; cursor: pointer;
background-color: $roomsublist-label-bg-color; background-color: $secondary-accent-color;
border-top: solid 2px $secondary-accent-color;
} }
.mx_RoomSubList_label.mx_RoomSubList_fixed { .mx_RoomSubList_label.mx_RoomSubList_fixed {
@ -156,6 +157,8 @@ limitations under the License.
position: relative; position: relative;
cursor: pointer; cursor: pointer;
font-size: 13px; font-size: 13px;
background-color: $secondary-accent-color;
} }
.collapsed .mx_RoomSubList_ellipsis { .collapsed .mx_RoomSubList_ellipsis {

View File

@ -0,0 +1,21 @@
/*
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
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_SyntaxHighlight {
/* inhibit hljs styling */
background: none !important;
color: $light-fg-color !important;
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="2048px" height="1792px" viewBox="0 0 2048 1792" enable-background="new 0 0 2048 1792" xml:space="preserve">
<path fill="#76CFA6" d="M1024,672c79.333,0,147.166,28.167,203.5,84.5c56.333,56.334,84.5,124.167,84.5,203.5
c0,79.334-28.167,147.167-84.5,203.5c-56.334,56.334-124.167,84.5-203.5,84.5c-79.334,0-147.167-28.166-203.5-84.5
C764.166,1107.167,736,1039.334,736,960c0-79.333,28.166-147.166,84.5-203.5C876.833,700.167,944.666,672,1024,672z M1728,256
c70.666,0,131,25,181,75s75,110.334,75,181v896c0,70.667-25,131-75,181s-110.334,75-181,75H320c-70.667,0-131-25-181-75
s-75-110.333-75-181V512c0-70.666,25-131,75-181s110.333-75,181-75h224l51-136c12.666-32.666,35.833-60.833,69.5-84.5
C698.166,11.834,732.666,0,768,0h512c35.333,0,69.833,11.834,103.5,35.5c33.666,23.667,56.833,51.834,69.5,84.5l51,136H1728z
M1024,1408c123.333,0,228.833-43.833,316.5-131.5c87.666-87.666,131.5-193.166,131.5-316.5c0-123.333-43.834-228.833-131.5-316.5
C1252.833,555.834,1147.333,512,1024,512c-123.334,0-228.834,43.834-316.5,131.5C619.833,731.167,576,836.667,576,960
c0,123.334,43.833,228.834,131.5,316.5C795.166,1364.167,900.666,1408,1024,1408z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1792px" height="1792px" viewBox="0 0 1792 1792" enable-background="new 0 0 1792 1792" xml:space="preserve">
<path fill="#76CFA6" d="M256,1408h1280V640H256V1408z M1792,288v1216c0,44-15.667,81.667-47,113s-69,47-113,47H160
c-44,0-81.667-15.667-113-47s-47-69-47-113V288c0-44,15.667-81.667,47-113s69-47,113-47h1472c44,0,81.667,15.667,113,47
S1792,244,1792,288z"/>
</svg>

After

Width:  |  Height:  |  Size: 745 B

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1792px" height="1792px" viewBox="0 0 1792 1792" enable-background="new 0 0 1792 1792" xml:space="preserve">
<path fill="#76CFA6" d="M1792,1312v192c0,44-15.667,81.667-47,113s-69,47-113,47H160c-44,0-81.667-15.667-113-47s-47-69-47-113v-192
c0-44,15.667-81.667,47-113s69-47,113-47h1472c44,0,81.667,15.667,113,47S1792,1268,1792,1312z"/>
</svg>

After

Width:  |  Height:  |  Size: 716 B

View File

@ -85,6 +85,7 @@ $preview-bar-bg-color: #f7f7f7;
// left-panel style muted accent color // left-panel style muted accent color
$secondary-accent-color: #586C7B; $secondary-accent-color: #586C7B;
$tertiary-accent-color: #DBEBF6;
// stop the tinter trying to change the secondary accent color // stop the tinter trying to change the secondary accent color
// by overriding the key to something untintable // by overriding the key to something untintable
@ -159,6 +160,7 @@ $roomtile-name-color: #ffffff;
$roomtile-selected-bg-color: #465561; $roomtile-selected-bg-color: #465561;
$roomtile-focused-bg-color: #6d8597; $roomtile-focused-bg-color: #6d8597;
$roomsublist-background: #465561;
$roomsublist-label-fg-color: #ffffff; $roomsublist-label-fg-color: #ffffff;
$roomsublist-label-bg-color: $secondary-accent-color; $roomsublist-label-bg-color: $secondary-accent-color;
$roomsublist-chevron-color: #ffffff; $roomsublist-chevron-color: #ffffff;
@ -236,7 +238,7 @@ $progressbar-color: #000;
.mx_RoomSubList_label { .mx_RoomSubList_label {
font-size: 13px; font-size: 13px;
font-family: $header-font-family; font-family: $header-font-family;
letter-spacing: 1px; letter-spacing: 1px;
} }
// FIXME: all these ! importants are horrid - we should instead go and define // FIXME: all these ! importants are horrid - we should instead go and define

View File

@ -387,6 +387,7 @@ async function loadLanguage() {
} }
try { try {
await languageHandler.setLanguage(langs); await languageHandler.setLanguage(langs);
document.documentElement.setAttribute("lang", languageHandler.getCurrentLanguage());
} catch (e) { } catch (e) {
console.error("Unable to set language", e); console.error("Unable to set language", e);
} }

View File

@ -16,6 +16,9 @@ limitations under the License.
/* joining.js: tests for the various paths when joining a room */ /* joining.js: tests for the various paths when joining a room */
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
import Platform from '../../src/vector/platform';
require('skin-sdk'); require('skin-sdk');
var jssdk = require('matrix-js-sdk'); var jssdk = require('matrix-js-sdk');
@ -85,6 +88,8 @@ describe('joining a room', function () {
localStorage.setItem("mx_access_token", ACCESS_TOKEN ); localStorage.setItem("mx_access_token", ACCESS_TOKEN );
localStorage.setItem("mx_user_id", USER_ID); localStorage.setItem("mx_user_id", USER_ID);
PlatformPeg.set(new Platform());
var mc = ( var mc = (
<MatrixChat config={{}} <MatrixChat config={{}}
makeRegistrationUrl={()=>{throw new Error("unimplemented");}} makeRegistrationUrl={()=>{throw new Error("unimplemented");}}

View File

@ -16,6 +16,9 @@ limitations under the License.
/* loading.js: test the myriad paths we have for loading the application */ /* loading.js: test the myriad paths we have for loading the application */
import PlatformPeg from 'matrix-react-sdk/lib/PlatformPeg';
import Platform from '../../src/vector/platform';
import 'skin-sdk'; import 'skin-sdk';
import React from 'react'; import React from 'react';
@ -137,6 +140,8 @@ describe('loading:', function () {
default_is_url: DEFAULT_IS_URL, default_is_url: DEFAULT_IS_URL,
}, opts.config || {}); }, opts.config || {});
PlatformPeg.set(new Platform());
var params = parseQs(windowLocation); var params = parseQs(windowLocation);
matrixChat = ReactDOM.render( matrixChat = ReactDOM.render(
<MatrixChat <MatrixChat