Merge remote-tracking branch 'origin/develop' into dbkr/translations

This commit is contained in:
David Baker 2017-05-26 17:30:02 +01:00
commit c22978d033
5 changed files with 55 additions and 33 deletions

View file

@ -51,40 +51,52 @@ function pad(n) {
return (n < 10 ? '0' : '') + n; return (n < 10 ? '0' : '') + n;
} }
function twelveHourTime(date) {
let hours = date.getHours() % 12;
const minutes = pad(date.getMinutes());
const ampm = hours >= 12 ? 'PM' : 'AM';
hours = pad(hours ? hours : 12);
return `${hours}:${minutes} ${ampm}`;
}
module.exports = { module.exports = {
formatDate: function(date) { formatDate: function(date) {
// date.toLocaleTimeString is completely system dependent.
// just go 24h for now
const days = getDaysArray();
const months = getMonthsArray();
// TODO: use standard date localize function provided in counterpart
var hoursAndMinutes = pad(date.getHours()) + ':' + pad(date.getMinutes());
var now = new Date(); var now = new Date();
if (date.toDateString() === now.toDateString()) { if (date.toDateString() === now.toDateString()) {
return hoursAndMinutes; return this.formatTime(date);
} }
else if (now.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) { else if (now.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
// TODO: use standard date localize function provided in counterpart // TODO: use standard date localize function provided in counterpart
return _t('%(weekDayName)s %(time)s', {weekDayName: days[date.getDay()], time: hoursAndMinutes}); return _t('%(weekDayName)s %(time)s', {weekDayName: days[date.getDay()], time: this.formatTime(date)});
} }
else if (now.getFullYear() === date.getFullYear()) { else if (now.getFullYear() === date.getFullYear()) {
// TODO: use standard date localize function provided in counterpart // TODO: use standard date localize function provided in counterpart
return _t('%(weekDayName)s, %(monthName)s %(day)s %(time)s', {weekDayName: days[date.getDay()], monthName: months[date.getMonth()], day: date.getDate(), time: hoursAndMinutes}); return _t('%(weekDayName)s, %(monthName)s %(day)s %(time)s', {
} weekDayName: days[date.getDay()],
else { monthName: months[date.getMonth()],
return this.formatFullDate(date); day: date.getDate(),
time: this.formatTime(date),
});
} }
return this.formatFullDate(date);
}, },
formatFullDate: function(date) { formatFullDate: function(date) {
const days = getDaysArray(); const days = getDaysArray();
const months = getMonthsArray(); const months = getMonthsArray();
var hoursAndMinutes = pad(date.getHours()) + ':' + pad(date.getMinutes()); return _t('%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s', {
return _t('%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s', {weekDayName: days[date.getDay()], monthName: months[date.getMonth()], day: date.getDate(), fullYear: date.getFullYear(),time: hoursAndMinutes}); weekDayName: days[date.getDay()],
monthName: months[date.getMonth()],
day: date.getDate(),
fullYear: date.getFullYear(),
time: this.formatTime(date),
});
}, },
formatTime: function(date) { formatTime: function(date, showTwelveHour=false) {
if (showTwelveHour) {
return twelveHourTime(date);
}
return pad(date.getHours()) + ':' + pad(date.getMinutes()); return pad(date.getHours()) + ':' + pad(date.getMinutes());
} },
}; };

View file

@ -84,6 +84,9 @@ module.exports = React.createClass({
// shape parameter to be passed to EventTiles // shape parameter to be passed to EventTiles
tileShape: React.PropTypes.string, tileShape: React.PropTypes.string,
// show twelve hour timestamps
isTwelveHour: React.PropTypes.bool,
}, },
componentWillMount: function() { componentWillMount: function() {
@ -230,8 +233,8 @@ module.exports = React.createClass({
}, },
_getEventTiles: function() { _getEventTiles: function() {
var EventTile = sdk.getComponent('rooms.EventTile'); const EventTile = sdk.getComponent('rooms.EventTile');
var DateSeparator = sdk.getComponent('messages.DateSeparator'); const DateSeparator = sdk.getComponent('messages.DateSeparator');
const MemberEventListSummary = sdk.getComponent('views.elements.MemberEventListSummary'); const MemberEventListSummary = sdk.getComponent('views.elements.MemberEventListSummary');
this.eventNodes = {}; this.eventNodes = {};
@ -413,8 +416,8 @@ module.exports = React.createClass({
}, },
_getTilesForEvent: function(prevEvent, mxEv, last) { _getTilesForEvent: function(prevEvent, mxEv, last) {
var EventTile = sdk.getComponent('rooms.EventTile'); const EventTile = sdk.getComponent('rooms.EventTile');
var DateSeparator = sdk.getComponent('messages.DateSeparator'); const DateSeparator = sdk.getComponent('messages.DateSeparator');
var ret = []; var ret = [];
// is this a continuation of the previous message? // is this a continuation of the previous message?
@ -468,7 +471,6 @@ module.exports = React.createClass({
if (this.props.manageReadReceipts) { if (this.props.manageReadReceipts) {
readReceipts = this._getReadReceiptsForEvent(mxEv); readReceipts = this._getReadReceiptsForEvent(mxEv);
} }
ret.push( ret.push(
<li key={eventId} <li key={eventId}
ref={this._collectEventNode.bind(this, eventId)} ref={this._collectEventNode.bind(this, eventId)}
@ -482,6 +484,7 @@ module.exports = React.createClass({
checkUnmounting={this._isUnmounting} checkUnmounting={this._isUnmounting}
eventSendStatus={mxEv.status} eventSendStatus={mxEv.status}
tileShape={this.props.tileShape} tileShape={this.props.tileShape}
isTwelveHour={this.props.isTwelveHour}
last={last} isSelectedEvent={highlight}/> last={last} isSelectedEvent={highlight}/>
</li> </li>
); );

View file

@ -30,6 +30,7 @@ var ObjectUtils = require('../../ObjectUtils');
var Modal = require("../../Modal"); var Modal = require("../../Modal");
var UserActivity = require("../../UserActivity"); var UserActivity = require("../../UserActivity");
var KeyCode = require('../../KeyCode'); var KeyCode = require('../../KeyCode');
import UserSettingsStore from '../../UserSettingsStore';
var PAGINATE_SIZE = 20; var PAGINATE_SIZE = 20;
var INITIAL_SIZE = 20; var INITIAL_SIZE = 20;
@ -123,7 +124,7 @@ var TimelinePanel = React.createClass({
let initialReadMarker = null; let initialReadMarker = null;
if (this.props.manageReadMarkers) { if (this.props.manageReadMarkers) {
const readmarker = this.props.timelineSet.room.getAccountData('m.fully_read'); const readmarker = this.props.timelineSet.room.getAccountData('m.fully_read');
if (readmarker){ if (readmarker) {
initialReadMarker = readmarker.getContent().event_id; initialReadMarker = readmarker.getContent().event_id;
} else { } else {
initialReadMarker = this._getCurrentReadReceipt(); initialReadMarker = this._getCurrentReadReceipt();
@ -172,6 +173,9 @@ var TimelinePanel = React.createClass({
// cache of matrixClient.getSyncState() (but from the 'sync' event) // cache of matrixClient.getSyncState() (but from the 'sync' event)
clientSyncState: MatrixClientPeg.get().getSyncState(), clientSyncState: MatrixClientPeg.get().getSyncState(),
// should the event tiles have twelve hour times
isTwelveHour: UserSettingsStore.getSyncedSetting('showTwelveHourTimestamps'),
}; };
}, },
@ -1104,7 +1108,6 @@ var TimelinePanel = React.createClass({
const forwardPaginating = ( const forwardPaginating = (
this.state.forwardPaginating || this.state.clientSyncState == 'PREPARED' this.state.forwardPaginating || this.state.clientSyncState == 'PREPARED'
); );
return ( return (
<MessagePanel ref="messagePanel" <MessagePanel ref="messagePanel"
hidden={ this.props.hidden } hidden={ this.props.hidden }
@ -1123,6 +1126,7 @@ var TimelinePanel = React.createClass({
onFillRequest={ this.onMessageListFillRequest } onFillRequest={ this.onMessageListFillRequest }
onUnfillRequest={ this.onMessageListUnfillRequest } onUnfillRequest={ this.onMessageListUnfillRequest }
opacity={ this.props.opacity } opacity={ this.props.opacity }
isTwelveHour={ this.state.isTwelveHour }
className={ this.props.className } className={ this.props.className }
tileShape={ this.props.tileShape } tileShape={ this.props.tileShape }
/> />

View file

@ -70,7 +70,6 @@ const SETTINGS_LABELS = [
id: 'dontSendTypingNotifications', id: 'dontSendTypingNotifications',
label: "Don't send typing notifications", label: "Don't send typing notifications",
}, },
/*
{ {
id: 'alwaysShowTimestamps', id: 'alwaysShowTimestamps',
label: 'Always show message timestamps', label: 'Always show message timestamps',
@ -79,6 +78,7 @@ const SETTINGS_LABELS = [
id: 'showTwelveHourTimestamps', id: 'showTwelveHourTimestamps',
label: 'Show timestamps in 12 hour format (e.g. 2:30pm)', label: 'Show timestamps in 12 hour format (e.g. 2:30pm)',
}, },
/*
{ {
id: 'useCompactLayout', id: 'useCompactLayout',
label: 'Use compact timeline layout', label: 'Use compact timeline layout',

View file

@ -16,6 +16,7 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); var React = require('react');
var classNames = require("classnames"); var classNames = require("classnames");
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
@ -130,6 +131,9 @@ module.exports = WithMatrixClient(React.createClass({
* for now. * for now.
*/ */
tileShape: React.PropTypes.string, tileShape: React.PropTypes.string,
// show twelve hour timestamps
isTwelveHour: React.PropTypes.bool,
}, },
getInitialState: function() { getInitialState: function() {
@ -405,9 +409,10 @@ module.exports = WithMatrixClient(React.createClass({
var isSending = (['sending', 'queued', 'encrypting'].indexOf(this.props.eventSendStatus) !== -1); var isSending = (['sending', 'queued', 'encrypting'].indexOf(this.props.eventSendStatus) !== -1);
const isRedacted = (eventType === 'm.room.message') && this.props.isRedacted; const isRedacted = (eventType === 'm.room.message') && this.props.isRedacted;
var classes = classNames({ const classes = classNames({
mx_EventTile: true, mx_EventTile: true,
mx_EventTile_info: isInfoMessage, mx_EventTile_info: isInfoMessage,
mx_EventTile_12hr: this.props.isTwelveHour,
mx_EventTile_encrypting: this.props.eventSendStatus == 'encrypting', mx_EventTile_encrypting: this.props.eventSendStatus == 'encrypting',
mx_EventTile_sending: isSending, mx_EventTile_sending: isSending,
mx_EventTile_notSent: this.props.eventSendStatus == 'not_sent', mx_EventTile_notSent: this.props.eventSendStatus == 'not_sent',
@ -475,11 +480,10 @@ module.exports = WithMatrixClient(React.createClass({
} }
} }
var editButton = ( const editButton = (
<span className="mx_EventTile_editButton" title="Options" onClick={this.onEditClicked} /> <span className="mx_EventTile_editButton" title="Options" onClick={this.onEditClicked} />
); );
let e2e;
var e2e;
// cosmetic padlocks: // cosmetic padlocks:
if ((e2eEnabled && this.props.eventSendStatus) || this.props.mxEvent.getType() === 'm.room.encryption') { if ((e2eEnabled && this.props.eventSendStatus) || this.props.mxEvent.getType() === 'm.room.encryption') {
e2e = <img style={{ cursor: 'initial', marginLeft: '-1px' }} className="mx_EventTile_e2eIcon" alt="Encrypted by verified device" src="img/e2e-verified.svg" width="10" height="12" />; e2e = <img style={{ cursor: 'initial', marginLeft: '-1px' }} className="mx_EventTile_e2eIcon" alt="Encrypted by verified device" src="img/e2e-verified.svg" width="10" height="12" />;
@ -490,7 +494,7 @@ module.exports = WithMatrixClient(React.createClass({
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Undecryptable" src="img/e2e-blocked.svg" width="12" height="12" style={{ marginLeft: "-1px" }} />; e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Undecryptable" src="img/e2e-blocked.svg" width="12" height="12" style={{ marginLeft: "-1px" }} />;
} }
else if (this.state.verified == true || (e2eEnabled && this.props.eventSendStatus)) { else if (this.state.verified == true || (e2eEnabled && this.props.eventSendStatus)) {
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Encrypted by verified device" src="img/e2e-verified.svg" width="10" height="12"/>; e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Encrypted by verified device" src="img/e2e-verified.svg" width="10" height="12"/>;
} }
else { else {
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Encrypted by unverified device" src="img/e2e-warning.svg" width="15" height="12" style={{ marginLeft: "-2px" }}/>; e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Encrypted by unverified device" src="img/e2e-warning.svg" width="15" height="12" style={{ marginLeft: "-2px" }}/>;
@ -500,11 +504,10 @@ module.exports = WithMatrixClient(React.createClass({
e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Unencrypted message" src="img/e2e-unencrypted.svg" width="12" height="12"/>; e2e = <img onClick={ this.onCryptoClicked } className="mx_EventTile_e2eIcon" alt="Unencrypted message" src="img/e2e-unencrypted.svg" width="12" height="12"/>;
} }
const timestamp = this.props.mxEvent.getTs() ? const timestamp = this.props.mxEvent.getTs() ?
<MessageTimestamp ts={this.props.mxEvent.getTs()} /> : null; <MessageTimestamp showTwelveHour={this.props.isTwelveHour} ts={this.props.mxEvent.getTs()} /> : null;
if (this.props.tileShape === "notif") { if (this.props.tileShape === "notif") {
var room = this.props.matrixClient.getRoom(this.props.mxEvent.getRoomId()); const room = this.props.matrixClient.getRoom(this.props.mxEvent.getRoomId());
return ( return (
<div className={classes}> <div className={classes}>
<div className="mx_EventTile_roomName"> <div className="mx_EventTile_roomName">