New React component: Message
Also: Use react to render contects on the 'show group members' screen
This commit is contained in:
parent
3ea14ce450
commit
dc11db92f9
48 changed files with 5299 additions and 2093 deletions
|
@ -15,6 +15,7 @@ const Util = require('../../ts/util');
|
|||
const {
|
||||
ContactDetail,
|
||||
} = require('../../ts/components/conversation/ContactDetail');
|
||||
const { ContactListItem } = require('../../ts/components/ContactListItem');
|
||||
const { ContactName } = require('../../ts/components/conversation/ContactName');
|
||||
const {
|
||||
ConversationTitle,
|
||||
|
@ -105,6 +106,7 @@ exports.setup = (options = {}) => {
|
|||
|
||||
const Components = {
|
||||
ContactDetail,
|
||||
ContactListItem,
|
||||
ContactName,
|
||||
ConversationTitle,
|
||||
EmbeddedContact,
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
/* global Whisper: false */
|
||||
/* global i18n: false */
|
||||
/* global textsecure: false */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
Whisper.ContactListView = Whisper.ListView.extend({
|
||||
|
@ -11,36 +17,45 @@
|
|||
events: {
|
||||
click: 'showIdentity',
|
||||
},
|
||||
initialize: function(options) {
|
||||
initialize(options) {
|
||||
this.ourNumber = textsecure.storage.user.getNumber();
|
||||
this.listenBack = options.listenBack;
|
||||
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
},
|
||||
render_attributes: function() {
|
||||
if (this.model.id === this.ourNumber) {
|
||||
return {
|
||||
title: i18n('me'),
|
||||
number: this.model.getNumber(),
|
||||
avatar: this.model.getAvatar(),
|
||||
};
|
||||
render() {
|
||||
if (this.contactView) {
|
||||
this.contactView.remove();
|
||||
this.contactView = null;
|
||||
}
|
||||
|
||||
return {
|
||||
class: 'clickable',
|
||||
title: this.model.getTitle(),
|
||||
number: this.model.getNumber(),
|
||||
avatar: this.model.getAvatar(),
|
||||
profileName: this.model.getProfileName(),
|
||||
isVerified: this.model.isVerified(),
|
||||
verified: i18n('verified'),
|
||||
};
|
||||
const avatar = this.model.getAvatar();
|
||||
const avatarPath = avatar && avatar.url;
|
||||
const color = avatar && avatar.color;
|
||||
const isMe = this.ourNumber === this.model.id;
|
||||
|
||||
this.contactView = new Whisper.ReactWrapperView({
|
||||
className: 'contact-wrapper',
|
||||
Component: window.Signal.Components.ContactListItem,
|
||||
props: {
|
||||
isMe,
|
||||
color,
|
||||
avatarPath,
|
||||
phoneNumber: this.model.getNumber(),
|
||||
name: this.model.getName(),
|
||||
profileName: this.model.getProfileName(),
|
||||
verified: this.model.isVerified(),
|
||||
onClick: this.showIdentity.bind(this),
|
||||
},
|
||||
});
|
||||
this.$el.append(this.contactView.el);
|
||||
return this;
|
||||
},
|
||||
showIdentity: function() {
|
||||
showIdentity() {
|
||||
if (this.model.id === this.ourNumber) {
|
||||
return;
|
||||
}
|
||||
var view = new Whisper.KeyVerificationPanelView({
|
||||
const view = new Whisper.KeyVerificationPanelView({
|
||||
model: this.model,
|
||||
});
|
||||
this.listenBack(view);
|
||||
|
|
|
@ -1,28 +1,84 @@
|
|||
/* global moment: false */
|
||||
/* global Whisper: false */
|
||||
/* global extension: false */
|
||||
/* global i18n: false */
|
||||
/* global _: false */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.Whisper = window.Whisper || {};
|
||||
|
||||
function extendedRelativeTime(number, string) {
|
||||
return moment.duration(-1 * number, string).humanize(string !== 's');
|
||||
}
|
||||
|
||||
const extendedFormats = {
|
||||
y: 'lll',
|
||||
M: `${i18n('timestampFormat_M') || 'MMM D'} LT`,
|
||||
d: 'ddd LT',
|
||||
};
|
||||
|
||||
function shortRelativeTime(number, string) {
|
||||
return moment.duration(number, string).humanize();
|
||||
}
|
||||
const shortFormats = {
|
||||
y: 'll',
|
||||
M: i18n('timestampFormat_M') || 'MMM D',
|
||||
d: 'ddd',
|
||||
};
|
||||
|
||||
function getRelativeTimeSpanString(rawTimestamp, options = {}) {
|
||||
_.defaults(options, { extended: false });
|
||||
|
||||
const relativeTime = options.extended
|
||||
? extendedRelativeTime
|
||||
: shortRelativeTime;
|
||||
const formats = options.extended ? extendedFormats : shortFormats;
|
||||
|
||||
// Convert to moment timestamp if it isn't already
|
||||
const timestamp = moment(rawTimestamp);
|
||||
const now = moment();
|
||||
const timediff = moment.duration(now - timestamp);
|
||||
|
||||
if (timediff.years() > 0) {
|
||||
return timestamp.format(formats.y);
|
||||
} else if (timediff.months() > 0 || timediff.days() > 6) {
|
||||
return timestamp.format(formats.M);
|
||||
} else if (timediff.days() > 0) {
|
||||
return timestamp.format(formats.d);
|
||||
} else if (timediff.hours() >= 1) {
|
||||
return relativeTime(timediff.hours(), 'h');
|
||||
} else if (timediff.minutes() >= 1) {
|
||||
// Note that humanize seems to jump to '1 hour' as soon as we cross 45 minutes
|
||||
return relativeTime(timediff.minutes(), 'm');
|
||||
}
|
||||
|
||||
return relativeTime(timediff.seconds(), 's');
|
||||
}
|
||||
|
||||
Whisper.TimestampView = Whisper.View.extend({
|
||||
initialize: function(options) {
|
||||
initialize() {
|
||||
extension.windows.onClosed(this.clearTimeout.bind(this));
|
||||
},
|
||||
update: function() {
|
||||
update() {
|
||||
this.clearTimeout();
|
||||
var millis_now = Date.now();
|
||||
var millis = this.$el.data('timestamp');
|
||||
const millisNow = Date.now();
|
||||
let millis = this.$el.data('timestamp');
|
||||
if (millis === '') {
|
||||
return;
|
||||
}
|
||||
if (millis >= millis_now) {
|
||||
millis = millis_now;
|
||||
if (millis >= millisNow) {
|
||||
millis = millisNow;
|
||||
}
|
||||
var result = this.getRelativeTimeSpanString(millis);
|
||||
const result = this.getRelativeTimeSpanString(millis);
|
||||
this.delay = this.getDelay(millis);
|
||||
this.$el.text(result);
|
||||
|
||||
var timestamp = moment(millis);
|
||||
const timestamp = moment(millis);
|
||||
this.$el.attr('title', timestamp.format('llll'));
|
||||
|
||||
var millis_since = millis_now - millis;
|
||||
if (this.delay) {
|
||||
if (this.delay < 0) {
|
||||
this.delay = 1000;
|
||||
|
@ -30,70 +86,44 @@
|
|||
this.timeout = setTimeout(this.update.bind(this), this.delay);
|
||||
}
|
||||
},
|
||||
clearTimeout: function() {
|
||||
clearTimeout() {
|
||||
clearTimeout(this.timeout);
|
||||
},
|
||||
getRelativeTimeSpanString: function(timestamp_) {
|
||||
getRelativeTimeSpanString(timestamp) {
|
||||
return getRelativeTimeSpanString(timestamp);
|
||||
},
|
||||
getDelay(rawTimestamp) {
|
||||
// Convert to moment timestamp if it isn't already
|
||||
var timestamp = moment(timestamp_),
|
||||
now = moment(),
|
||||
timediff = moment.duration(now - timestamp);
|
||||
const timestamp = moment(rawTimestamp);
|
||||
const now = moment();
|
||||
const timediff = moment.duration(now - timestamp);
|
||||
|
||||
if (timediff.years() > 0) {
|
||||
this.delay = null;
|
||||
return timestamp.format(this._format.y);
|
||||
return null;
|
||||
} else if (timediff.months() > 0 || timediff.days() > 6) {
|
||||
this.delay = null;
|
||||
return timestamp.format(this._format.M);
|
||||
return null;
|
||||
} else if (timediff.days() > 0) {
|
||||
this.delay = moment(timestamp)
|
||||
return moment(timestamp)
|
||||
.add(timediff.days() + 1, 'd')
|
||||
.diff(now);
|
||||
return timestamp.format(this._format.d);
|
||||
} else if (timediff.hours() > 1) {
|
||||
this.delay = moment(timestamp)
|
||||
} else if (timediff.hours() >= 1) {
|
||||
return moment(timestamp)
|
||||
.add(timediff.hours() + 1, 'h')
|
||||
.diff(now);
|
||||
return this.relativeTime(timediff.hours(), 'h');
|
||||
} else if (timediff.hours() === 1) {
|
||||
this.delay = moment(timestamp)
|
||||
.add(timediff.hours() + 1, 'h')
|
||||
.diff(now);
|
||||
return this.relativeTime(timediff.hours(), 'h');
|
||||
} else if (timediff.minutes() > 1) {
|
||||
this.delay = moment(timestamp)
|
||||
} else if (timediff.minutes() >= 1) {
|
||||
return moment(timestamp)
|
||||
.add(timediff.minutes() + 1, 'm')
|
||||
.diff(now);
|
||||
return this.relativeTime(timediff.minutes(), 'm');
|
||||
} else if (timediff.minutes() === 1) {
|
||||
this.delay = moment(timestamp)
|
||||
.add(timediff.minutes() + 1, 'm')
|
||||
.diff(now);
|
||||
return this.relativeTime(timediff.minutes(), 'm');
|
||||
} else {
|
||||
this.delay = moment(timestamp)
|
||||
.add(1, 'm')
|
||||
.diff(now);
|
||||
return this.relativeTime(timediff.seconds(), 's');
|
||||
}
|
||||
},
|
||||
relativeTime: function(number, string) {
|
||||
return moment.duration(number, string).humanize();
|
||||
},
|
||||
_format: {
|
||||
y: 'll',
|
||||
M: i18n('timestampFormat_M') || 'MMM D',
|
||||
d: 'ddd',
|
||||
|
||||
return moment(timestamp)
|
||||
.add(1, 'm')
|
||||
.diff(now);
|
||||
},
|
||||
});
|
||||
Whisper.ExtendedTimestampView = Whisper.TimestampView.extend({
|
||||
relativeTime: function(number, string, isFuture) {
|
||||
return moment.duration(-1 * number, string).humanize(string !== 's');
|
||||
},
|
||||
_format: {
|
||||
y: 'lll',
|
||||
M: (i18n('timestampFormat_M') || 'MMM D') + ' LT',
|
||||
d: 'ddd LT',
|
||||
getRelativeTimeSpanString(timestamp) {
|
||||
return getRelativeTimeSpanString(timestamp, { extended: true });
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue