Merge branch 'develop' into departify
This commit is contained in:
commit
95b2392104
17 changed files with 202 additions and 60 deletions
|
@ -21,6 +21,8 @@ import Modal from './Modal';
|
||||||
import { getAddressType } from './UserAddress';
|
import { getAddressType } from './UserAddress';
|
||||||
import createRoom from './createRoom';
|
import createRoom from './createRoom';
|
||||||
import sdk from './';
|
import sdk from './';
|
||||||
|
import dis from './dispatcher';
|
||||||
|
import DMRoomMap from './utils/DMRoomMap';
|
||||||
import { _t } from './languageHandler';
|
import { _t } from './languageHandler';
|
||||||
|
|
||||||
export function inviteToRoom(roomId, addr) {
|
export function inviteToRoom(roomId, addr) {
|
||||||
|
@ -79,15 +81,40 @@ function _onStartChatFinished(shouldInvite, addrs) {
|
||||||
const addrTexts = addrs.map((addr) => addr.address);
|
const addrTexts = addrs.map((addr) => addr.address);
|
||||||
|
|
||||||
if (_isDmChat(addrTexts)) {
|
if (_isDmChat(addrTexts)) {
|
||||||
// Start a new DM chat
|
const rooms = _getDirectMessageRooms(addrTexts[0]);
|
||||||
createRoom({dmUserId: addrTexts[0]}).catch((err) => {
|
if (rooms.length > 0) {
|
||||||
console.error(err.stack);
|
// A Direct Message room already exists for this user, so select a
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
// room from a list that is similar to the one in MemberInfo panel
|
||||||
Modal.createTrackedDialog('Failed to invite user', '', ErrorDialog, {
|
const ChatCreateOrReuseDialog = sdk.getComponent(
|
||||||
title: _t("Failed to invite user"),
|
"views.dialogs.ChatCreateOrReuseDialog",
|
||||||
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
);
|
||||||
|
const close = Modal.createTrackedDialog('Create or Reuse', '', ChatCreateOrReuseDialog, {
|
||||||
|
userId: addrTexts[0],
|
||||||
|
onNewDMClick: () => {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'start_chat',
|
||||||
|
user_id: addrTexts[0],
|
||||||
|
});
|
||||||
|
close(true);
|
||||||
|
},
|
||||||
|
onExistingRoomSelected: (roomId) => {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
room_id: roomId,
|
||||||
|
});
|
||||||
|
close(true);
|
||||||
|
},
|
||||||
|
}).close;
|
||||||
|
} else {
|
||||||
|
// Start a new DM chat
|
||||||
|
createRoom({dmUserId: addrTexts[0]}).catch((err) => {
|
||||||
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createTrackedDialog('Failed to invite user', '', ErrorDialog, {
|
||||||
|
title: _t("Failed to invite user"),
|
||||||
|
description: ((err && err.message) ? err.message : _t("Operation failed")),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
} else {
|
} else {
|
||||||
// Start multi user chat
|
// Start multi user chat
|
||||||
let room;
|
let room;
|
||||||
|
@ -153,3 +180,19 @@ function _showAnyInviteErrors(addrs, room) {
|
||||||
return addrs;
|
return addrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _getDirectMessageRooms(addr) {
|
||||||
|
const dmRoomMap = new DMRoomMap(MatrixClientPeg.get());
|
||||||
|
const dmRooms = dmRoomMap.getDMRoomsForUserId(addr);
|
||||||
|
const rooms = [];
|
||||||
|
dmRooms.forEach((dmRoom) => {
|
||||||
|
const room = MatrixClientPeg.get().getRoom(dmRoom);
|
||||||
|
if (room) {
|
||||||
|
const me = room.getMember(MatrixClientPeg.get().credentials.userId);
|
||||||
|
if (me.membership == 'join') {
|
||||||
|
rooms.push(room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -447,7 +447,7 @@ export default React.createClass({
|
||||||
|
|
||||||
_initGroupStore: function(groupId) {
|
_initGroupStore: function(groupId) {
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(MatrixClientPeg.get(), groupId);
|
this._groupStore = GroupStoreCache.getGroupStore(MatrixClientPeg.get(), groupId);
|
||||||
this._groupStore.on('update', () => {
|
this._groupStore.registerListener(() => {
|
||||||
const summary = this._groupStore.getSummary();
|
const summary = this._groupStore.getSummary();
|
||||||
if (summary.profile) {
|
if (summary.profile) {
|
||||||
// Default profile fields should be "" for later sending to the server (which
|
// Default profile fields should be "" for later sending to the server (which
|
||||||
|
@ -464,7 +464,6 @@ export default React.createClass({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this._groupStore.on('error', (err) => {
|
this._groupStore.on('error', (err) => {
|
||||||
console.error(err);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
summary: null,
|
summary: null,
|
||||||
error: err,
|
error: err,
|
||||||
|
@ -964,13 +963,15 @@ export default React.createClass({
|
||||||
</AccessibleButton>,
|
</AccessibleButton>,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
rightButtons.push(
|
if (summary.user && summary.user.membership === 'join') {
|
||||||
<AccessibleButton className="mx_GroupHeader_button"
|
rightButtons.push(
|
||||||
onClick={this._onEditClick} title={_t("Community Settings")} key="_editButton"
|
<AccessibleButton className="mx_GroupHeader_button"
|
||||||
>
|
onClick={this._onEditClick} title={_t("Community Settings")} key="_editButton"
|
||||||
<TintableSvg src="img/icons-settings-room.svg" width="16" height="16" />
|
>
|
||||||
</AccessibleButton>,
|
<TintableSvg src="img/icons-settings-room.svg" width="16" height="16" />
|
||||||
);
|
</AccessibleButton>,
|
||||||
|
);
|
||||||
|
}
|
||||||
if (this.props.collapsedRhs) {
|
if (this.props.collapsedRhs) {
|
||||||
rightButtons.push(
|
rightButtons.push(
|
||||||
<AccessibleButton className="mx_GroupHeader_button"
|
<AccessibleButton className="mx_GroupHeader_button"
|
||||||
|
|
|
@ -118,6 +118,10 @@ const SETTINGS_LABELS = [
|
||||||
id: 'TextualBody.disableBigEmoji',
|
id: 'TextualBody.disableBigEmoji',
|
||||||
label: _td('Disable big emoji in chat'),
|
label: _td('Disable big emoji in chat'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'VideoView.flipVideoHorizontally',
|
||||||
|
label: _td('Mirror local video feed'),
|
||||||
|
},
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
id: 'useFixedWidthFont',
|
id: 'useFixedWidthFont',
|
||||||
|
@ -1328,8 +1332,11 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
<div className="mx_UserSettings_avatarPicker">
|
<div className="mx_UserSettings_avatarPicker">
|
||||||
<div className="mx_UserSettings_avatarPicker_remove" onClick={this.onAvatarRemoveClick}>
|
<div className="mx_UserSettings_avatarPicker_remove" onClick={this.onAvatarRemoveClick}>
|
||||||
<img src="img/cancel.svg" width="15" height="15"
|
<img src="img/cancel.svg"
|
||||||
alt={_t("Remove avatar")} title={_t("Remove avatar")} />
|
width="15" height="15"
|
||||||
|
className="mx_filterFlipColor"
|
||||||
|
alt={_t("Remove avatar")}
|
||||||
|
title={_t("Remove avatar")} />
|
||||||
</div>
|
</div>
|
||||||
<div onClick={this.onAvatarPickerClick} className="mx_UserSettings_avatarPicker_imgContainer">
|
<div onClick={this.onAvatarPickerClick} className="mx_UserSettings_avatarPicker_imgContainer">
|
||||||
<ChangeAvatar ref="changeAvatar" initialAvatarUrl={avatarUrl}
|
<ChangeAvatar ref="changeAvatar" initialAvatarUrl={avatarUrl}
|
||||||
|
|
|
@ -302,7 +302,7 @@ module.exports = React.createClass({
|
||||||
} : {};
|
} : {};
|
||||||
|
|
||||||
return this._matrixClient.register(
|
return this._matrixClient.register(
|
||||||
this.state.formVals.username,
|
this.state.formVals.username.toLowerCase(),
|
||||||
this.state.formVals.password,
|
this.state.formVals.password,
|
||||||
undefined, // session id: included in the auth dict already
|
undefined, // session id: included in the auth dict already
|
||||||
auth,
|
auth,
|
||||||
|
|
|
@ -174,7 +174,7 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
<div className="mx_MemberInfo">
|
<div className="mx_MemberInfo">
|
||||||
<GeminiScrollbar autoshow={true}>
|
<GeminiScrollbar autoshow={true}>
|
||||||
<AccessibleButton className="mx_MemberInfo_cancel"onClick={this._onCancel}>
|
<AccessibleButton className="mx_MemberInfo_cancel"onClick={this._onCancel}>
|
||||||
<img src="img/cancel.svg" width="18" height="18" />
|
<img src="img/cancel.svg" width="18" height="18" className="mx_filterFlipColor" />
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<div className="mx_MemberInfo_avatar">
|
<div className="mx_MemberInfo_avatar">
|
||||||
{ avatar }
|
{ avatar }
|
||||||
|
|
|
@ -50,12 +50,9 @@ export default withMatrixClient(React.createClass({
|
||||||
|
|
||||||
_initGroupStore: function(groupId) {
|
_initGroupStore: function(groupId) {
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(this.context.matrixClient, groupId);
|
this._groupStore = GroupStoreCache.getGroupStore(this.context.matrixClient, groupId);
|
||||||
this._groupStore.on('update', () => {
|
this._groupStore.registerListener(() => {
|
||||||
this._fetchMembers();
|
this._fetchMembers();
|
||||||
});
|
});
|
||||||
this._groupStore.on('error', (err) => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_fetchMembers: function() {
|
_fetchMembers: function() {
|
||||||
|
|
|
@ -47,16 +47,14 @@ export default React.createClass({
|
||||||
|
|
||||||
_initGroupStore: function(groupId) {
|
_initGroupStore: function(groupId) {
|
||||||
this._groupStore = GroupStoreCache.getGroupStore(this.context.matrixClient, groupId);
|
this._groupStore = GroupStoreCache.getGroupStore(this.context.matrixClient, groupId);
|
||||||
this._groupStore.on('update', () => {
|
this._groupStore.registerListener(() => {
|
||||||
this._fetchRooms();
|
this._fetchRooms();
|
||||||
});
|
});
|
||||||
this._groupStore.on('error', (err) => {
|
this._groupStore.on('error', (err) => {
|
||||||
console.error('Error in group store (listened to by GroupRoomList)', err);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
rooms: null,
|
rooms: null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this._fetchRooms();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_fetchRooms: function() {
|
_fetchRooms: function() {
|
||||||
|
|
|
@ -120,8 +120,11 @@ const GroupRoomTile = React.createClass({
|
||||||
<div className="mx_GroupRoomTile_name">
|
<div className="mx_GroupRoomTile_name">
|
||||||
{ this.state.name }
|
{ this.state.name }
|
||||||
</div>
|
</div>
|
||||||
<AccessibleButton className="mx_GroupRoomTile_delete" onClick={this.onDeleteClick}>
|
<AccessibleButton className="mx_GroupRoomTile_delete"
|
||||||
<img src="img/cancel-small.svg" />
|
onClick={this.onDeleteClick}
|
||||||
|
tooltip={_t("Remove this room from the community")}
|
||||||
|
>
|
||||||
|
<img src="img/cancel.svg" width="15" height="15" className="mx_filterFlipColor" />
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
);
|
);
|
||||||
|
|
|
@ -25,7 +25,10 @@ module.exports = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
let tooltip = _t("Removed or unknown message type");
|
let tooltip = _t("Removed or unknown message type");
|
||||||
if (this.props.mxEvent.isRedacted()) {
|
if (this.props.mxEvent.isRedacted()) {
|
||||||
tooltip = _t("Message removed by %(userId)s", {userId: this.props.mxEvent.getSender()});
|
const redactedBecauseUserId = this.props.mxEvent.getUnsigned().redacted_because.sender;
|
||||||
|
tooltip = redactedBecauseUserId ?
|
||||||
|
_t("Message removed by %(userId)s", { userId: redactedBecauseUserId }) :
|
||||||
|
_t("Message removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = this.props.mxEvent.getContent().body;
|
const text = this.props.mxEvent.getContent().body;
|
||||||
|
|
|
@ -133,8 +133,9 @@ module.exports = React.createClass({
|
||||||
{ p["og:description"] }
|
{ p["og:description"] }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<img className="mx_LinkPreviewWidget_cancel" src="img/cancel.svg" width="18" height="18"
|
<img className="mx_LinkPreviewWidget_cancel mx_filterFlipColor"
|
||||||
onClick={this.props.onCancelClick} />
|
src="img/cancel.svg" width="18" height="18"
|
||||||
|
onClick={this.props.onCancelClick} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -39,6 +39,7 @@ import { findReadReceiptFromUserId } from '../../../utils/Receipt';
|
||||||
import withMatrixClient from '../../../wrappers/withMatrixClient';
|
import withMatrixClient from '../../../wrappers/withMatrixClient';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
import GeminiScrollbar from 'react-gemini-scrollbar';
|
import GeminiScrollbar from 'react-gemini-scrollbar';
|
||||||
|
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||||
|
|
||||||
|
|
||||||
module.exports = withMatrixClient(React.createClass({
|
module.exports = withMatrixClient(React.createClass({
|
||||||
|
@ -81,6 +82,7 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
cli.on("Room.receipt", this.onRoomReceipt);
|
cli.on("Room.receipt", this.onRoomReceipt);
|
||||||
cli.on("RoomState.events", this.onRoomStateEvents);
|
cli.on("RoomState.events", this.onRoomStateEvents);
|
||||||
cli.on("RoomMember.name", this.onRoomMemberName);
|
cli.on("RoomMember.name", this.onRoomMemberName);
|
||||||
|
cli.on("RoomMember.membership", this.onRoomMemberMembership);
|
||||||
cli.on("accountData", this.onAccountData);
|
cli.on("accountData", this.onAccountData);
|
||||||
|
|
||||||
this._checkIgnoreState();
|
this._checkIgnoreState();
|
||||||
|
@ -107,6 +109,7 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
client.removeListener("Room.receipt", this.onRoomReceipt);
|
client.removeListener("Room.receipt", this.onRoomReceipt);
|
||||||
client.removeListener("RoomState.events", this.onRoomStateEvents);
|
client.removeListener("RoomState.events", this.onRoomStateEvents);
|
||||||
client.removeListener("RoomMember.name", this.onRoomMemberName);
|
client.removeListener("RoomMember.name", this.onRoomMemberName);
|
||||||
|
client.removeListener("RoomMember.membership", this.onRoomMemberMembership);
|
||||||
client.removeListener("accountData", this.onAccountData);
|
client.removeListener("accountData", this.onAccountData);
|
||||||
}
|
}
|
||||||
if (this._cancelDeviceList) {
|
if (this._cancelDeviceList) {
|
||||||
|
@ -186,6 +189,10 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onRoomMemberMembership: function(ev, member) {
|
||||||
|
if (this.props.member.userId === member.userId) this.forceUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
onAccountData: function(ev) {
|
onAccountData: function(ev) {
|
||||||
if (ev.getType() === 'm.direct') {
|
if (ev.getType() === 'm.direct') {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
|
@ -615,6 +622,8 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
const member = this.props.member;
|
const member = this.props.member;
|
||||||
|
|
||||||
let ignoreButton = null;
|
let ignoreButton = null;
|
||||||
|
let insertPillButton = null;
|
||||||
|
let inviteUserButton = null;
|
||||||
let readReceiptButton = null;
|
let readReceiptButton = null;
|
||||||
|
|
||||||
// Only allow the user to ignore the user if its not ourselves
|
// Only allow the user to ignore the user if its not ourselves
|
||||||
|
@ -639,22 +648,58 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onInsertPillButton = function() {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'insert_mention',
|
||||||
|
user_id: member.userId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
readReceiptButton = (
|
readReceiptButton = (
|
||||||
<AccessibleButton onClick={onReadReceiptButton} className="mx_MemberInfo_field">
|
<AccessibleButton onClick={onReadReceiptButton} className="mx_MemberInfo_field">
|
||||||
{ _t('Jump to read receipt') }
|
{ _t('Jump to read receipt') }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
insertPillButton = (
|
||||||
|
<AccessibleButton onClick={onInsertPillButton} className={"mx_MemberInfo_field"}>
|
||||||
|
{ _t('Mention') }
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!member || !member.membership || member.membership === 'leave') {
|
||||||
|
const roomId = member && member.roomId ? member.roomId : RoomViewStore.getRoomId();
|
||||||
|
const onInviteUserButton = async () => {
|
||||||
|
try {
|
||||||
|
await cli.invite(roomId, member.userId);
|
||||||
|
} catch (err) {
|
||||||
|
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
|
||||||
|
Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
|
||||||
|
title: _t('Failed to invite'),
|
||||||
|
description: ((err && err.message) ? err.message : "Operation failed"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inviteUserButton = (
|
||||||
|
<AccessibleButton onClick={onInviteUserButton} className="mx_MemberInfo_field">
|
||||||
|
{ _t('Invite') }
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ignoreButton && !readReceiptButton) return null;
|
if (!ignoreButton && !readReceiptButton && !insertPillButton && !inviteUserButton) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3>{ _t("User Options") }</h3>
|
<h3>{ _t("User Options") }</h3>
|
||||||
<div className="mx_MemberInfo_buttons">
|
<div className="mx_MemberInfo_buttons">
|
||||||
{ readReceiptButton }
|
{ readReceiptButton }
|
||||||
|
{ insertPillButton }
|
||||||
{ ignoreButton }
|
{ ignoreButton }
|
||||||
|
{ inviteUserButton }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -760,9 +805,6 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
</AccessibleButton>;
|
</AccessibleButton>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we should have an invite button if this MemberInfo is showing a user who isn't actually in the current room yet
|
|
||||||
// e.g. clicking on a linkified userid in a room
|
|
||||||
|
|
||||||
let adminTools;
|
let adminTools;
|
||||||
if (kickButton || banButton || muteButton || giveModButton) {
|
if (kickButton || banButton || muteButton || giveModButton) {
|
||||||
adminTools =
|
adminTools =
|
||||||
|
@ -790,9 +832,29 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
presenceCurrentlyActive = this.props.member.user.currentlyActive;
|
presenceCurrentlyActive = this.props.member.user.currentlyActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let roomMemberDetails = null;
|
||||||
|
|
||||||
|
if (this.props.member.roomId) { // is in room
|
||||||
|
const PowerSelector = sdk.getComponent('elements.PowerSelector');
|
||||||
|
const PresenceLabel = sdk.getComponent('rooms.PresenceLabel');
|
||||||
|
roomMemberDetails = <div>
|
||||||
|
<div className="mx_MemberInfo_profileField">
|
||||||
|
{ _t("Level:") } <b>
|
||||||
|
<PowerSelector controlled={true}
|
||||||
|
value={parseInt(this.props.member.powerLevel)}
|
||||||
|
disabled={!this.state.can.modifyLevel}
|
||||||
|
onChange={this.onPowerChange} />
|
||||||
|
</b>
|
||||||
|
</div>
|
||||||
|
<div className="mx_MemberInfo_profileField">
|
||||||
|
<PresenceLabel activeAgo={presenceLastActiveAgo}
|
||||||
|
currentlyActive={presenceCurrentlyActive}
|
||||||
|
presenceState={presenceState} />
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||||
const PowerSelector = sdk.getComponent('elements.PowerSelector');
|
|
||||||
const PresenceLabel = sdk.getComponent('rooms.PresenceLabel');
|
|
||||||
const EmojiText = sdk.getComponent('elements.EmojiText');
|
const EmojiText = sdk.getComponent('elements.EmojiText');
|
||||||
return (
|
return (
|
||||||
<div className="mx_MemberInfo">
|
<div className="mx_MemberInfo">
|
||||||
|
@ -808,16 +870,7 @@ module.exports = withMatrixClient(React.createClass({
|
||||||
<div className="mx_MemberInfo_profileField">
|
<div className="mx_MemberInfo_profileField">
|
||||||
{ this.props.member.userId }
|
{ this.props.member.userId }
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_MemberInfo_profileField">
|
{ roomMemberDetails }
|
||||||
{ _t("Level:") } <b>
|
|
||||||
<PowerSelector controlled={true} value={parseInt(this.props.member.powerLevel)} disabled={!this.state.can.modifyLevel} onChange={this.onPowerChange} />
|
|
||||||
</b>
|
|
||||||
</div>
|
|
||||||
<div className="mx_MemberInfo_profileField">
|
|
||||||
<PresenceLabel activeAgo={presenceLastActiveAgo}
|
|
||||||
currentlyActive={presenceCurrentlyActive}
|
|
||||||
presenceState={presenceState} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{ this._renderUserOptions() }
|
{ this._renderUserOptions() }
|
||||||
|
|
|
@ -95,7 +95,9 @@ module.exports = React.createClass({
|
||||||
return (
|
return (
|
||||||
<div className="mx_PinnedEventsPanel">
|
<div className="mx_PinnedEventsPanel">
|
||||||
<div className="mx_PinnedEventsPanel_body">
|
<div className="mx_PinnedEventsPanel_body">
|
||||||
<AccessibleButton className="mx_PinnedEventsPanel_cancel" onClick={this.props.onCancelClick}><img src="img/cancel.svg" width="18" height="18" /></AccessibleButton>
|
<AccessibleButton className="mx_PinnedEventsPanel_cancel" onClick={this.props.onCancelClick}>
|
||||||
|
<img className="mx_filterFlipColor" src="img/cancel.svg" width="18" height="18" />
|
||||||
|
</AccessibleButton>
|
||||||
<h3 className="mx_PinnedEventsPanel_header">{ _t("Pinned Messages") }</h3>
|
<h3 className="mx_PinnedEventsPanel_header">{ _t("Pinned Messages") }</h3>
|
||||||
{ tiles }
|
{ tiles }
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -281,8 +281,11 @@ module.exports = React.createClass({
|
||||||
<input id="avatarInput" type="file" onChange={this.onAvatarSelected} />
|
<input id="avatarInput" type="file" onChange={this.onAvatarSelected} />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_RoomHeader_avatarPicker_remove" onClick={this.onAvatarRemoveClick}>
|
<div className="mx_RoomHeader_avatarPicker_remove" onClick={this.onAvatarRemoveClick}>
|
||||||
<img src="img/cancel.svg" width="10"
|
<img src="img/cancel.svg"
|
||||||
alt={_t("Remove avatar")} title={_t("Remove avatar")} />
|
className="mx_filterFlipColor"
|
||||||
|
width="10"
|
||||||
|
alt={_t("Remove avatar")}
|
||||||
|
title={_t("Remove avatar")} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,10 +18,13 @@ limitations under the License.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import dis from '../../../dispatcher';
|
import dis from '../../../dispatcher';
|
||||||
|
|
||||||
|
import UserSettingsStore from '../../../UserSettingsStore';
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'VideoView',
|
displayName: 'VideoView',
|
||||||
|
|
||||||
|
@ -108,14 +111,18 @@ module.exports = React.createClass({
|
||||||
document.mozFullScreenElement ||
|
document.mozFullScreenElement ||
|
||||||
document.webkitFullscreenElement);
|
document.webkitFullscreenElement);
|
||||||
const maxVideoHeight = fullscreenElement ? null : this.props.maxHeight;
|
const maxVideoHeight = fullscreenElement ? null : this.props.maxHeight;
|
||||||
|
const localVideoFeedClasses = classNames("mx_VideoView_localVideoFeed",
|
||||||
|
{ "mx_VideoView_localVideoFeed_flipped":
|
||||||
|
UserSettingsStore.getSyncedSetting('VideoView.flipVideoHorizontally', false),
|
||||||
|
},
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div className="mx_VideoView" ref={this.setContainer} onClick={this.props.onClick}>
|
<div className="mx_VideoView" ref={this.setContainer} onClick={this.props.onClick}>
|
||||||
<div className="mx_VideoView_remoteVideoFeed">
|
<div className="mx_VideoView_remoteVideoFeed">
|
||||||
<VideoFeed ref="remote" onResize={this.props.onResize}
|
<VideoFeed ref="remote" onResize={this.props.onResize}
|
||||||
maxHeight={maxVideoHeight} />
|
maxHeight={maxVideoHeight} />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_VideoView_localVideoFeed">
|
<div className={localVideoFeedClasses}>
|
||||||
<VideoFeed ref="local" />
|
<VideoFeed ref="local" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -152,6 +152,7 @@
|
||||||
"%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s",
|
"%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s",
|
||||||
"Communities": "Communities",
|
"Communities": "Communities",
|
||||||
"Message Pinning": "Message Pinning",
|
"Message Pinning": "Message Pinning",
|
||||||
|
"Mention": "Mention",
|
||||||
"%(displayName)s is typing": "%(displayName)s is typing",
|
"%(displayName)s is typing": "%(displayName)s is typing",
|
||||||
"%(names)s and %(count)s others are typing|other": "%(names)s and %(count)s others are typing",
|
"%(names)s and %(count)s others are typing|other": "%(names)s and %(count)s others are typing",
|
||||||
"%(names)s and %(count)s others are typing|one": "%(names)s and one other is typing",
|
"%(names)s and %(count)s others are typing|one": "%(names)s and one other is typing",
|
||||||
|
@ -200,8 +201,6 @@
|
||||||
"Authentication": "Authentication",
|
"Authentication": "Authentication",
|
||||||
"Failed to delete device": "Failed to delete device",
|
"Failed to delete device": "Failed to delete device",
|
||||||
"Delete": "Delete",
|
"Delete": "Delete",
|
||||||
"Delete Widget": "Delete Widget",
|
|
||||||
"Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?",
|
|
||||||
"Disable Notifications": "Disable Notifications",
|
"Disable Notifications": "Disable Notifications",
|
||||||
"Enable Notifications": "Enable Notifications",
|
"Enable Notifications": "Enable Notifications",
|
||||||
"Cannot add any more widgets": "Cannot add any more widgets",
|
"Cannot add any more widgets": "Cannot add any more widgets",
|
||||||
|
@ -245,6 +244,7 @@
|
||||||
"Unignore": "Unignore",
|
"Unignore": "Unignore",
|
||||||
"Ignore": "Ignore",
|
"Ignore": "Ignore",
|
||||||
"Jump to read receipt": "Jump to read receipt",
|
"Jump to read receipt": "Jump to read receipt",
|
||||||
|
"Invite": "Invite",
|
||||||
"User Options": "User Options",
|
"User Options": "User Options",
|
||||||
"Direct chats": "Direct chats",
|
"Direct chats": "Direct chats",
|
||||||
"Unmute": "Unmute",
|
"Unmute": "Unmute",
|
||||||
|
@ -456,6 +456,7 @@
|
||||||
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?",
|
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?",
|
||||||
"Removed or unknown message type": "Removed or unknown message type",
|
"Removed or unknown message type": "Removed or unknown message type",
|
||||||
"Message removed by %(userId)s": "Message removed by %(userId)s",
|
"Message removed by %(userId)s": "Message removed by %(userId)s",
|
||||||
|
"Message removed": "Message removed",
|
||||||
"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>",
|
||||||
"This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot",
|
"This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot",
|
||||||
"Sign in with CAS": "Sign in with CAS",
|
"Sign in with CAS": "Sign in with CAS",
|
||||||
|
@ -500,10 +501,13 @@
|
||||||
"Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Are you sure you want to remove '%(roomName)s' from %(groupId)s?",
|
"Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Are you sure you want to remove '%(roomName)s' from %(groupId)s?",
|
||||||
"Removing a room from the community will also remove it from the community page.": "Removing a room from the community will also remove it from the community page.",
|
"Removing a room from the community will also remove it from the community page.": "Removing a room from the community will also remove it from the community page.",
|
||||||
"Remove": "Remove",
|
"Remove": "Remove",
|
||||||
|
"Remove this room from the community": "Remove this room from the community",
|
||||||
"Unknown Address": "Unknown Address",
|
"Unknown Address": "Unknown Address",
|
||||||
"NOTE: Apps are not end-to-end encrypted": "NOTE: Apps are not end-to-end encrypted",
|
"NOTE: Apps are not end-to-end encrypted": "NOTE: Apps are not end-to-end encrypted",
|
||||||
"Do you want to load widget from URL:": "Do you want to load widget from URL:",
|
"Do you want to load widget from URL:": "Do you want to load widget from URL:",
|
||||||
"Allow": "Allow",
|
"Allow": "Allow",
|
||||||
|
"Delete Widget": "Delete Widget",
|
||||||
|
"Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?",
|
||||||
"Delete widget": "Delete widget",
|
"Delete widget": "Delete widget",
|
||||||
"Revoke widget access": "Revoke widget access",
|
"Revoke widget access": "Revoke widget access",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
|
@ -688,8 +692,8 @@
|
||||||
"Featured Rooms:": "Featured Rooms:",
|
"Featured Rooms:": "Featured Rooms:",
|
||||||
"Featured Users:": "Featured Users:",
|
"Featured Users:": "Featured Users:",
|
||||||
"%(inviter)s has invited you to join this community": "%(inviter)s has invited you to join this community",
|
"%(inviter)s has invited you to join this community": "%(inviter)s has invited you to join this community",
|
||||||
"You are a member of this community": "You are a member of this community",
|
|
||||||
"You are an administrator of this community": "You are an administrator of this community",
|
"You are an administrator of this community": "You are an administrator of this community",
|
||||||
|
"You are a member of this community": "You are a member of this community",
|
||||||
"Community Member Settings": "Community Member Settings",
|
"Community Member Settings": "Community Member Settings",
|
||||||
"Publish this community on your profile": "Publish this community on your profile",
|
"Publish this community on your profile": "Publish this community on your profile",
|
||||||
"Long Description (HTML)": "Long Description (HTML)",
|
"Long Description (HTML)": "Long Description (HTML)",
|
||||||
|
@ -759,6 +763,7 @@
|
||||||
"Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing",
|
"Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing",
|
||||||
"Hide avatars in user and room mentions": "Hide avatars in user and room mentions",
|
"Hide avatars in user and room mentions": "Hide avatars in user and room mentions",
|
||||||
"Disable big emoji in chat": "Disable big emoji in chat",
|
"Disable big emoji in chat": "Disable big emoji in chat",
|
||||||
|
"Mirror local video feed": "Mirror local video feed",
|
||||||
"Opt out of analytics": "Opt out of analytics",
|
"Opt out of analytics": "Opt out of analytics",
|
||||||
"Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls",
|
"Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls",
|
||||||
"Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device",
|
"Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device",
|
||||||
|
|
|
@ -29,9 +29,10 @@ export default class GroupStore extends EventEmitter {
|
||||||
this._matrixClient = matrixClient;
|
this._matrixClient = matrixClient;
|
||||||
this._summary = {};
|
this._summary = {};
|
||||||
this._rooms = [];
|
this._rooms = [];
|
||||||
this._fetchSummary();
|
|
||||||
this._fetchRooms();
|
this.on('error', (err) => {
|
||||||
this._fetchMembers();
|
console.error(`GroupStore for ${this.groupId} encountered error`, err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_fetchMembers() {
|
_fetchMembers() {
|
||||||
|
@ -51,6 +52,10 @@ export default class GroupStore extends EventEmitter {
|
||||||
});
|
});
|
||||||
this._notifyListeners();
|
this._notifyListeners();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
// Invited users not visible to non-members
|
||||||
|
if (err.httpStatus === 403) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.error("Failed to get group invited member list: " + err);
|
console.error("Failed to get group invited member list: " + err);
|
||||||
this.emit('error', err);
|
this.emit('error', err);
|
||||||
});
|
});
|
||||||
|
@ -80,6 +85,17 @@ export default class GroupStore extends EventEmitter {
|
||||||
this.emit('update');
|
this.emit('update');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerListener(fn) {
|
||||||
|
this.on('update', fn);
|
||||||
|
this._fetchSummary();
|
||||||
|
this._fetchRooms();
|
||||||
|
this._fetchMembers();
|
||||||
|
}
|
||||||
|
|
||||||
|
unregisterListener(fn) {
|
||||||
|
this.removeListener('update', fn);
|
||||||
|
}
|
||||||
|
|
||||||
getSummary() {
|
getSummary() {
|
||||||
return this._summary;
|
return this._summary;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,9 @@ describe('MemberEventListSummary', function() {
|
||||||
sandbox = testUtils.stubClient();
|
sandbox = testUtils.stubClient();
|
||||||
|
|
||||||
languageHandler.setLanguage('en').done(done);
|
languageHandler.setLanguage('en').done(done);
|
||||||
|
languageHandler.setMissingEntryGenerator(function(key) {
|
||||||
|
return key.split('|', 2)[1];
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue