Fix merge conflict
This commit is contained in:
commit
35cb52febc
17 changed files with 713 additions and 165 deletions
|
@ -123,7 +123,6 @@ src/Roles.js
|
||||||
src/Rooms.js
|
src/Rooms.js
|
||||||
src/ScalarAuthClient.js
|
src/ScalarAuthClient.js
|
||||||
src/ScalarMessaging.js
|
src/ScalarMessaging.js
|
||||||
src/TextForEvent.js
|
|
||||||
src/Tinter.js
|
src/Tinter.js
|
||||||
src/UiEffects.js
|
src/UiEffects.js
|
||||||
src/Unread.js
|
src/Unread.js
|
||||||
|
|
|
@ -107,6 +107,9 @@ export default class BasePlatform {
|
||||||
|
|
||||||
isElectron(): boolean { return false; }
|
isElectron(): boolean { return false; }
|
||||||
|
|
||||||
|
setupScreenSharingForIframe() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restarts the application, without neccessarily reloading
|
* Restarts the application, without neccessarily reloading
|
||||||
* any application code
|
* any application code
|
||||||
|
|
|
@ -18,11 +18,12 @@ import Modal from './Modal';
|
||||||
import sdk from './';
|
import sdk from './';
|
||||||
import MultiInviter from './utils/MultiInviter';
|
import MultiInviter from './utils/MultiInviter';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
|
import MatrixClientPeg from './MatrixClientPeg';
|
||||||
|
|
||||||
export function showGroupInviteDialog(groupId) {
|
export function showGroupInviteDialog(groupId) {
|
||||||
const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
|
const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
|
||||||
Modal.createTrackedDialog('Group Invite', '', AddressPickerDialog, {
|
Modal.createTrackedDialog('Group Invite', '', AddressPickerDialog, {
|
||||||
title: _t('Invite new group members'),
|
title: _t("Invite new group members"),
|
||||||
description: _t("Who would you like to add to this group?"),
|
description: _t("Who would you like to add to this group?"),
|
||||||
placeholder: _t("Name or matrix ID"),
|
placeholder: _t("Name or matrix ID"),
|
||||||
button: _t("Invite to Group"),
|
button: _t("Invite to Group"),
|
||||||
|
@ -35,6 +36,25 @@ export function showGroupInviteDialog(groupId) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function showGroupAddRoomDialog(groupId) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog");
|
||||||
|
Modal.createTrackedDialog('Add Rooms to Group', '', AddressPickerDialog, {
|
||||||
|
title: _t("Add rooms to the group"),
|
||||||
|
description: _t("Which rooms would you like to add to this group?"),
|
||||||
|
placeholder: _t("Room name or alias"),
|
||||||
|
button: _t("Add to group"),
|
||||||
|
pickerType: 'room',
|
||||||
|
validAddressTypes: ['mx'],
|
||||||
|
onFinished: (success, addrs) => {
|
||||||
|
if (!success) return;
|
||||||
|
|
||||||
|
_onGroupAddRoomFinished(groupId, addrs).then(resolve, reject);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function _onGroupInviteFinished(groupId, addrs) {
|
function _onGroupInviteFinished(groupId, addrs) {
|
||||||
const multiInviter = new MultiInviter(groupId);
|
const multiInviter = new MultiInviter(groupId);
|
||||||
|
|
||||||
|
@ -65,3 +85,27 @@ function _onGroupInviteFinished(groupId, addrs) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _onGroupAddRoomFinished(groupId, addrs) {
|
||||||
|
const errorList = [];
|
||||||
|
return Promise.all(addrs.map((addr) => {
|
||||||
|
return MatrixClientPeg.get()
|
||||||
|
.addRoomToGroup(groupId, addr.address)
|
||||||
|
.catch(() => { errorList.push(addr.address); })
|
||||||
|
.reflect();
|
||||||
|
})).then(() => {
|
||||||
|
if (errorList.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createTrackedDialog(
|
||||||
|
'Failed to add the following room to the group',
|
||||||
|
'', ErrorDialog,
|
||||||
|
{
|
||||||
|
title: _t(
|
||||||
|
"Failed to add the following rooms to %(groupId)s:",
|
||||||
|
{groupId},
|
||||||
|
),
|
||||||
|
description: errorList.join(", "),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -13,56 +13,67 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
import MatrixClientPeg from "./MatrixClientPeg";
|
import MatrixClientPeg from './MatrixClientPeg';
|
||||||
import CallHandler from "./CallHandler";
|
import CallHandler from './CallHandler';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
import * as Roles from './Roles';
|
import * as Roles from './Roles';
|
||||||
|
|
||||||
function textForMemberEvent(ev) {
|
function textForMemberEvent(ev) {
|
||||||
// XXX: SYJS-16 "sender is sometimes null for join messages"
|
// XXX: SYJS-16 "sender is sometimes null for join messages"
|
||||||
var senderName = ev.sender ? ev.sender.name : ev.getSender();
|
const senderName = ev.sender ? ev.sender.name : ev.getSender();
|
||||||
var targetName = ev.target ? ev.target.name : ev.getStateKey();
|
const targetName = ev.target ? ev.target.name : ev.getStateKey();
|
||||||
var ConferenceHandler = CallHandler.getConferenceHandler();
|
const prevContent = ev.getPrevContent();
|
||||||
var reason = ev.getContent().reason ? (
|
const content = ev.getContent();
|
||||||
_t('Reason') + ': ' + ev.getContent().reason
|
|
||||||
) : "";
|
const ConferenceHandler = CallHandler.getConferenceHandler();
|
||||||
switch (ev.getContent().membership) {
|
const reason = content.reason ? (_t('Reason') + ': ' + content.reason) : '';
|
||||||
case 'invite':
|
switch (content.membership) {
|
||||||
var threePidContent = ev.getContent().third_party_invite;
|
case 'invite': {
|
||||||
|
const threePidContent = content.third_party_invite;
|
||||||
if (threePidContent) {
|
if (threePidContent) {
|
||||||
if (threePidContent.display_name) {
|
if (threePidContent.display_name) {
|
||||||
return _t('%(targetName)s accepted the invitation for %(displayName)s.', {targetName: targetName, displayName: threePidContent.display_name});
|
return _t('%(targetName)s accepted the invitation for %(displayName)s.', {
|
||||||
|
targetName,
|
||||||
|
displayName: threePidContent.display_name,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
return _t('%(targetName)s accepted an invitation.', {targetName: targetName});
|
return _t('%(targetName)s accepted an invitation.', {targetName});
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
|
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
|
||||||
return _t('%(senderName)s requested a VoIP conference.', {senderName: senderName});
|
return _t('%(senderName)s requested a VoIP conference.', {senderName});
|
||||||
}
|
} else {
|
||||||
else {
|
return _t('%(senderName)s invited %(targetName)s.', {senderName, targetName});
|
||||||
return _t('%(senderName)s invited %(targetName)s.', {senderName: senderName, targetName: targetName});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case 'ban':
|
case 'ban':
|
||||||
return _t(
|
return _t('%(senderName)s banned %(targetName)s.', {senderName, targetName}) + ' ' + reason;
|
||||||
'%(senderName)s banned %(targetName)s.',
|
|
||||||
{senderName: senderName, targetName: targetName}
|
|
||||||
) + ' ' + reason;
|
|
||||||
case 'join':
|
case 'join':
|
||||||
if (ev.getPrevContent() && ev.getPrevContent().membership == 'join') {
|
if (prevContent && prevContent.membership === 'join') {
|
||||||
if (ev.getPrevContent().displayname && ev.getContent().displayname && ev.getPrevContent().displayname != ev.getContent().displayname) {
|
if (prevContent.displayname && content.displayname && prevContent.displayname !== content.displayname) {
|
||||||
return _t('%(senderName)s changed their display name from %(oldDisplayName)s to %(displayName)s.', {senderName: ev.getSender(), oldDisplayName: ev.getPrevContent().displayname, displayName: ev.getContent().displayname});
|
return _t('%(senderName)s changed their display name from %(oldDisplayName)s to %(displayName)s.', {
|
||||||
} else if (!ev.getPrevContent().displayname && ev.getContent().displayname) {
|
senderName,
|
||||||
return _t('%(senderName)s set their display name to %(displayName)s.', {senderName: ev.getSender(), displayName: ev.getContent().displayname});
|
oldDisplayName: prevContent.displayname,
|
||||||
} else if (ev.getPrevContent().displayname && !ev.getContent().displayname) {
|
displayName: content.displayname,
|
||||||
return _t('%(senderName)s removed their display name (%(oldDisplayName)s).', {senderName: ev.getSender(), oldDisplayName: ev.getPrevContent().displayname});
|
});
|
||||||
} else if (ev.getPrevContent().avatar_url && !ev.getContent().avatar_url) {
|
} else if (!prevContent.displayname && content.displayname) {
|
||||||
return _t('%(senderName)s removed their profile picture.', {senderName: senderName});
|
return _t('%(senderName)s set their display name to %(displayName)s.', {
|
||||||
} else if (ev.getPrevContent().avatar_url && ev.getContent().avatar_url && ev.getPrevContent().avatar_url != ev.getContent().avatar_url) {
|
senderName,
|
||||||
return _t('%(senderName)s changed their profile picture.', {senderName: senderName});
|
displayName: content.displayname,
|
||||||
} else if (!ev.getPrevContent().avatar_url && ev.getContent().avatar_url) {
|
});
|
||||||
return _t('%(senderName)s set a profile picture.', {senderName: senderName});
|
} else if (prevContent.displayname && !content.displayname) {
|
||||||
|
return _t('%(senderName)s removed their display name (%(oldDisplayName)s).', {
|
||||||
|
senderName,
|
||||||
|
oldDisplayName: prevContent.displayname,
|
||||||
|
});
|
||||||
|
} else if (prevContent.avatar_url && !content.avatar_url) {
|
||||||
|
return _t('%(senderName)s removed their profile picture.', {senderName});
|
||||||
|
} else if (prevContent.avatar_url && content.avatar_url &&
|
||||||
|
prevContent.avatar_url !== content.avatar_url) {
|
||||||
|
return _t('%(senderName)s changed their profile picture.', {senderName});
|
||||||
|
} else if (!prevContent.avatar_url && content.avatar_url) {
|
||||||
|
return _t('%(senderName)s set a profile picture.', {senderName});
|
||||||
} else {
|
} else {
|
||||||
// suppress null rejoins
|
// suppress null rejoins
|
||||||
return '';
|
return '';
|
||||||
|
@ -71,73 +82,69 @@ function textForMemberEvent(ev) {
|
||||||
if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
|
if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
|
||||||
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
|
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
|
||||||
return _t('VoIP conference started.');
|
return _t('VoIP conference started.');
|
||||||
}
|
} else {
|
||||||
else {
|
return _t('%(targetName)s joined the room.', {targetName});
|
||||||
return _t('%(targetName)s joined the room.', {targetName: targetName});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'leave':
|
case 'leave':
|
||||||
if (ev.getSender() === ev.getStateKey()) {
|
if (ev.getSender() === ev.getStateKey()) {
|
||||||
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
|
if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
|
||||||
return _t('VoIP conference finished.');
|
return _t('VoIP conference finished.');
|
||||||
|
} else if (prevContent.membership === "invite") {
|
||||||
|
return _t('%(targetName)s rejected the invitation.', {targetName});
|
||||||
|
} else {
|
||||||
|
return _t('%(targetName)s left the room.', {targetName});
|
||||||
}
|
}
|
||||||
else if (ev.getPrevContent().membership === "invite") {
|
} else if (prevContent.membership === "ban") {
|
||||||
return _t('%(targetName)s rejected the invitation.', {targetName: targetName});
|
return _t('%(senderName)s unbanned %(targetName)s.', {senderName, targetName});
|
||||||
}
|
} else if (prevContent.membership === "join") {
|
||||||
else {
|
return _t('%(senderName)s kicked %(targetName)s.', {senderName, targetName}) + ' ' + reason;
|
||||||
return _t('%(targetName)s left the room.', {targetName: targetName});
|
} else if (prevContent.membership === "invite") {
|
||||||
}
|
return _t('%(senderName)s withdrew %(targetName)s\'s invitation.', {
|
||||||
}
|
senderName,
|
||||||
else if (ev.getPrevContent().membership === "ban") {
|
targetName,
|
||||||
return _t('%(senderName)s unbanned %(targetName)s.', {senderName: senderName, targetName: targetName});
|
}) + ' ' + reason;
|
||||||
}
|
} else {
|
||||||
else if (ev.getPrevContent().membership === "join") {
|
return _t('%(targetName)s left the room.', {targetName});
|
||||||
return _t(
|
|
||||||
'%(senderName)s kicked %(targetName)s.',
|
|
||||||
{senderName: senderName, targetName: targetName}
|
|
||||||
) + ' ' + reason;
|
|
||||||
}
|
|
||||||
else if (ev.getPrevContent().membership === "invite") {
|
|
||||||
return _t(
|
|
||||||
'%(senderName)s withdrew %(targetName)s\'s invitation.',
|
|
||||||
{senderName: senderName, targetName: targetName}
|
|
||||||
) + ' ' + reason;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return _t('%(targetName)s left the room.', {targetName: targetName});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForTopicEvent(ev) {
|
function textForTopicEvent(ev) {
|
||||||
var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
||||||
return _t('%(senderDisplayName)s changed the topic to "%(topic)s".', {senderDisplayName: senderDisplayName, topic: ev.getContent().topic});
|
return _t('%(senderDisplayName)s changed the topic to "%(topic)s".', {
|
||||||
|
senderDisplayName,
|
||||||
|
topic: ev.getContent().topic,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForRoomNameEvent(ev) {
|
function textForRoomNameEvent(ev) {
|
||||||
var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
||||||
|
|
||||||
if (!ev.getContent().name || ev.getContent().name.trim().length === 0) {
|
if (!ev.getContent().name || ev.getContent().name.trim().length === 0) {
|
||||||
return _t('%(senderDisplayName)s removed the room name.', {senderDisplayName: senderDisplayName});
|
return _t('%(senderDisplayName)s removed the room name.', {senderDisplayName});
|
||||||
}
|
}
|
||||||
return _t('%(senderDisplayName)s changed the room name to %(roomName)s.', {senderDisplayName: senderDisplayName, roomName: ev.getContent().name});
|
return _t('%(senderDisplayName)s changed the room name to %(roomName)s.', {
|
||||||
|
senderDisplayName,
|
||||||
|
roomName: ev.getContent().name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForMessageEvent(ev) {
|
function textForMessageEvent(ev) {
|
||||||
var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
|
||||||
var message = senderDisplayName + ': ' + ev.getContent().body;
|
let message = senderDisplayName + ': ' + ev.getContent().body;
|
||||||
if (ev.getContent().msgtype === "m.emote") {
|
if (ev.getContent().msgtype === "m.emote") {
|
||||||
message = "* " + senderDisplayName + " " + message;
|
message = "* " + senderDisplayName + " " + message;
|
||||||
} else if (ev.getContent().msgtype === "m.image") {
|
} else if (ev.getContent().msgtype === "m.image") {
|
||||||
message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName: senderDisplayName});
|
message = _t('%(senderDisplayName)s sent an image.', {senderDisplayName});
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForCallAnswerEvent(event) {
|
function textForCallAnswerEvent(event) {
|
||||||
var senderName = event.sender ? event.sender.name : _t('Someone');
|
const senderName = event.sender ? event.sender.name : _t('Someone');
|
||||||
var supported = MatrixClientPeg.get().supportsVoip() ? "" : _t('(not supported by this browser)');
|
const supported = MatrixClientPeg.get().supportsVoip() ? '' : _t('(not supported by this browser)');
|
||||||
return _t('%(senderName)s answered the call.', {senderName: senderName}) + ' ' + supported;
|
return _t('%(senderName)s answered the call.', {senderName}) + ' ' + supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForCallHangupEvent(event) {
|
function textForCallHangupEvent(event) {
|
||||||
|
@ -159,20 +166,23 @@ function textForCallHangupEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForCallInviteEvent(event) {
|
function textForCallInviteEvent(event) {
|
||||||
var senderName = event.sender ? event.sender.name : _t('Someone');
|
const senderName = event.sender ? event.sender.name : _t('Someone');
|
||||||
// FIXME: Find a better way to determine this from the event?
|
// FIXME: Find a better way to determine this from the event?
|
||||||
var type = "voice";
|
let callType = "voice";
|
||||||
if (event.getContent().offer && event.getContent().offer.sdp &&
|
if (event.getContent().offer && event.getContent().offer.sdp &&
|
||||||
event.getContent().offer.sdp.indexOf('m=video') !== -1) {
|
event.getContent().offer.sdp.indexOf('m=video') !== -1) {
|
||||||
type = "video";
|
callType = "video";
|
||||||
}
|
}
|
||||||
var supported = MatrixClientPeg.get().supportsVoip() ? "" : _t('(not supported by this browser)');
|
const supported = MatrixClientPeg.get().supportsVoip() ? "" : _t('(not supported by this browser)');
|
||||||
return _t('%(senderName)s placed a %(callType)s call.', {senderName: senderName, callType: type}) + ' ' + supported;
|
return _t('%(senderName)s placed a %(callType)s call.', {senderName, callType}) + ' ' + supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForThreePidInviteEvent(event) {
|
function textForThreePidInviteEvent(event) {
|
||||||
var senderName = event.sender ? event.sender.name : event.getSender();
|
const senderName = event.sender ? event.sender.name : event.getSender();
|
||||||
return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', {senderName: senderName, targetDisplayName: event.getContent().display_name});
|
return _t('%(senderName)s sent an invitation to %(targetDisplayName)s to join the room.', {
|
||||||
|
senderName,
|
||||||
|
targetDisplayName: event.getContent().display_name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForHistoryVisibilityEvent(event) {
|
function textForHistoryVisibilityEvent(event) {
|
||||||
|
@ -197,8 +207,11 @@ function textForHistoryVisibilityEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function textForEncryptionEvent(event) {
|
function textForEncryptionEvent(event) {
|
||||||
var senderName = event.sender ? event.sender.name : event.getSender();
|
const senderName = event.sender ? event.sender.name : event.getSender();
|
||||||
return _t('%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).', {senderName: senderName, algorithm: event.getContent().algorithm});
|
return _t('%(senderName)s turned on end-to-end encryption (algorithm %(algorithm)s).', {
|
||||||
|
senderName,
|
||||||
|
algorithm: event.getContent().algorithm,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently will only display a change if a user's power level is changed
|
// Currently will only display a change if a user's power level is changed
|
||||||
|
@ -209,18 +222,18 @@ function textForPowerEvent(event) {
|
||||||
}
|
}
|
||||||
const userDefault = event.getContent().users_default || 0;
|
const userDefault = event.getContent().users_default || 0;
|
||||||
// Construct set of userIds
|
// Construct set of userIds
|
||||||
let users = [];
|
const users = [];
|
||||||
Object.keys(event.getContent().users).forEach(
|
Object.keys(event.getContent().users).forEach(
|
||||||
(userId) => {
|
(userId) => {
|
||||||
if (users.indexOf(userId) === -1) users.push(userId);
|
if (users.indexOf(userId) === -1) users.push(userId);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
Object.keys(event.getPrevContent().users).forEach(
|
Object.keys(event.getPrevContent().users).forEach(
|
||||||
(userId) => {
|
(userId) => {
|
||||||
if (users.indexOf(userId) === -1) users.push(userId);
|
if (users.indexOf(userId) === -1) users.push(userId);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
let diff = [];
|
const diff = [];
|
||||||
// XXX: This is also surely broken for i18n
|
// XXX: This is also surely broken for i18n
|
||||||
users.forEach((userId) => {
|
users.forEach((userId) => {
|
||||||
// Previous power level
|
// Previous power level
|
||||||
|
@ -229,11 +242,11 @@ function textForPowerEvent(event) {
|
||||||
const to = event.getContent().users[userId];
|
const to = event.getContent().users[userId];
|
||||||
if (to !== from) {
|
if (to !== from) {
|
||||||
diff.push(
|
diff.push(
|
||||||
_t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', {
|
_t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
fromPowerLevel: Roles.textualPowerLevel(from, userDefault),
|
fromPowerLevel: Roles.textualPowerLevel(from, userDefault),
|
||||||
toPowerLevel: Roles.textualPowerLevel(to, userDefault)
|
toPowerLevel: Roles.textualPowerLevel(to, userDefault),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -276,14 +289,14 @@ function textForWidgetEvent(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var handlers = {
|
const handlers = {
|
||||||
'm.room.message': textForMessageEvent,
|
'm.room.message': textForMessageEvent,
|
||||||
'm.room.name': textForRoomNameEvent,
|
'm.room.name': textForRoomNameEvent,
|
||||||
'm.room.topic': textForTopicEvent,
|
'm.room.topic': textForTopicEvent,
|
||||||
'm.room.member': textForMemberEvent,
|
'm.room.member': textForMemberEvent,
|
||||||
'm.call.invite': textForCallInviteEvent,
|
'm.call.invite': textForCallInviteEvent,
|
||||||
'm.call.answer': textForCallAnswerEvent,
|
'm.call.answer': textForCallAnswerEvent,
|
||||||
'm.call.hangup': textForCallHangupEvent,
|
'm.call.hangup': textForCallHangupEvent,
|
||||||
'm.room.third_party_invite': textForThreePidInviteEvent,
|
'm.room.third_party_invite': textForThreePidInviteEvent,
|
||||||
'm.room.history_visibility': textForHistoryVisibilityEvent,
|
'm.room.history_visibility': textForHistoryVisibilityEvent,
|
||||||
'm.room.encryption': textForEncryptionEvent,
|
'm.room.encryption': textForEncryptionEvent,
|
||||||
|
@ -294,8 +307,8 @@ var handlers = {
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
textForEvent: function(ev) {
|
textForEvent: function(ev) {
|
||||||
var hdlr = handlers[ev.getType()];
|
const hdlr = handlers[ev.getType()];
|
||||||
if (!hdlr) return "";
|
if (!hdlr) return '';
|
||||||
return hdlr(ev);
|
return hdlr(ev);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,6 +27,8 @@ import AccessibleButton from '../views/elements/AccessibleButton';
|
||||||
import Modal from '../../Modal';
|
import Modal from '../../Modal';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
|
import GroupSummaryStore from '../../stores/GroupSummaryStore';
|
||||||
|
|
||||||
const RoomSummaryType = PropTypes.shape({
|
const RoomSummaryType = PropTypes.shape({
|
||||||
room_id: PropTypes.string.isRequired,
|
room_id: PropTypes.string.isRequired,
|
||||||
profile: PropTypes.shape({
|
profile: PropTypes.shape({
|
||||||
|
@ -76,8 +78,8 @@ const CategoryRoomList = React.createClass({
|
||||||
if (!success) return;
|
if (!success) return;
|
||||||
const errorList = [];
|
const errorList = [];
|
||||||
Promise.all(addrs.map((addr) => {
|
Promise.all(addrs.map((addr) => {
|
||||||
return MatrixClientPeg.get()
|
return this.context.groupSummaryStore
|
||||||
.addRoomToGroupSummary(this.props.groupId, addr.address)
|
.addRoomToGroupSummary(addr.address)
|
||||||
.catch(() => { errorList.push(addr.address); })
|
.catch(() => { errorList.push(addr.address); })
|
||||||
.reflect();
|
.reflect();
|
||||||
})).then(() => {
|
})).then(() => {
|
||||||
|
@ -153,8 +155,7 @@ const FeaturedRoom = React.createClass({
|
||||||
onDeleteClicked: function(e) {
|
onDeleteClicked: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
MatrixClientPeg.get().removeRoomFromGroupSummary(
|
this.context.groupSummaryStore.removeRoomFromGroupSummary(
|
||||||
this.props.groupId,
|
|
||||||
this.props.summaryInfo.room_id,
|
this.props.summaryInfo.room_id,
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
console.error('Error whilst removing room from group summary', err);
|
console.error('Error whilst removing room from group summary', err);
|
||||||
|
@ -242,8 +243,8 @@ const RoleUserList = React.createClass({
|
||||||
if (!success) return;
|
if (!success) return;
|
||||||
const errorList = [];
|
const errorList = [];
|
||||||
Promise.all(addrs.map((addr) => {
|
Promise.all(addrs.map((addr) => {
|
||||||
return MatrixClientPeg.get()
|
return this.context.groupSummaryStore
|
||||||
.addUserToGroupSummary(this.props.groupId, addr.address)
|
.addUserToGroupSummary(addr.address)
|
||||||
.catch(() => { errorList.push(addr.address); })
|
.catch(() => { errorList.push(addr.address); })
|
||||||
.reflect();
|
.reflect();
|
||||||
})).then(() => {
|
})).then(() => {
|
||||||
|
@ -317,8 +318,7 @@ const FeaturedUser = React.createClass({
|
||||||
onDeleteClicked: function(e) {
|
onDeleteClicked: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
MatrixClientPeg.get().removeUserFromGroupSummary(
|
this.context.groupSummaryStore.removeUserFromGroupSummary(
|
||||||
this.props.groupId,
|
|
||||||
this.props.summaryInfo.user_id,
|
this.props.summaryInfo.user_id,
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
console.error('Error whilst removing user from group summary', err);
|
console.error('Error whilst removing user from group summary', err);
|
||||||
|
@ -364,6 +364,15 @@ const FeaturedUser = React.createClass({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const GroupSummaryContext = {
|
||||||
|
groupSummaryStore: React.PropTypes.instanceOf(GroupSummaryStore).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
CategoryRoomList.contextTypes = GroupSummaryContext;
|
||||||
|
FeaturedRoom.contextTypes = GroupSummaryContext;
|
||||||
|
RoleUserList.contextTypes = GroupSummaryContext;
|
||||||
|
FeaturedUser.contextTypes = GroupSummaryContext;
|
||||||
|
|
||||||
export default React.createClass({
|
export default React.createClass({
|
||||||
displayName: 'GroupView',
|
displayName: 'GroupView',
|
||||||
|
|
||||||
|
@ -371,6 +380,16 @@ export default React.createClass({
|
||||||
groupId: PropTypes.string.isRequired,
|
groupId: PropTypes.string.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
childContextTypes: {
|
||||||
|
groupSummaryStore: React.PropTypes.instanceOf(GroupSummaryStore),
|
||||||
|
},
|
||||||
|
|
||||||
|
getChildContext: function() {
|
||||||
|
return {
|
||||||
|
groupSummaryStore: this._groupSummaryStore,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
summary: null,
|
summary: null,
|
||||||
|
@ -379,18 +398,20 @@ export default React.createClass({
|
||||||
saving: false,
|
saving: false,
|
||||||
uploadingAvatar: false,
|
uploadingAvatar: false,
|
||||||
membershipBusy: false,
|
membershipBusy: false,
|
||||||
|
publicityBusy: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
this._changeAvatarComponent = null;
|
this._changeAvatarComponent = null;
|
||||||
this._loadGroupFromServer(this.props.groupId);
|
this._initGroupSummaryStore(this.props.groupId);
|
||||||
|
|
||||||
MatrixClientPeg.get().on("Group.myMembership", this._onGroupMyMembership);
|
MatrixClientPeg.get().on("Group.myMembership", this._onGroupMyMembership);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership);
|
MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership);
|
||||||
|
this._groupSummaryStore.removeAllListeners();
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillReceiveProps: function(newProps) {
|
componentWillReceiveProps: function(newProps) {
|
||||||
|
@ -399,7 +420,7 @@ export default React.createClass({
|
||||||
summary: null,
|
summary: null,
|
||||||
error: null,
|
error: null,
|
||||||
}, () => {
|
}, () => {
|
||||||
this._loadGroupFromServer(newProps.groupId);
|
this._initGroupSummaryStore(newProps.groupId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -410,13 +431,17 @@ export default React.createClass({
|
||||||
this.setState({membershipBusy: false});
|
this.setState({membershipBusy: false});
|
||||||
},
|
},
|
||||||
|
|
||||||
_loadGroupFromServer: function(groupId) {
|
_initGroupSummaryStore: function(groupId) {
|
||||||
MatrixClientPeg.get().getGroupSummary(groupId).done((res) => {
|
this._groupSummaryStore = new GroupSummaryStore(
|
||||||
|
MatrixClientPeg.get(), this.props.groupId,
|
||||||
|
);
|
||||||
|
this._groupSummaryStore.on('update', () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
summary: res,
|
summary: this._groupSummaryStore.getSummary(),
|
||||||
error: null,
|
error: null,
|
||||||
});
|
});
|
||||||
}, (err) => {
|
});
|
||||||
|
this._groupSummaryStore.on('error', (err) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
summary: null,
|
summary: null,
|
||||||
error: err,
|
error: err,
|
||||||
|
@ -493,7 +518,7 @@ export default React.createClass({
|
||||||
editing: false,
|
editing: false,
|
||||||
summary: null,
|
summary: null,
|
||||||
});
|
});
|
||||||
this._loadGroupFromServer(this.props.groupId);
|
this._initGroupSummaryStore(this.props.groupId);
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
saving: false,
|
saving: false,
|
||||||
|
@ -560,7 +585,26 @@ export default React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_getFeaturedRoomsNode() {
|
_onPubliciseOffClick: function() {
|
||||||
|
this._setPublicity(false);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onPubliciseOnClick: function() {
|
||||||
|
this._setPublicity(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_setPublicity: function(publicity) {
|
||||||
|
this.setState({
|
||||||
|
publicityBusy: true,
|
||||||
|
});
|
||||||
|
this._groupSummaryStore.setGroupPublicity(publicity).then(() => {
|
||||||
|
this.setState({
|
||||||
|
publicityBusy: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_getFeaturedRoomsNode: function() {
|
||||||
const summary = this.state.summary;
|
const summary = this.state.summary;
|
||||||
|
|
||||||
const defaultCategoryRooms = [];
|
const defaultCategoryRooms = [];
|
||||||
|
@ -601,7 +645,7 @@ export default React.createClass({
|
||||||
</div>;
|
</div>;
|
||||||
},
|
},
|
||||||
|
|
||||||
_getFeaturedUsersNode() {
|
_getFeaturedUsersNode: function() {
|
||||||
const summary = this.state.summary;
|
const summary = this.state.summary;
|
||||||
|
|
||||||
const noRoleUsers = [];
|
const noRoleUsers = [];
|
||||||
|
@ -643,12 +687,12 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_getMembershipSection: function() {
|
_getMembershipSection: function() {
|
||||||
|
const Spinner = sdk.getComponent("elements.Spinner");
|
||||||
|
|
||||||
const group = MatrixClientPeg.get().getGroup(this.props.groupId);
|
const group = MatrixClientPeg.get().getGroup(this.props.groupId);
|
||||||
if (!group) return null;
|
if (!group) return null;
|
||||||
|
|
||||||
if (group.myMembership === 'invite') {
|
if (group.myMembership === 'invite') {
|
||||||
const Spinner = sdk.getComponent("elements.Spinner");
|
|
||||||
|
|
||||||
if (this.state.membershipBusy) {
|
if (this.state.membershipBusy) {
|
||||||
return <div className="mx_GroupView_membershipSection">
|
return <div className="mx_GroupView_membershipSection">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
|
@ -677,17 +721,57 @@ export default React.createClass({
|
||||||
if (this.state.summary.user && this.state.summary.user.is_privileged) {
|
if (this.state.summary.user && this.state.summary.user.is_privileged) {
|
||||||
youAreAMemberText = _t("You are an administrator of this group");
|
youAreAMemberText = _t("You are an administrator of this group");
|
||||||
}
|
}
|
||||||
return <div className="mx_GroupView_membershipSection mx_GroupView_membershipSection_joined">
|
|
||||||
<div className="mx_GroupView_membershipSection_description">
|
let publicisedButton;
|
||||||
{youAreAMemberText}
|
if (this.state.publicityBusy) {
|
||||||
</div>
|
publicisedButton = <Spinner />;
|
||||||
<div className="mx_GroupView_membership_buttonContainer">
|
}
|
||||||
<AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
|
|
||||||
onClick={this._onLeaveClick}
|
let publicisedSection;
|
||||||
|
if (this.state.summary.user && this.state.summary.user.is_publicised) {
|
||||||
|
if (!this.state.publicityBusy) {
|
||||||
|
publicisedButton = <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
|
||||||
|
onClick={this._onPubliciseOffClick}
|
||||||
|
>
|
||||||
|
{_t("Unpublish")}
|
||||||
|
</AccessibleButton>;
|
||||||
|
}
|
||||||
|
publicisedSection = <div className="mx_GroupView_membershipSubSection">
|
||||||
|
{_t("This group is published on your profile")}
|
||||||
|
<div className="mx_GroupView_membership_buttonContainer">
|
||||||
|
{publicisedButton}
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
} else {
|
||||||
|
if (!this.state.publicityBusy) {
|
||||||
|
publicisedButton = <AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
|
||||||
|
onClick={this._onPubliciseOnClick}
|
||||||
>
|
>
|
||||||
{_t("Leave")}
|
{_t("Publish")}
|
||||||
</AccessibleButton>
|
</AccessibleButton>;
|
||||||
|
}
|
||||||
|
publicisedSection = <div className="mx_GroupView_membershipSubSection">
|
||||||
|
{_t("This group is not published on your profile")}
|
||||||
|
<div className="mx_GroupView_membership_buttonContainer">
|
||||||
|
{publicisedButton}
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className="mx_GroupView_membershipSection mx_GroupView_membershipSection_joined">
|
||||||
|
<div className="mx_GroupView_membershipSubSection">
|
||||||
|
<div className="mx_GroupView_membershipSection_description">
|
||||||
|
{youAreAMemberText}
|
||||||
|
</div>
|
||||||
|
<div className="mx_GroupView_membership_buttonContainer">
|
||||||
|
<AccessibleButton className="mx_GroupView_textButton mx_RoomHeader_textButton"
|
||||||
|
onClick={this._onLeaveClick}
|
||||||
|
>
|
||||||
|
{_t("Leave")}
|
||||||
|
</AccessibleButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{publicisedSection}
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ module.exports = React.createClass({
|
||||||
if (this.props.groupId) {
|
if (this.props.groupId) {
|
||||||
this._doNaiveGroupRoomSearch(query);
|
this._doNaiveGroupRoomSearch(query);
|
||||||
} else {
|
} else {
|
||||||
console.error('Room searching only implemented for groups');
|
this._doRoomSearch(query);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error('Unknown pickerType', this.props.pickerType);
|
console.error('Unknown pickerType', this.props.pickerType);
|
||||||
|
@ -248,7 +248,7 @@ module.exports = React.createClass({
|
||||||
results.push({
|
results.push({
|
||||||
room_id: r.room_id,
|
room_id: r.room_id,
|
||||||
avatar_url: r.avatar_url,
|
avatar_url: r.avatar_url,
|
||||||
name: r.name,
|
name: r.name || r.canonical_alias,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this._processResults(results, query);
|
this._processResults(results, query);
|
||||||
|
@ -264,6 +264,37 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_doRoomSearch: function(query) {
|
||||||
|
const lowerCaseQuery = query.toLowerCase();
|
||||||
|
const rooms = MatrixClientPeg.get().getRooms();
|
||||||
|
const results = [];
|
||||||
|
rooms.forEach((room) => {
|
||||||
|
const nameEvent = room.currentState.getStateEvents('m.room.name', '');
|
||||||
|
const topicEvent = room.currentState.getStateEvents('m.room.topic', '');
|
||||||
|
const name = nameEvent ? nameEvent.getContent().name : '';
|
||||||
|
const canonicalAlias = room.getCanonicalAlias();
|
||||||
|
const topic = topicEvent ? topicEvent.getContent().topic : '';
|
||||||
|
|
||||||
|
const nameMatch = (name || '').toLowerCase().includes(lowerCaseQuery);
|
||||||
|
const aliasMatch = (canonicalAlias || '').toLowerCase().includes(lowerCaseQuery);
|
||||||
|
const topicMatch = (topic || '').toLowerCase().includes(lowerCaseQuery);
|
||||||
|
if (!(nameMatch || topicMatch || aliasMatch)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const avatarEvent = room.currentState.getStateEvents('m.room.avatar', '');
|
||||||
|
const avatarUrl = avatarEvent ? avatarEvent.getContent().url : undefined;
|
||||||
|
results.push({
|
||||||
|
room_id: room.roomId,
|
||||||
|
avatar_url: avatarUrl,
|
||||||
|
name: name || canonicalAlias,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this._processResults(results, query);
|
||||||
|
this.setState({
|
||||||
|
busy: false,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
_doUserDirectorySearch: function(query) {
|
_doUserDirectorySearch: function(query) {
|
||||||
this.setState({
|
this.setState({
|
||||||
busy: true,
|
busy: true,
|
||||||
|
|
|
@ -19,6 +19,7 @@ limitations under the License.
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
|
import PlatformPeg from '../../../PlatformPeg';
|
||||||
import ScalarAuthClient from '../../../ScalarAuthClient';
|
import ScalarAuthClient from '../../../ScalarAuthClient';
|
||||||
import SdkConfig from '../../../SdkConfig';
|
import SdkConfig from '../../../SdkConfig';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
|
@ -127,6 +128,30 @@ export default React.createClass({
|
||||||
loading: false,
|
loading: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
window.addEventListener('message', this._onMessage, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener('message', this._onMessage);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onMessage(event) {
|
||||||
|
if (this.props.type !== 'jitsi') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!event.origin) {
|
||||||
|
event.origin = event.originalEvent.origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.state.widgetUrl.startsWith(event.origin)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.data.widgetAction === 'jitsi_iframe_loaded') {
|
||||||
|
const iframe = this.refs.appFrame.contentWindow
|
||||||
|
.document.querySelector('iframe[id^="jitsiConferenceFrame"]');
|
||||||
|
PlatformPeg.get().setupScreenSharingForIframe(iframe);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_canUserModify: function() {
|
_canUserModify: function() {
|
||||||
|
|
|
@ -29,6 +29,9 @@ const BULK_REQUEST_DEBOUNCE_MS = 200;
|
||||||
// If true, flair can function and we should keep sending requests for groups and avatars.
|
// If true, flair can function and we should keep sending requests for groups and avatars.
|
||||||
let groupSupport = true;
|
let groupSupport = true;
|
||||||
|
|
||||||
|
const USER_GROUPS_CACHE_BUST_MS = 1800000; // 30 mins
|
||||||
|
const GROUP_PROFILES_CACHE_BUST_MS = 1800000; // 30 mins
|
||||||
|
|
||||||
// TODO: Cache-busting based on time. (The server won't inform us of membership changes.)
|
// TODO: Cache-busting based on time. (The server won't inform us of membership changes.)
|
||||||
// This applies to userGroups and groupProfiles. We can provide a slightly better UX by
|
// This applies to userGroups and groupProfiles. We can provide a slightly better UX by
|
||||||
// cache-busting when the current user joins/leaves a group.
|
// cache-busting when the current user joins/leaves a group.
|
||||||
|
@ -69,7 +72,9 @@ function getPublicisedGroupsCached(matrixClient, userId) {
|
||||||
usersPending[userId].reject = reject;
|
usersPending[userId].reject = reject;
|
||||||
}).then((groups) => {
|
}).then((groups) => {
|
||||||
userGroups[userId] = groups;
|
userGroups[userId] = groups;
|
||||||
// TODO: Reset cache at this point
|
setTimeout(() => {
|
||||||
|
delete userGroups[userId];
|
||||||
|
}, USER_GROUPS_CACHE_BUST_MS);
|
||||||
return userGroups[userId];
|
return userGroups[userId];
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
throw err;
|
throw err;
|
||||||
|
@ -126,6 +131,9 @@ async function getGroupProfileCached(matrixClient, groupId) {
|
||||||
groupId,
|
groupId,
|
||||||
avatarUrl: profile.avatar_url,
|
avatarUrl: profile.avatar_url,
|
||||||
};
|
};
|
||||||
|
setTimeout(() => {
|
||||||
|
delete groupProfiles[groupId];
|
||||||
|
}, GROUP_PROFILES_CACHE_BUST_MS);
|
||||||
|
|
||||||
return groupProfiles[groupId];
|
return groupProfiles[groupId];
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,12 +152,21 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
const avatarUrl = this.props.matrixClient.mxcUrlToHttp(
|
||||||
const avatar = (
|
this.props.groupMember.avatarUrl,
|
||||||
<BaseAvatar name={this.props.groupMember.userId} width={36} height={36} />
|
36, 36, 'crop',
|
||||||
);
|
);
|
||||||
|
|
||||||
const groupMemberName = this.props.groupMember.userId;
|
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||||
|
const avatar = (
|
||||||
|
<BaseAvatar name={this.props.groupMember.userId} width={36} height={36}
|
||||||
|
url={avatarUrl}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const groupMemberName = (
|
||||||
|
this.props.groupMember.displayname || this.props.groupMember.userId
|
||||||
|
);
|
||||||
|
|
||||||
const EmojiText = sdk.getComponent('elements.EmojiText');
|
const EmojiText = sdk.getComponent('elements.EmojiText');
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -131,7 +131,7 @@ export default withMatrixClient(React.createClass({
|
||||||
|
|
||||||
const inputBox = (
|
const inputBox = (
|
||||||
<form autoComplete="off">
|
<form autoComplete="off">
|
||||||
<input className="mx_MemberList_query" id="mx_MemberList_query" type="text"
|
<input className="mx_GroupMemberList_query" id="mx_GroupMemberList_query" type="text"
|
||||||
onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
|
onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
|
||||||
placeholder={ _t('Filter group members') } />
|
placeholder={ _t('Filter group members') } />
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -48,11 +48,15 @@ export default withMatrixClient(React.createClass({
|
||||||
const EntityTile = sdk.getComponent('rooms.EntityTile');
|
const EntityTile = sdk.getComponent('rooms.EntityTile');
|
||||||
|
|
||||||
const name = this.props.member.displayname || this.props.member.userId;
|
const name = this.props.member.displayname || this.props.member.userId;
|
||||||
|
const avatarUrl = this.props.matrixClient.mxcUrlToHttp(
|
||||||
|
this.props.member.avatarUrl,
|
||||||
|
36, 36, 'crop',
|
||||||
|
);
|
||||||
|
|
||||||
const av = (
|
const av = (
|
||||||
<BaseAvatar name={this.props.member.userId}
|
<BaseAvatar name={this.props.member.userId}
|
||||||
width={36} height={36}
|
width={36} height={36}
|
||||||
url={this.props.matrixClient.mxcUrlToHttp(this.props.member.avatarUrl)}
|
url={avatarUrl}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
143
src/components/views/groups/GroupRoomList.js
Normal file
143
src/components/views/groups/GroupRoomList.js
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
import { _t } from '../../../languageHandler';
|
||||||
|
import sdk from '../../../index';
|
||||||
|
import { groupRoomFromApiObject } from '../../../groups';
|
||||||
|
import GeminiScrollbar from 'react-gemini-scrollbar';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {MatrixClient} from 'matrix-js-sdk';
|
||||||
|
|
||||||
|
const INITIAL_LOAD_NUM_ROOMS = 30;
|
||||||
|
|
||||||
|
export default React.createClass({
|
||||||
|
contextTypes: {
|
||||||
|
matrixClient: React.PropTypes.instanceOf(MatrixClient).isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
groupId: PropTypes.string.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
fetching: false,
|
||||||
|
rooms: null,
|
||||||
|
truncateAt: INITIAL_LOAD_NUM_ROOMS,
|
||||||
|
searchQuery: "",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillMount: function() {
|
||||||
|
this._unmounted = false;
|
||||||
|
this._fetchRooms();
|
||||||
|
},
|
||||||
|
|
||||||
|
_fetchRooms: function() {
|
||||||
|
this.setState({fetching: true});
|
||||||
|
this.context.matrixClient.getGroupRooms(this.props.groupId).then((result) => {
|
||||||
|
this.setState({
|
||||||
|
rooms: result.chunk.map((apiRoom) => {
|
||||||
|
return groupRoomFromApiObject(apiRoom);
|
||||||
|
}),
|
||||||
|
fetching: false,
|
||||||
|
});
|
||||||
|
}).catch((e) => {
|
||||||
|
this.setState({fetching: false});
|
||||||
|
console.error("Failed to get group room list: ", e);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_createOverflowTile: function(overflowCount, totalCount) {
|
||||||
|
// For now we'll pretend this is any entity. It should probably be a separate tile.
|
||||||
|
const EntityTile = sdk.getComponent("rooms.EntityTile");
|
||||||
|
const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
|
||||||
|
const text = _t("and %(count)s others...", { count: overflowCount });
|
||||||
|
return (
|
||||||
|
<EntityTile className="mx_EntityTile_ellipsis" avatarJsx={
|
||||||
|
<BaseAvatar url="img/ellipsis.svg" name="..." width={36} height={36} />
|
||||||
|
} name={text} presenceState="online" suppressOnHover={true}
|
||||||
|
onClick={this._showFullRoomList} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_showFullRoomList: function() {
|
||||||
|
this.setState({
|
||||||
|
truncateAt: -1,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onSearchQueryChanged: function(ev) {
|
||||||
|
this.setState({ searchQuery: ev.target.value });
|
||||||
|
},
|
||||||
|
|
||||||
|
makeGroupRoomTiles: function(query) {
|
||||||
|
const GroupRoomTile = sdk.getComponent("groups.GroupRoomTile");
|
||||||
|
query = (query || "").toLowerCase();
|
||||||
|
|
||||||
|
let roomList = this.state.rooms;
|
||||||
|
if (query) {
|
||||||
|
roomList = roomList.filter((room) => {
|
||||||
|
const matchesName = (room.name || "").toLowerCase().include(query);
|
||||||
|
const matchesAlias = (room.canonicalAlias || "").toLowerCase().includes(query);
|
||||||
|
return matchesName || matchesAlias;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
roomList = roomList.map((groupRoom, index) => {
|
||||||
|
return (
|
||||||
|
<GroupRoomTile
|
||||||
|
key={index}
|
||||||
|
groupId={this.props.groupId}
|
||||||
|
groupRoom={groupRoom} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return roomList;
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
if (this.state.fetching) {
|
||||||
|
const Spinner = sdk.getComponent("elements.Spinner");
|
||||||
|
return (<div className="mx_GroupRoomList">
|
||||||
|
<Spinner />
|
||||||
|
</div>);
|
||||||
|
} else if (this.state.rooms === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputBox = (
|
||||||
|
<form autoComplete="off">
|
||||||
|
<input className="mx_GroupRoomList_query" id="mx_GroupRoomList_query" type="text"
|
||||||
|
onChange={this.onSearchQueryChanged} value={this.state.searchQuery}
|
||||||
|
placeholder={ _t('Filter group rooms') } />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
|
||||||
|
const TruncatedList = sdk.getComponent("elements.TruncatedList");
|
||||||
|
return (
|
||||||
|
<div className="mx_GroupRoomList">
|
||||||
|
{ inputBox }
|
||||||
|
<GeminiScrollbar autoshow={true} className="mx_GroupRoomList_joined mx_GroupRoomList_outerWrapper">
|
||||||
|
<TruncatedList className="mx_GroupRoomList_wrapper" truncateAt={this.state.truncateAt}
|
||||||
|
createOverflowElement={this._createOverflowTile}>
|
||||||
|
{this.makeGroupRoomTiles(this.state.searchQuery)}
|
||||||
|
</TruncatedList>
|
||||||
|
</GeminiScrollbar>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
89
src/components/views/groups/GroupRoomTile.js
Normal file
89
src/components/views/groups/GroupRoomTile.js
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {MatrixClient} from 'matrix-js-sdk';
|
||||||
|
import { _t } from '../../../languageHandler';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import sdk from '../../../index';
|
||||||
|
import dis from '../../../dispatcher';
|
||||||
|
import { GroupRoomType } from '../../../groups';
|
||||||
|
|
||||||
|
const GroupRoomTile = React.createClass({
|
||||||
|
displayName: 'GroupRoomTile',
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
groupId: PropTypes.string.isRequired,
|
||||||
|
groupRoom: GroupRoomType.isRequired,
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialState: function() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
|
||||||
|
onClick: function(e) {
|
||||||
|
let roomId;
|
||||||
|
let roomAlias;
|
||||||
|
if (this.props.groupRoom.canonicalAlias) {
|
||||||
|
roomAlias = this.props.groupRoom.canonicalAlias;
|
||||||
|
} else {
|
||||||
|
roomId = this.props.groupRoom.roomId;
|
||||||
|
}
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
room_id: roomId,
|
||||||
|
room_alias: roomAlias,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
|
||||||
|
const name = this.props.groupRoom.name ||
|
||||||
|
this.props.groupRoom.canonicalAlias ||
|
||||||
|
_t("Unnamed Room");
|
||||||
|
const avatarUrl = this.context.matrixClient.mxcUrlToHttp(
|
||||||
|
this.props.groupRoom.avatarUrl,
|
||||||
|
36, 36, 'crop',
|
||||||
|
);
|
||||||
|
|
||||||
|
const av = (
|
||||||
|
<BaseAvatar name={name}
|
||||||
|
width={36} height={36}
|
||||||
|
url={avatarUrl}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AccessibleButton className="mx_GroupRoomTile" onClick={this.onClick}>
|
||||||
|
<div className="mx_GroupRoomTile_avatar">
|
||||||
|
{av}
|
||||||
|
</div>
|
||||||
|
<div className="mx_GroupRoomTile_name">
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
GroupRoomTile.contextTypes = {
|
||||||
|
matrixClient: React.PropTypes.instanceOf(MatrixClient).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default GroupRoomTile;
|
|
@ -18,12 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import classNames from 'classnames';
|
|
||||||
import Matrix from 'matrix-js-sdk';
|
|
||||||
import Promise from 'bluebird';
|
|
||||||
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
||||||
var Modal = require("../../../Modal");
|
|
||||||
var Entities = require("../../../Entities");
|
|
||||||
var sdk = require('../../../index');
|
var sdk = require('../../../index');
|
||||||
var GeminiScrollbar = require('react-gemini-scrollbar');
|
var GeminiScrollbar = require('react-gemini-scrollbar');
|
||||||
var rate_limited_func = require('../../../ratelimitedfunc');
|
var rate_limited_func = require('../../../ratelimitedfunc');
|
||||||
|
@ -31,30 +26,26 @@ var CallHandler = require("../../../CallHandler");
|
||||||
|
|
||||||
const INITIAL_LOAD_NUM_MEMBERS = 30;
|
const INITIAL_LOAD_NUM_MEMBERS = 30;
|
||||||
const INITIAL_LOAD_NUM_INVITED = 5;
|
const INITIAL_LOAD_NUM_INVITED = 5;
|
||||||
|
const SHOW_MORE_INCREMENT = 100;
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'MemberList',
|
displayName: 'MemberList',
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
const state = {
|
this.memberDict = this.getMemberDict();
|
||||||
members: [],
|
const members = this.roomMembers();
|
||||||
|
|
||||||
|
return {
|
||||||
|
members: members,
|
||||||
|
filteredJoinedMembers: this._filterMembers(members, 'join'),
|
||||||
|
filteredInvitedMembers: this._filterMembers(members, 'invite'),
|
||||||
|
|
||||||
// ideally we'd size this to the page height, but
|
// ideally we'd size this to the page height, but
|
||||||
// in practice I find that a little constraining
|
// in practice I find that a little constraining
|
||||||
truncateAtJoined: INITIAL_LOAD_NUM_MEMBERS,
|
truncateAtJoined: INITIAL_LOAD_NUM_MEMBERS,
|
||||||
truncateAtInvited: INITIAL_LOAD_NUM_INVITED,
|
truncateAtInvited: INITIAL_LOAD_NUM_INVITED,
|
||||||
searchQuery: "",
|
searchQuery: "",
|
||||||
};
|
};
|
||||||
if (!this.props.roomId) return state;
|
|
||||||
var cli = MatrixClientPeg.get();
|
|
||||||
var room = cli.getRoom(this.props.roomId);
|
|
||||||
if (!room) return state;
|
|
||||||
|
|
||||||
this.memberDict = this.getMemberDict();
|
|
||||||
|
|
||||||
state.members = this.roomMembers();
|
|
||||||
state.filteredJoinedMembers = this._filterMembers(state.members, 'join');
|
|
||||||
state.filteredInvitedMembers = this._filterMembers(state.members, 'invite');
|
|
||||||
return state;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
|
@ -207,11 +198,11 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_createOverflowTileJoined: function(overflowCount, totalCount) {
|
_createOverflowTileJoined: function(overflowCount, totalCount) {
|
||||||
return this._createOverflowTile(overflowCount, totalCount, this._showFullJoinedMemberList);
|
return this._createOverflowTile(overflowCount, totalCount, this._showMoreJoinedMemberList);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createOverflowTileInvited: function(overflowCount, totalCount) {
|
_createOverflowTileInvited: function(overflowCount, totalCount) {
|
||||||
return this._createOverflowTile(overflowCount, totalCount, this._showFullInvitedMemberList);
|
return this._createOverflowTile(overflowCount, totalCount, this._showMoreInvitedMemberList);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createOverflowTile: function(overflowCount, totalCount, onClick) {
|
_createOverflowTile: function(overflowCount, totalCount, onClick) {
|
||||||
|
@ -227,15 +218,15 @@ module.exports = React.createClass({
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
_showFullJoinedMemberList: function() {
|
_showMoreJoinedMemberList: function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
truncateAtJoined: -1
|
truncateAtJoined: this.state.truncateAtJoined + SHOW_MORE_INCREMENT,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_showFullInvitedMemberList: function() {
|
_showMoreInvitedMemberList: function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
truncateAtInvited: -1
|
truncateAtInvited: this.state.truncateAtInvited + SHOW_MORE_INCREMENT,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,14 @@ export const GroupMemberType = PropTypes.shape({
|
||||||
avatarUrl: PropTypes.string,
|
avatarUrl: PropTypes.string,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const GroupRoomType = PropTypes.shape({
|
||||||
|
name: PropTypes.string,
|
||||||
|
// TODO: API doesn't return this yet
|
||||||
|
// roomId: PropTypes.string.isRequired,
|
||||||
|
canonicalAlias: PropTypes.string,
|
||||||
|
avatarUrl: PropTypes.string,
|
||||||
|
});
|
||||||
|
|
||||||
export function groupMemberFromApiObject(apiObject) {
|
export function groupMemberFromApiObject(apiObject) {
|
||||||
return {
|
return {
|
||||||
userId: apiObject.user_id,
|
userId: apiObject.user_id,
|
||||||
|
@ -29,3 +37,11 @@ export function groupMemberFromApiObject(apiObject) {
|
||||||
avatarUrl: apiObject.avatar_url,
|
avatarUrl: apiObject.avatar_url,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function groupRoomFromApiObject(apiObject) {
|
||||||
|
return {
|
||||||
|
name: apiObject.name,
|
||||||
|
canonicalAlias: apiObject.canonical_alias,
|
||||||
|
avatarUrl: apiObject.avatar_url,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -846,6 +846,7 @@
|
||||||
"Robot check is currently unavailable on desktop - please use a <a>web browser</a>": "Robot check is currently unavailable on desktop - please use a <a>web browser</a>",
|
"Robot check is currently unavailable on desktop - please use a <a>web browser</a>": "Robot check is currently unavailable on desktop - please use a <a>web browser</a>",
|
||||||
"Description": "Description",
|
"Description": "Description",
|
||||||
"Filter group members": "Filter group members",
|
"Filter group members": "Filter group members",
|
||||||
|
"Filter group rooms": "Filter group rooms",
|
||||||
"Remove from group": "Remove from group",
|
"Remove from group": "Remove from group",
|
||||||
"Invite new group members": "Invite new group members",
|
"Invite new group members": "Invite new group members",
|
||||||
"Who would you like to add to this group?": "Who would you like to add to this group?",
|
"Who would you like to add to this group?": "Who would you like to add to this group?",
|
||||||
|
@ -876,11 +877,22 @@
|
||||||
"Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?",
|
"Which rooms would you like to add to this summary?": "Which rooms would you like to add to this summary?",
|
||||||
"Room name or alias": "Room name or alias",
|
"Room name or alias": "Room name or alias",
|
||||||
"You are an administrator of this group": "You are an administrator of this group",
|
"You are an administrator of this group": "You are an administrator of this group",
|
||||||
|
"Failed to add the following rooms to the summary of %(groupId)s:": "Failed to add the following rooms to the summary of %(groupId)s:",
|
||||||
"Failed to remove the room from the summary of %(groupId)s": "Failed to remove the room from the summary of %(groupId)s",
|
"Failed to remove the room from the summary of %(groupId)s": "Failed to remove the room from the summary of %(groupId)s",
|
||||||
"The room '%(roomName)' could not be removed from the summary.": "The room '%(roomName)' could not be removed from the summary.",
|
"The room '%(roomName)s' could not be removed from the summary.": "The room '%(roomName)s' could not be removed from the summary.",
|
||||||
"Failed to remove a user from the summary of %(groupId)s": "Failed to remove a user from the summary of %(groupId)s",
|
"Failed to remove a user from the summary of %(groupId)s": "Failed to remove a user from the summary of %(groupId)s",
|
||||||
"The user '%(displayName)s' could not be removed from the summary.": "The user '%(displayName)s' could not be removed from the summary.",
|
"The user '%(displayName)s' could not be removed from the summary.": "The user '%(displayName)s' could not be removed from the summary.",
|
||||||
"Light theme": "Light theme",
|
"Light theme": "Light theme",
|
||||||
"Dark theme": "Dark theme",
|
"Dark theme": "Dark theme",
|
||||||
"Unknown": "Unknown"
|
"Unknown": "Unknown",
|
||||||
|
"Failed to add the following rooms to the summary of %(groupId)s:": "Failed to add the following rooms to the summary of %(groupId)s:",
|
||||||
|
"The room '%(roomName)s' could not be removed from the summary.": "The room '%(roomName)s' could not be removed from the summary.",
|
||||||
|
"Add rooms to the group": "Add rooms to the group",
|
||||||
|
"Which rooms would you like to add to this group?": "Which rooms would you like to add to this group?",
|
||||||
|
"Add to group": "Add to group",
|
||||||
|
"Failed to add the following rooms to %(groupId)s:": "Failed to add the following rooms to %(groupId)s:",
|
||||||
|
"Unpublish": "Unpublish",
|
||||||
|
"This group is published on your profile": "This group is published on your profile",
|
||||||
|
"Publish": "Publish",
|
||||||
|
"This group is not published on your profile": "This group is not published on your profile"
|
||||||
}
|
}
|
||||||
|
|
77
src/stores/GroupSummaryStore.js
Normal file
77
src/stores/GroupSummaryStore.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the group summary for a room and provides an API to change it
|
||||||
|
*/
|
||||||
|
export default class GroupSummaryStore extends EventEmitter {
|
||||||
|
constructor(matrixClient, groupId) {
|
||||||
|
super();
|
||||||
|
this._groupId = groupId;
|
||||||
|
this._matrixClient = matrixClient;
|
||||||
|
this._summary = {};
|
||||||
|
this._fetchSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
_fetchSummary() {
|
||||||
|
this._matrixClient.getGroupSummary(this._groupId).then((resp) => {
|
||||||
|
this._summary = resp;
|
||||||
|
this._notifyListeners();
|
||||||
|
}).catch((err) => {
|
||||||
|
this.emit('error', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_notifyListeners() {
|
||||||
|
this.emit('update');
|
||||||
|
}
|
||||||
|
|
||||||
|
getSummary() {
|
||||||
|
return this._summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
addRoomToGroupSummary(roomId, categoryId) {
|
||||||
|
return this._matrixClient
|
||||||
|
.addRoomToGroupSummary(this._groupId, roomId, categoryId)
|
||||||
|
.then(this._fetchSummary.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
addUserToGroupSummary(userId, roleId) {
|
||||||
|
return this._matrixClient
|
||||||
|
.addUserToGroupSummary(this._groupId, userId, roleId)
|
||||||
|
.then(this._fetchSummary.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeRoomFromGroupSummary(roomId) {
|
||||||
|
return this._matrixClient
|
||||||
|
.removeRoomFromGroupSummary(this._groupId, roomId)
|
||||||
|
.then(this._fetchSummary.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeUserFromGroupSummary(userId) {
|
||||||
|
return this._matrixClient
|
||||||
|
.removeUserFromGroupSummary(this._groupId, userId)
|
||||||
|
.then(this._fetchSummary.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
setGroupPublicity(isPublished) {
|
||||||
|
return this._matrixClient
|
||||||
|
.setGroupPublicity(this._groupId, isPublished)
|
||||||
|
.then(this._fetchSummary.bind(this));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue