Merge pull request #2925 from matrix-org/bwindels/stylepreviewbar
Redesigned room preview bar
This commit is contained in:
commit
0fbe10a816
13 changed files with 573 additions and 356 deletions
|
@ -24,6 +24,7 @@ steps:
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "matrixdotorg/riotweb-ci-e2etests-env:latest"
|
image: "matrixdotorg/riotweb-ci-e2etests-env:latest"
|
||||||
|
propagate-environment: true
|
||||||
|
|
||||||
- label: ":karma: Tests"
|
- label: ":karma: Tests"
|
||||||
agents:
|
agents:
|
||||||
|
|
|
@ -523,3 +523,38 @@ textarea {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// username colors
|
||||||
|
// used by SenderProfile & RoomPreviewBar
|
||||||
|
.mx_Username_color1 {
|
||||||
|
color: $username-variant1-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Username_color2 {
|
||||||
|
color: $username-variant2-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Username_color3 {
|
||||||
|
color: $username-variant3-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Username_color4 {
|
||||||
|
color: $username-variant4-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Username_color5 {
|
||||||
|
color: $username-variant5-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Username_color6 {
|
||||||
|
color: $username-variant6-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Username_color7 {
|
||||||
|
color: $username-variant7-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Username_color8 {
|
||||||
|
color: $username-variant8-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,15 +163,6 @@ limitations under the License.
|
||||||
height: 1px;
|
height: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.mx_RoomView_body .mx_RoomView_statusArea {
|
|
||||||
order: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_RoomView_body .mx_MessageComposer {
|
|
||||||
order: 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_RoomView_messageListWrapper {
|
.mx_RoomView_messageListWrapper {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,12 @@ limitations under the License.
|
||||||
.mx_AccessibleButton_kind_primary {
|
.mx_AccessibleButton_kind_primary {
|
||||||
color: $button-primary-fg-color;
|
color: $button-primary-fg-color;
|
||||||
background-color: $button-primary-bg-color;
|
background-color: $button-primary-bg-color;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_AccessibleButton_kind_secondary {
|
||||||
|
color: $accent-color;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AccessibleButton_kind_primary.mx_AccessibleButton_disabled {
|
.mx_AccessibleButton_kind_primary.mx_AccessibleButton_disabled {
|
||||||
|
|
|
@ -18,36 +18,3 @@ limitations under the License.
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_SenderProfile_color1 {
|
|
||||||
color: $username-variant1-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SenderProfile_color2 {
|
|
||||||
color: $username-variant2-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SenderProfile_color3 {
|
|
||||||
color: $username-variant3-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SenderProfile_color4 {
|
|
||||||
color: $username-variant4-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SenderProfile_color5 {
|
|
||||||
color: $username-variant5-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SenderProfile_color6 {
|
|
||||||
color: $username-variant6-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SenderProfile_color7 {
|
|
||||||
color: $username-variant7-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SenderProfile_color8 {
|
|
||||||
color: $username-variant8-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,48 +15,112 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_RoomPreviewBar {
|
.mx_RoomPreviewBar {
|
||||||
text-align: center;
|
flex: 0 0 auto;
|
||||||
height: 176px;
|
|
||||||
background-color: $event-selected-color;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: $preview-bar-bg-color;
|
|
||||||
-webkit-align-items: center;
|
-webkit-align-items: center;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&.mx_RoomPreviewBar_spinnerTitle {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_Spinner {
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
margin: 10px 10px 10px 0;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomPreviewBar_wrapper {
|
.mx_RoomPreviewBar_dark {
|
||||||
|
background-color: $tagpanel-bg-color;
|
||||||
|
color: $accent-fg-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomPreviewBar_invite_text {
|
.mx_RoomPreviewBar_actions {
|
||||||
color: $primary-fg-color;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomPreviewBar_join_text {
|
.mx_RoomPreviewBar_message {
|
||||||
color: $warning-color;
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
p {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomPreviewBar_preview_text {
|
.mx_RoomPreviewBar_panel {
|
||||||
margin-top: 25px;
|
padding: 8px 8px 8px 20px;
|
||||||
color: $settings-grey-fg-color;
|
border-top: 1px solid $panel-divider-color;
|
||||||
|
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.mx_RoomPreviewBar_actions {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 3px 8px;
|
||||||
|
|
||||||
|
&>* {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomPreviewBar_message {
|
||||||
|
flex: 1 0 0;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&>* {
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomPreviewBar_join_text a {
|
.mx_RoomPreviewBar_dialog {
|
||||||
|
margin: auto;
|
||||||
|
box-sizing: content;
|
||||||
|
width: 400px;
|
||||||
|
border-radius: 4px;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.mx_RoomPreviewBar_message {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&>* {
|
||||||
|
margin: 5px 0 20px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomPreviewBar_actions {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
.mx_AccessibleButton {
|
||||||
|
padding: 7px 50px;//extra wide
|
||||||
|
}
|
||||||
|
|
||||||
|
&>* {
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_RoomPreviewBar_inviter {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.mx_RoomPreviewBar_inviter {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomPreviewBar_warning {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_RoomPreviewBar_warningIcon {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_RoomPreviewBar_spinnerIntro {
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
|
@ -565,6 +565,9 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 'view_user_info':
|
||||||
|
this._viewUser(payload.userId, payload.subAction);
|
||||||
|
break;
|
||||||
case 'view_room':
|
case 'view_room':
|
||||||
// Takes either a room ID or room alias: if switching to a room the client is already
|
// Takes either a room ID or room alias: if switching to a room the client is already
|
||||||
// known to be in (eg. user clicks on a room in the recents panel), supply the ID
|
// known to be in (eg. user clicks on a room in the recents panel), supply the ID
|
||||||
|
@ -919,6 +922,22 @@ export default React.createClass({
|
||||||
this.notifyNewScreen('home');
|
this.notifyNewScreen('home');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_viewUser: function(userId, subAction) {
|
||||||
|
// Wait for the first sync so that `getRoom` gives us a room object if it's
|
||||||
|
// in the sync response
|
||||||
|
const waitForSync = this.firstSyncPromise ?
|
||||||
|
this.firstSyncPromise.promise : Promise.resolve();
|
||||||
|
waitForSync.then(() => {
|
||||||
|
if (subAction === 'chat') {
|
||||||
|
this._chatCreateOrReuse(userId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.notifyNewScreen('user/' + userId);
|
||||||
|
this.setState({currentUserId: userId});
|
||||||
|
this._setPage(PageTypes.UserView);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
_setMxId: function(payload) {
|
_setMxId: function(payload) {
|
||||||
const SetMxIdDialog = sdk.getComponent('views.dialogs.SetMxIdDialog');
|
const SetMxIdDialog = sdk.getComponent('views.dialogs.SetMxIdDialog');
|
||||||
const close = Modal.createTrackedDialog('Set MXID', '', SetMxIdDialog, {
|
const close = Modal.createTrackedDialog('Set MXID', '', SetMxIdDialog, {
|
||||||
|
@ -1612,19 +1631,10 @@ export default React.createClass({
|
||||||
dis.dispatch(payload);
|
dis.dispatch(payload);
|
||||||
} else if (screen.indexOf('user/') == 0) {
|
} else if (screen.indexOf('user/') == 0) {
|
||||||
const userId = screen.substring(5);
|
const userId = screen.substring(5);
|
||||||
|
dis.dispatch({
|
||||||
// Wait for the first sync so that `getRoom` gives us a room object if it's
|
action: 'view_user_info',
|
||||||
// in the sync response
|
userId: userId,
|
||||||
const waitFor = this.firstSyncPromise ?
|
subAction: params.action,
|
||||||
this.firstSyncPromise.promise : Promise.resolve();
|
|
||||||
waitFor.then(() => {
|
|
||||||
if (params.action === 'chat') {
|
|
||||||
this._chatCreateOrReuse(userId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.notifyNewScreen('user/' + userId);
|
|
||||||
this.setState({currentUserId: userId});
|
|
||||||
this._setPage(PageTypes.UserView);
|
|
||||||
});
|
});
|
||||||
} else if (screen.indexOf('group/') == 0) {
|
} else if (screen.indexOf('group/') == 0) {
|
||||||
const groupId = screen.substring(6);
|
const groupId = screen.substring(6);
|
||||||
|
|
|
@ -1511,16 +1511,21 @@ module.exports = React.createClass({
|
||||||
const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
|
const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||||
const RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar");
|
const RoomPreviewBar = sdk.getComponent("rooms.RoomPreviewBar");
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
|
||||||
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
|
const TimelinePanel = sdk.getComponent("structures.TimelinePanel");
|
||||||
const RoomUpgradeWarningBar = sdk.getComponent("rooms.RoomUpgradeWarningBar");
|
const RoomUpgradeWarningBar = sdk.getComponent("rooms.RoomUpgradeWarningBar");
|
||||||
const RoomRecoveryReminder = sdk.getComponent("rooms.RoomRecoveryReminder");
|
const RoomRecoveryReminder = sdk.getComponent("rooms.RoomRecoveryReminder");
|
||||||
|
|
||||||
if (!this.state.room) {
|
if (!this.state.room) {
|
||||||
if (this.state.roomLoading || this.state.peekLoading) {
|
const loading = this.state.roomLoading || this.state.peekLoading;
|
||||||
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomView">
|
<div className="mx_RoomView">
|
||||||
<Loader />
|
<RoomPreviewBar
|
||||||
|
canPreview={false}
|
||||||
|
error={this.state.roomLoadError}
|
||||||
|
loading={loading}
|
||||||
|
joining={this.state.joining}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1538,28 +1543,16 @@ module.exports = React.createClass({
|
||||||
const roomAlias = this.state.roomAlias;
|
const roomAlias = this.state.roomAlias;
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomView">
|
<div className="mx_RoomView">
|
||||||
<RoomHeader ref="header"
|
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked}
|
||||||
|
onForgetClick={this.onForgetClick}
|
||||||
|
onRejectClick={this.onRejectThreepidInviteButtonClicked}
|
||||||
|
canPreview={false} error={this.state.roomLoadError}
|
||||||
|
roomAlias={roomAlias}
|
||||||
|
joining={this.state.joining}
|
||||||
|
inviterName={inviterName}
|
||||||
|
invitedEmail={invitedEmail}
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
oobData={this.props.oobData}
|
|
||||||
collapsedRhs={this.props.collapsedRhs}
|
|
||||||
e2eStatus={this.state.e2eStatus}
|
|
||||||
/>
|
/>
|
||||||
<div className="mx_RoomView_body">
|
|
||||||
<div className="mx_RoomView_auxPanel">
|
|
||||||
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked}
|
|
||||||
onForgetClick={this.onForgetClick}
|
|
||||||
onRejectClick={this.onRejectThreepidInviteButtonClicked}
|
|
||||||
canPreview={false} error={this.state.roomLoadError}
|
|
||||||
roomAlias={roomAlias}
|
|
||||||
spinner={this.state.joining}
|
|
||||||
spinnerState="joining"
|
|
||||||
inviterName={inviterName}
|
|
||||||
invitedEmail={invitedEmail}
|
|
||||||
room={this.state.room}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mx_RoomView_messagePanel"></div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1569,9 +1562,12 @@ module.exports = React.createClass({
|
||||||
if (myMembership == 'invite') {
|
if (myMembership == 'invite') {
|
||||||
if (this.state.joining || this.state.rejecting) {
|
if (this.state.joining || this.state.rejecting) {
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomView">
|
<RoomPreviewBar
|
||||||
<Loader />
|
canPreview={false}
|
||||||
</div>
|
error={this.state.roomLoadError}
|
||||||
|
joining={this.state.joining}
|
||||||
|
rejecting={this.state.rejecting}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const myUserId = MatrixClientPeg.get().credentials.userId;
|
const myUserId = MatrixClientPeg.get().credentials.userId;
|
||||||
|
@ -1586,26 +1582,14 @@ module.exports = React.createClass({
|
||||||
// We have a regular invite for this room.
|
// We have a regular invite for this room.
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomView">
|
<div className="mx_RoomView">
|
||||||
<RoomHeader
|
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked}
|
||||||
ref="header"
|
onForgetClick={this.onForgetClick}
|
||||||
|
onRejectClick={this.onRejectButtonClicked}
|
||||||
|
inviterName={inviterName}
|
||||||
|
canPreview={false}
|
||||||
|
joining={this.state.joining}
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
collapsedRhs={this.props.collapsedRhs}
|
|
||||||
e2eStatus={this.state.e2eStatus}
|
|
||||||
/>
|
/>
|
||||||
<div className="mx_RoomView_body">
|
|
||||||
<div className="mx_RoomView_auxPanel">
|
|
||||||
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked}
|
|
||||||
onForgetClick={this.onForgetClick}
|
|
||||||
onRejectClick={this.onRejectButtonClicked}
|
|
||||||
inviterName={inviterName}
|
|
||||||
canPreview={false}
|
|
||||||
spinner={this.state.joining}
|
|
||||||
spinnerState="joining"
|
|
||||||
room={this.state.room}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mx_RoomView_messagePanel"></div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1661,7 +1645,9 @@ module.exports = React.createClass({
|
||||||
const hiddenHighlightCount = this._getHiddenHighlightCount();
|
const hiddenHighlightCount = this._getHiddenHighlightCount();
|
||||||
|
|
||||||
let aux = null;
|
let aux = null;
|
||||||
|
let previewBar;
|
||||||
let hideCancel = false;
|
let hideCancel = false;
|
||||||
|
let hideRightPanel = false;
|
||||||
if (this.state.forwardingEvent !== null) {
|
if (this.state.forwardingEvent !== null) {
|
||||||
aux = <ForwardMessage onCancelClick={this.onCancelClick} />;
|
aux = <ForwardMessage onCancelClick={this.onCancelClick} />;
|
||||||
} else if (this.state.searching) {
|
} else if (this.state.searching) {
|
||||||
|
@ -1688,18 +1674,26 @@ module.exports = React.createClass({
|
||||||
invitedEmail = this.props.thirdPartyInvite.invitedEmail;
|
invitedEmail = this.props.thirdPartyInvite.invitedEmail;
|
||||||
}
|
}
|
||||||
hideCancel = true;
|
hideCancel = true;
|
||||||
aux = (
|
previewBar = (
|
||||||
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked}
|
<RoomPreviewBar onJoinClick={this.onJoinButtonClicked}
|
||||||
onForgetClick={this.onForgetClick}
|
onForgetClick={this.onForgetClick}
|
||||||
onRejectClick={this.onRejectThreepidInviteButtonClicked}
|
onRejectClick={this.onRejectThreepidInviteButtonClicked}
|
||||||
spinner={this.state.joining}
|
joining={this.state.joining}
|
||||||
spinnerState="joining"
|
|
||||||
inviterName={inviterName}
|
inviterName={inviterName}
|
||||||
invitedEmail={invitedEmail}
|
invitedEmail={invitedEmail}
|
||||||
canPreview={this.state.canPeek}
|
canPreview={this.state.canPeek}
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
if (!this.state.canPeek) {
|
||||||
|
return (
|
||||||
|
<div className="mx_RoomView">
|
||||||
|
{ previewBar }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
hideRightPanel = true;
|
||||||
|
}
|
||||||
} else if (hiddenHighlightCount > 0) {
|
} else if (hiddenHighlightCount > 0) {
|
||||||
aux = (
|
aux = (
|
||||||
<AccessibleButton element="div" className="mx_RoomView_auxPanel_hiddenHighlights"
|
<AccessibleButton element="div" className="mx_RoomView_auxPanel_hiddenHighlights"
|
||||||
|
@ -1743,11 +1737,6 @@ module.exports = React.createClass({
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
|
||||||
const AuthButtons = sdk.getComponent('views.auth.AuthButtons');
|
|
||||||
messageComposer = <AuthButtons />;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Why aren't we storing the term/scope/count in this format
|
// TODO: Why aren't we storing the term/scope/count in this format
|
||||||
// in this.state if this is what RoomHeader desires?
|
// in this.state if this is what RoomHeader desires?
|
||||||
if (this.state.searchResults) {
|
if (this.state.searchResults) {
|
||||||
|
@ -1875,14 +1864,16 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const rightPanel = this.state.room ? <RightPanel roomId={this.state.room.roomId} resizeNotifier={this.props.resizeNotifier} /> : undefined;
|
const rightPanel = !hideRightPanel && this.state.room &&
|
||||||
|
<RightPanel roomId={this.state.room.roomId} resizeNotifier={this.props.resizeNotifier} />;
|
||||||
|
const collapsedRhs = hideRightPanel || this.props.collapsedRhs;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className={"mx_RoomView" + (inCall ? " mx_RoomView_inCall" : "")} ref="roomView">
|
<main className={"mx_RoomView" + (inCall ? " mx_RoomView_inCall" : "")} ref="roomView">
|
||||||
<RoomHeader ref="header" room={this.state.room} searchInfo={searchInfo}
|
<RoomHeader ref="header" room={this.state.room} searchInfo={searchInfo}
|
||||||
oobData={this.props.oobData}
|
oobData={this.props.oobData}
|
||||||
inRoom={myMembership === 'join'}
|
inRoom={myMembership === 'join'}
|
||||||
collapsedRhs={this.props.collapsedRhs}
|
collapsedRhs={collapsedRhs}
|
||||||
onSearchClick={this.onSearchClick}
|
onSearchClick={this.onSearchClick}
|
||||||
onSettingsClick={this.onSettingsClick}
|
onSettingsClick={this.onSettingsClick}
|
||||||
onPinnedClick={this.onPinnedClick}
|
onPinnedClick={this.onPinnedClick}
|
||||||
|
@ -1893,7 +1884,7 @@ module.exports = React.createClass({
|
||||||
/>
|
/>
|
||||||
<MainSplit
|
<MainSplit
|
||||||
panel={rightPanel}
|
panel={rightPanel}
|
||||||
collapsedRhs={this.props.collapsedRhs}
|
collapsedRhs={collapsedRhs}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
>
|
>
|
||||||
<div className={fadableSectionClasses}>
|
<div className={fadableSectionClasses}>
|
||||||
|
@ -1910,6 +1901,7 @@ module.exports = React.createClass({
|
||||||
{ statusBar }
|
{ statusBar }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{ previewBar }
|
||||||
{ messageComposer }
|
{ messageComposer }
|
||||||
</div>
|
</div>
|
||||||
</MainSplit>
|
</MainSplit>
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2017 Vector Creations Ltd
|
|
||||||
Copyright 2018, 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const React = require('react');
|
|
||||||
import { _t } from '../../../languageHandler';
|
|
||||||
const dis = require('../../../dispatcher');
|
|
||||||
const AccessibleButton = require('../elements/AccessibleButton');
|
|
||||||
|
|
||||||
module.exports = React.createClass({
|
|
||||||
displayName: 'AuthButtons',
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
},
|
|
||||||
|
|
||||||
onLoginClick: function() {
|
|
||||||
dis.dispatch({ action: 'start_login' });
|
|
||||||
},
|
|
||||||
|
|
||||||
onRegisterClick: function() {
|
|
||||||
dis.dispatch({ action: 'start_registration' });
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
const loginButton = (
|
|
||||||
<div className="mx_AuthButtons_loginButton_wrapper">
|
|
||||||
<AccessibleButton className="mx_AuthButtons_loginButton" element="button" onClick={this.onLoginClick}>
|
|
||||||
{ _t("Login") }
|
|
||||||
</AccessibleButton>
|
|
||||||
<AccessibleButton className="mx_AuthButtons_registerButton" element="button" onClick={this.onRegisterClick}>
|
|
||||||
{ _t("Register") }
|
|
||||||
</AccessibleButton>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="mx_AuthButtons">
|
|
||||||
{ loginButton }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -23,7 +23,7 @@ import sdk from '../../../index';
|
||||||
import Flair from '../elements/Flair.js';
|
import Flair from '../elements/Flair.js';
|
||||||
import FlairStore from '../../../stores/FlairStore';
|
import FlairStore from '../../../stores/FlairStore';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import {hashCode} from '../../../utils/FormattingUtils';
|
import {getUserNameColorClass} from '../../../utils/FormattingUtils';
|
||||||
|
|
||||||
export default React.createClass({
|
export default React.createClass({
|
||||||
displayName: 'SenderProfile',
|
displayName: 'SenderProfile',
|
||||||
|
@ -97,7 +97,7 @@ export default React.createClass({
|
||||||
render() {
|
render() {
|
||||||
const EmojiText = sdk.getComponent('elements.EmojiText');
|
const EmojiText = sdk.getComponent('elements.EmojiText');
|
||||||
const {mxEvent} = this.props;
|
const {mxEvent} = this.props;
|
||||||
const colorNumber = (hashCode(mxEvent.getSender()) % 8) + 1;
|
const colorClass = getUserNameColorClass(mxEvent.getSender());
|
||||||
const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();
|
||||||
const {msgtype} = mxEvent.getContent();
|
const {msgtype} = mxEvent.getContent();
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ export default React.createClass({
|
||||||
|
|
||||||
// Name + flair
|
// Name + flair
|
||||||
const nameFlair = <span>
|
const nameFlair = <span>
|
||||||
<span className={`mx_SenderProfile_name mx_SenderProfile_color${colorNumber}`}>
|
<span className={`mx_SenderProfile_name ${colorClass}`}>
|
||||||
{ nameElem }
|
{ nameElem }
|
||||||
</span>
|
</span>
|
||||||
{ flair }
|
{ flair }
|
||||||
|
|
|
@ -17,12 +17,29 @@ limitations under the License.
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const React = require('react');
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
const sdk = require('../../../index');
|
import sdk from '../../../index';
|
||||||
const MatrixClientPeg = require('../../../MatrixClientPeg');
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
|
import dis from '../../../dispatcher';
|
||||||
|
import classNames from 'classnames';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
import {getUserNameColorClass} from '../../../utils/FormattingUtils';
|
||||||
|
|
||||||
|
const MessageCase = Object.freeze({
|
||||||
|
NotLoggedIn: "NotLoggedIn",
|
||||||
|
Joining: "Joining",
|
||||||
|
Loading: "Loading",
|
||||||
|
Rejecting: "Rejecting",
|
||||||
|
Kicked: "Kicked",
|
||||||
|
Banned: "Banned",
|
||||||
|
OtherThreePIDError: "OtherThreePIDError",
|
||||||
|
InvitedEmailMismatch: "InvitedEmailMismatch",
|
||||||
|
Invite: "Invite",
|
||||||
|
ViewingRoom: "ViewingRoom",
|
||||||
|
RoomNotFound: "RoomNotFound",
|
||||||
|
OtherError: "OtherError",
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'RoomPreviewBar',
|
displayName: 'RoomPreviewBar',
|
||||||
|
@ -31,7 +48,6 @@ module.exports = React.createClass({
|
||||||
onJoinClick: PropTypes.func,
|
onJoinClick: PropTypes.func,
|
||||||
onRejectClick: PropTypes.func,
|
onRejectClick: PropTypes.func,
|
||||||
onForgetClick: PropTypes.func,
|
onForgetClick: PropTypes.func,
|
||||||
|
|
||||||
// if inviterName is specified, the preview bar will shown an invite to the room.
|
// if inviterName is specified, the preview bar will shown an invite to the room.
|
||||||
// You should also specify onRejectClick if specifiying inviterName
|
// You should also specify onRejectClick if specifiying inviterName
|
||||||
inviterName: PropTypes.string,
|
inviterName: PropTypes.string,
|
||||||
|
@ -50,7 +66,9 @@ module.exports = React.createClass({
|
||||||
// purpose of the spinner.
|
// purpose of the spinner.
|
||||||
spinner: PropTypes.bool,
|
spinner: PropTypes.bool,
|
||||||
spinnerState: PropTypes.oneOf(["joining"]),
|
spinnerState: PropTypes.oneOf(["joining"]),
|
||||||
|
loading: PropTypes.bool,
|
||||||
|
joining: PropTypes.bool,
|
||||||
|
rejecting: PropTypes.bool,
|
||||||
// The alias that was used to access this room, if appropriate
|
// The alias that was used to access this room, if appropriate
|
||||||
// If given, this will be how the room is referred to (eg.
|
// If given, this will be how the room is referred to (eg.
|
||||||
// in error messages).
|
// in error messages).
|
||||||
|
@ -60,7 +78,6 @@ module.exports = React.createClass({
|
||||||
getDefaultProps: function() {
|
getDefaultProps: function() {
|
||||||
return {
|
return {
|
||||||
onJoinClick: function() {},
|
onJoinClick: function() {},
|
||||||
canPreview: true,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -72,7 +89,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
// If this is an invite and we've been told what email
|
// If this is an invite and we've been told what email
|
||||||
// address was invited, fetch the user's list of 3pids
|
// address was invited, fetch the user's list of Threepids
|
||||||
// so we can check them against the one that was invited
|
// so we can check them against the one that was invited
|
||||||
if (this.props.inviterName && this.props.invitedEmail) {
|
if (this.props.inviterName && this.props.invitedEmail) {
|
||||||
this.setState({busy: true});
|
this.setState({busy: true});
|
||||||
|
@ -88,157 +105,334 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_roomNameElement: function() {
|
_onInviterClick(evt) {
|
||||||
return this.props.room ? this.props.room.name : (this.props.room_alias || "");
|
evt.preventDefault();
|
||||||
|
const member = this._getInviteMember();
|
||||||
|
dis.dispatch({action: 'view_user_info', userId: member.userId});
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
_getMessageCase() {
|
||||||
let joinBlock; let previewBlock;
|
const isGuest = MatrixClientPeg.get().isGuest();
|
||||||
|
|
||||||
if (this.props.spinner || this.state.busy) {
|
if (isGuest) {
|
||||||
const Spinner = sdk.getComponent("elements.Spinner");
|
return MessageCase.NotLoggedIn;
|
||||||
let spinnerIntro = "";
|
|
||||||
if (this.props.spinnerState === "joining") {
|
|
||||||
spinnerIntro = _t("Joining room...");
|
|
||||||
}
|
|
||||||
return (<div className="mx_RoomPreviewBar">
|
|
||||||
<p className="mx_RoomPreviewBar_spinnerIntro">{ spinnerIntro }</p>
|
|
||||||
<Spinner />
|
|
||||||
</div>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const myMember = this.props.room &&
|
||||||
|
this.props.room.getMember(MatrixClientPeg.get().getUserId());
|
||||||
|
|
||||||
|
if (myMember) {
|
||||||
|
if (myMember.isKicked()) {
|
||||||
|
return MessageCase.Kicked;
|
||||||
|
} else if (myMember.membership === "ban") {
|
||||||
|
return MessageCase.Banned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.joining) {
|
||||||
|
return MessageCase.Joining;
|
||||||
|
} else if (this.props.rejecting) {
|
||||||
|
return MessageCase.Rejecting;
|
||||||
|
} else if (this.props.loading || this.state.busy) {
|
||||||
|
return MessageCase.Loading;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.inviterName) {
|
||||||
|
if (this.props.invitedEmail) {
|
||||||
|
if (this.state.threePidFetchError) {
|
||||||
|
return MessageCase.OtherThreePIDError;
|
||||||
|
} else if (this.state.invitedEmailMxid != MatrixClientPeg.get().getUserId()) {
|
||||||
|
return MessageCase.InvitedEmailMismatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MessageCase.Invite;
|
||||||
|
} else if (this.props.error) {
|
||||||
|
if (this.props.error.errcode == 'M_NOT_FOUND') {
|
||||||
|
return MessageCase.RoomNotFound;
|
||||||
|
} else {
|
||||||
|
return MessageCase.OtherError;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return MessageCase.ViewingRoom;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getKickOrBanInfo() {
|
||||||
const myMember = this.props.room ?
|
const myMember = this.props.room ?
|
||||||
this.props.room.getMember(MatrixClientPeg.get().getUserId()) :
|
this.props.room.getMember(MatrixClientPeg.get().getUserId()) :
|
||||||
null;
|
null;
|
||||||
const kicked = myMember && myMember.isKicked();
|
if (!myMember) {
|
||||||
const banned = myMember && myMember && myMember.membership == 'ban';
|
return {};
|
||||||
|
}
|
||||||
|
const kickerMember = this.props.room.currentState.getMember(
|
||||||
|
myMember.events.member.getSender(),
|
||||||
|
);
|
||||||
|
const memberName = kickerMember ?
|
||||||
|
kickerMember.name : myMember.events.member.getSender();
|
||||||
|
const reason = myMember.events.member.getContent().reason;
|
||||||
|
return {memberName, reason};
|
||||||
|
},
|
||||||
|
|
||||||
if (this.props.inviterName) {
|
_joinRule: function() {
|
||||||
let emailMatchBlock;
|
const room = this.props.room;
|
||||||
if (this.props.invitedEmail) {
|
if (room) {
|
||||||
if (this.state.threePidFetchError) {
|
const joinRules = room.currentState.getStateEvents('m.room.join_rules', '');
|
||||||
emailMatchBlock = <div className="error">
|
if (joinRules) {
|
||||||
{ _t("Unable to ascertain that the address this invite was sent to matches one associated with your account.") }
|
return joinRules.getContent().join_rule;
|
||||||
</div>;
|
|
||||||
} else if (this.state.invitedEmailMxid != MatrixClientPeg.get().credentials.userId) {
|
|
||||||
emailMatchBlock =
|
|
||||||
<div className="mx_RoomPreviewBar_warning">
|
|
||||||
<div className="mx_RoomPreviewBar_warningIcon">
|
|
||||||
<img src={require("../../../../res/img/warning.svg")} width="24" height="23" title= "/!\\" alt="/!\\" />
|
|
||||||
</div>
|
|
||||||
<div className="mx_RoomPreviewBar_warningText">
|
|
||||||
{ _t("This invitation was sent to an email address which is not associated with this account:") }
|
|
||||||
<b><span className="email">{ this.props.invitedEmail }</span></b>
|
|
||||||
<br />
|
|
||||||
{ _t("You may wish to login with a different account, or add this email to this account.") }
|
|
||||||
</div>
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
joinBlock = (
|
|
||||||
<div>
|
|
||||||
<div className="mx_RoomPreviewBar_invite_text">
|
|
||||||
{ _t('You have been invited to join this room by %(inviterName)s', {inviterName: this.props.inviterName}) }
|
|
||||||
</div>
|
|
||||||
<div className="mx_RoomPreviewBar_join_text">
|
|
||||||
{ _t(
|
|
||||||
'Would you like to <acceptText>accept</acceptText> or <declineText>decline</declineText> this invitation?',
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
'acceptText': (sub) => <a onClick={this.props.onJoinClick}>{ sub }</a>,
|
|
||||||
'declineText': (sub) => <a onClick={this.props.onRejectClick}>{ sub }</a>,
|
|
||||||
},
|
|
||||||
) }
|
|
||||||
</div>
|
|
||||||
{ emailMatchBlock }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (kicked || banned) {
|
|
||||||
const roomName = this._roomNameElement();
|
|
||||||
const kickerMember = this.props.room.currentState.getMember(
|
|
||||||
myMember.events.member.getSender(),
|
|
||||||
);
|
|
||||||
const kickerName = kickerMember ?
|
|
||||||
kickerMember.name : myMember.events.member.getSender();
|
|
||||||
let reason;
|
|
||||||
if (myMember.events.member.getContent().reason) {
|
|
||||||
reason = <div>{ _t("Reason: %(reasonText)s", {reasonText: myMember.events.member.getContent().reason}) }</div>;
|
|
||||||
}
|
|
||||||
let rejoinBlock;
|
|
||||||
if (!banned) {
|
|
||||||
rejoinBlock = <div><a onClick={this.props.onJoinClick}><b>{ _t("Rejoin") }</b></a></div>;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
let actionText;
|
_roomName: function(atStart = false) {
|
||||||
if (kicked) {
|
const name = this.props.room ? this.props.room.name : this.props.roomAlias;
|
||||||
if (roomName) {
|
if (name) {
|
||||||
actionText = _t("You have been kicked from %(roomName)s by %(userName)s.", {roomName: roomName, userName: kickerName});
|
return name;
|
||||||
} else {
|
} else if (atStart) {
|
||||||
actionText = _t("You have been kicked from this room by %(userName)s.", {userName: kickerName});
|
return _t("This room");
|
||||||
}
|
|
||||||
} else if (banned) {
|
|
||||||
if (roomName) {
|
|
||||||
actionText = _t("You have been banned from %(roomName)s by %(userName)s.", {roomName: roomName, userName: kickerName});
|
|
||||||
} else {
|
|
||||||
actionText = _t("You have been banned from this room by %(userName)s.", {userName: kickerName});
|
|
||||||
}
|
|
||||||
} // no other options possible due to the kicked || banned check above.
|
|
||||||
|
|
||||||
joinBlock = (
|
|
||||||
<div>
|
|
||||||
<div className="mx_RoomPreviewBar_join_text">
|
|
||||||
{ actionText }
|
|
||||||
<br />
|
|
||||||
{ reason }
|
|
||||||
{ rejoinBlock }
|
|
||||||
<a onClick={this.props.onForgetClick}><b>{ _t("Forget room") }</b></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (this.props.error) {
|
|
||||||
const name = this.props.roomAlias || _t("This room");
|
|
||||||
let error;
|
|
||||||
if (this.props.error.errcode == 'M_NOT_FOUND') {
|
|
||||||
error = _t("%(roomName)s does not exist.", {roomName: name});
|
|
||||||
} else {
|
|
||||||
error = _t("%(roomName)s is not accessible at this time.", {roomName: name});
|
|
||||||
}
|
|
||||||
joinBlock = (
|
|
||||||
<div>
|
|
||||||
<div className="mx_RoomPreviewBar_join_text">
|
|
||||||
{ error }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
const name = this._roomNameElement();
|
return _t("this room");
|
||||||
joinBlock = (
|
}
|
||||||
<div>
|
},
|
||||||
<div className="mx_RoomPreviewBar_join_text">
|
|
||||||
{ name ? _t('You are trying to access %(roomName)s.', {roomName: name}) : _t('You are trying to access a room.') }
|
_getInviteMember: function() {
|
||||||
<br />
|
const {room} = this.props;
|
||||||
{ _t("<a>Click here</a> to join the discussion!",
|
if (!room) {
|
||||||
{},
|
return;
|
||||||
{ 'a': (sub) => <a onClick={this.props.onJoinClick}><b>{ sub }</b></a> },
|
}
|
||||||
) }
|
const myUserId = MatrixClientPeg.get().getUserId();
|
||||||
</div>
|
const inviteEvent = room.currentState.getMember(myUserId);
|
||||||
</div>
|
if (!inviteEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const inviterUserId = inviteEvent.events.member.getSender();
|
||||||
|
return room.currentState.getMember(inviterUserId);
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoginClick: function() {
|
||||||
|
dis.dispatch({ action: 'start_login' });
|
||||||
|
},
|
||||||
|
|
||||||
|
onRegisterClick: function() {
|
||||||
|
dis.dispatch({ action: 'start_registration' });
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
let showSpinner = false;
|
||||||
|
let darkStyle = false;
|
||||||
|
let title;
|
||||||
|
let subTitle;
|
||||||
|
let primaryActionHandler;
|
||||||
|
let primaryActionLabel;
|
||||||
|
let secondaryActionHandler;
|
||||||
|
let secondaryActionLabel;
|
||||||
|
|
||||||
|
const messageCase = this._getMessageCase();
|
||||||
|
switch (messageCase) {
|
||||||
|
case MessageCase.Joining: {
|
||||||
|
title = _t("Joining room …");
|
||||||
|
showSpinner = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.Loading: {
|
||||||
|
title = _t("Loading …");
|
||||||
|
showSpinner = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.Rejecting: {
|
||||||
|
title = _t("Rejecting invite …");
|
||||||
|
showSpinner = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.NotLoggedIn: {
|
||||||
|
darkStyle = true;
|
||||||
|
title = _t("Join the conversation with an account");
|
||||||
|
primaryActionLabel = _t("Sign Up");
|
||||||
|
primaryActionHandler = this.onRegisterClick;
|
||||||
|
secondaryActionLabel = _t("Sign In");
|
||||||
|
secondaryActionHandler = this.onLoginClick;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.Kicked: {
|
||||||
|
const {memberName, reason} = this._getKickOrBanInfo();
|
||||||
|
title = _t("You were kicked from %(roomName)s by %(memberName)s",
|
||||||
|
{memberName, roomName: this._roomName()});
|
||||||
|
subTitle = _t("Reason: %(reason)s", {reason});
|
||||||
|
|
||||||
|
if (this._joinRule() === "invite") {
|
||||||
|
primaryActionLabel = _t("Forget this room");
|
||||||
|
primaryActionHandler = this.props.onForgetClick;
|
||||||
|
} else {
|
||||||
|
primaryActionLabel = _t("Re-join");
|
||||||
|
primaryActionHandler = this.props.onJoinClick;
|
||||||
|
secondaryActionLabel = _t("Forget this room");
|
||||||
|
secondaryActionHandler = this.props.onForgetClick;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.Banned: {
|
||||||
|
const {memberName, reason} = this._getKickOrBanInfo();
|
||||||
|
title = _t("You were banned from %(roomName)s by %(memberName)s",
|
||||||
|
{memberName, roomName: this._roomName()});
|
||||||
|
subTitle = _t("Reason: %(reason)s", {reason});
|
||||||
|
primaryActionLabel = _t("Forget this room");
|
||||||
|
primaryActionHandler = this.props.onForgetClick;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.OtherThreePIDError: {
|
||||||
|
title = _t("Something went wrong with your invite to this room");
|
||||||
|
const joinRule = this._joinRule();
|
||||||
|
const errCodeMessage = _t("%(errcode)s was returned while trying to valide your invite. You could try to pass this information on to a room admin.",
|
||||||
|
{errcode: this.state.threePidFetchError.errcode},
|
||||||
|
);
|
||||||
|
switch (joinRule) {
|
||||||
|
case "invite":
|
||||||
|
subTitle = [
|
||||||
|
_t("You can only join it with a working invite."),
|
||||||
|
errCodeMessage,
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
case "public":
|
||||||
|
subTitle = _t("You can still join it because this is a public room.");
|
||||||
|
primaryActionLabel = _t("Join the discussion");
|
||||||
|
primaryActionHandler = this.props.onJoinClick;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
subTitle = errCodeMessage;
|
||||||
|
primaryActionLabel = _t("Try to join anyway");
|
||||||
|
primaryActionHandler = this.props.onJoinClick;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.InvitedEmailMismatch: {
|
||||||
|
title = _t("The room invite wasn't sent to your account");
|
||||||
|
const joinRule = this._joinRule();
|
||||||
|
if (joinRule === "public") {
|
||||||
|
subTitle = _t("You can still join it because this is a public room.");
|
||||||
|
primaryActionLabel = _t("Join the discussion");
|
||||||
|
primaryActionHandler = this.props.onJoinClick;
|
||||||
|
} else {
|
||||||
|
subTitle = _t("Sign in with a different account, ask for another invite, or add the e-mail address %(email)s to this account.", {email: this.props.invitedEmail});
|
||||||
|
if (joinRule !== "invite") {
|
||||||
|
primaryActionLabel = _t("Try to join anyway");
|
||||||
|
primaryActionHandler = this.props.onJoinClick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.Invite: {
|
||||||
|
const inviteMember = this._getInviteMember();
|
||||||
|
let avatar;
|
||||||
|
let inviterElement;
|
||||||
|
if (inviteMember) {
|
||||||
|
const MemberAvatar = sdk.getComponent("views.avatars.MemberAvatar");
|
||||||
|
avatar = (<MemberAvatar member={inviteMember} onClick={this._onInviterClick} />);
|
||||||
|
const inviterClasses = [
|
||||||
|
"mx_RoomPreviewBar_inviter",
|
||||||
|
getUserNameColorClass(inviteMember.userId),
|
||||||
|
].join(" ");
|
||||||
|
inviterElement = (
|
||||||
|
<a onClick={this._onInviterClick} className={inviterClasses}>
|
||||||
|
{inviteMember.name}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
inviterElement = (<span className="mx_RoomPreviewBar_inviter">{this.props.inviterName}</span>);
|
||||||
|
}
|
||||||
|
|
||||||
|
title = _t("Do you want to join this room?");
|
||||||
|
subTitle = [
|
||||||
|
avatar,
|
||||||
|
_t("<userName/> invited you", {}, {userName: () => inviterElement}),
|
||||||
|
];
|
||||||
|
|
||||||
|
primaryActionLabel = _t("Accept");
|
||||||
|
primaryActionHandler = this.props.onJoinClick;
|
||||||
|
secondaryActionLabel = _t("Reject");
|
||||||
|
secondaryActionHandler = this.props.onRejectClick;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.ViewingRoom: {
|
||||||
|
if (this.props.canPreview) {
|
||||||
|
title = _t("You're previewing this room. Want to join it?");
|
||||||
|
} else {
|
||||||
|
title = _t("%(roomName)s can't be previewed. Do you want to join it?",
|
||||||
|
{roomName: this._roomName(true)});
|
||||||
|
}
|
||||||
|
primaryActionLabel = _t("Join the discussion");
|
||||||
|
primaryActionHandler = this.props.onJoinClick;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.RoomNotFound: {
|
||||||
|
title = _t("%(roomName)s does not exist.", {roomName: this._roomName(true)});
|
||||||
|
subTitle = _t("This room doesn't exist. Are you sure you're at the right place?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MessageCase.OtherError: {
|
||||||
|
title = _t("%(roomName)s is not accessible at this time.", {roomName: this._roomName(true)});
|
||||||
|
subTitle = [
|
||||||
|
_t("Try again later, or ask a room admin to check if you have access."),
|
||||||
|
_t("%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please <issueLink>submit a bug report</issueLink>.",
|
||||||
|
{ errcode: this.props.error.errcode },
|
||||||
|
{ issueLink: label => <a href="https://github.com/vector-im/riot-web/issues/new/choose"
|
||||||
|
target="_blank" rel="noopener">{ label }</a> },
|
||||||
|
),
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
const Spinner = sdk.getComponent('elements.Spinner');
|
||||||
|
|
||||||
|
let subTitleElements;
|
||||||
|
if (subTitle) {
|
||||||
|
if (!Array.isArray(subTitle)) {
|
||||||
|
subTitle = [subTitle];
|
||||||
|
}
|
||||||
|
subTitleElements = subTitle.map((t, i) => <p key={`subTitle${i}`}>{t}</p>);
|
||||||
|
}
|
||||||
|
|
||||||
|
let titleElement;
|
||||||
|
if (showSpinner) {
|
||||||
|
titleElement = <h3 className="mx_RoomPreviewBar_spinnerTitle"><Spinner />{ title }</h3>;
|
||||||
|
} else {
|
||||||
|
titleElement = <h3>{ title }</h3>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let primaryButton;
|
||||||
|
if (primaryActionHandler) {
|
||||||
|
primaryButton = (
|
||||||
|
<AccessibleButton kind="primary" onClick={primaryActionHandler}>
|
||||||
|
{ primaryActionLabel }
|
||||||
|
</AccessibleButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.props.canPreview) {
|
let secondaryButton;
|
||||||
previewBlock = (
|
if (secondaryActionHandler) {
|
||||||
<div className="mx_RoomPreviewBar_preview_text">
|
secondaryButton = (
|
||||||
{ _t('This is a preview of this room. Room interactions have been disabled') }.
|
<AccessibleButton kind="secondary" onClick={secondaryActionHandler}>
|
||||||
</div>
|
{ secondaryActionLabel }
|
||||||
|
</AccessibleButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const classes = classNames("mx_RoomPreviewBar", "dark-panel", `mx_RoomPreviewBar_${messageCase}`, {
|
||||||
|
"mx_RoomPreviewBar_panel": this.props.canPreview,
|
||||||
|
"mx_RoomPreviewBar_dialog": !this.props.canPreview,
|
||||||
|
"mx_RoomPreviewBar_dark": darkStyle,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_RoomPreviewBar">
|
<div className={classes}>
|
||||||
<div className="mx_RoomPreviewBar_wrapper">
|
<div className="mx_RoomPreviewBar_message">
|
||||||
{ joinBlock }
|
{ titleElement }
|
||||||
{ previewBlock }
|
{ subTitleElements }
|
||||||
|
</div>
|
||||||
|
<div className="mx_RoomPreviewBar_actions">
|
||||||
|
{ secondaryButton }
|
||||||
|
{ primaryButton }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -601,7 +601,7 @@
|
||||||
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
|
"This room is not accessible by remote Matrix servers": "This room is not accessible by remote Matrix servers",
|
||||||
"Upgrade this room to the recommended room version": "Upgrade this room to the recommended room version",
|
"Upgrade this room to the recommended room version": "Upgrade this room to the recommended room version",
|
||||||
"this room": "this room",
|
"this room": "this room",
|
||||||
"View older messages in %(roomName)s": "View older messages in %(roomName)s",
|
"View older messages in %(roomName)s.": "View older messages in %(roomName)s.",
|
||||||
"Room information": "Room information",
|
"Room information": "Room information",
|
||||||
"Internal room ID:": "Internal room ID:",
|
"Internal room ID:": "Internal room ID:",
|
||||||
"Room version": "Room version",
|
"Room version": "Room version",
|
||||||
|
@ -792,25 +792,36 @@
|
||||||
"Low priority": "Low priority",
|
"Low priority": "Low priority",
|
||||||
"Historical": "Historical",
|
"Historical": "Historical",
|
||||||
"System Alerts": "System Alerts",
|
"System Alerts": "System Alerts",
|
||||||
"Joining room...": "Joining room...",
|
|
||||||
"Unable to ascertain that the address this invite was sent to matches one associated with your account.": "Unable to ascertain that the address this invite was sent to matches one associated with your account.",
|
|
||||||
"This invitation was sent to an email address which is not associated with this account:": "This invitation was sent to an email address which is not associated with this account:",
|
|
||||||
"You may wish to login with a different account, or add this email to this account.": "You may wish to login with a different account, or add this email to this account.",
|
|
||||||
"You have been invited to join this room by %(inviterName)s": "You have been invited to join this room by %(inviterName)s",
|
|
||||||
"Would you like to <acceptText>accept</acceptText> or <declineText>decline</declineText> this invitation?": "Would you like to <acceptText>accept</acceptText> or <declineText>decline</declineText> this invitation?",
|
|
||||||
"Reason: %(reasonText)s": "Reason: %(reasonText)s",
|
|
||||||
"Rejoin": "Rejoin",
|
|
||||||
"You have been kicked from %(roomName)s by %(userName)s.": "You have been kicked from %(roomName)s by %(userName)s.",
|
|
||||||
"You have been kicked from this room by %(userName)s.": "You have been kicked from this room by %(userName)s.",
|
|
||||||
"You have been banned from %(roomName)s by %(userName)s.": "You have been banned from %(roomName)s by %(userName)s.",
|
|
||||||
"You have been banned from this room by %(userName)s.": "You have been banned from this room by %(userName)s.",
|
|
||||||
"This room": "This room",
|
"This room": "This room",
|
||||||
|
"Joining room …": "Joining room …",
|
||||||
|
"Loading …": "Loading …",
|
||||||
|
"Rejecting invite …": "Rejecting invite …",
|
||||||
|
"Join the conversation with an account": "Join the conversation with an account",
|
||||||
|
"Sign Up": "Sign Up",
|
||||||
|
"Sign In": "Sign In",
|
||||||
|
"You were kicked from %(roomName)s by %(memberName)s": "You were kicked from %(roomName)s by %(memberName)s",
|
||||||
|
"Reason: %(reason)s": "Reason: %(reason)s",
|
||||||
|
"Forget this room": "Forget this room",
|
||||||
|
"Re-join": "Re-join",
|
||||||
|
"You were banned from %(roomName)s by %(memberName)s": "You were banned from %(roomName)s by %(memberName)s",
|
||||||
|
"Something went wrong with your invite to this room": "Something went wrong with your invite to this room",
|
||||||
|
"%(errcode)s was returned while trying to valide your invite. You could try to pass this information on to a room admin.": "%(errcode)s was returned while trying to valide your invite. You could try to pass this information on to a room admin.",
|
||||||
|
"You can only join it with a working invite.": "You can only join it with a working invite.",
|
||||||
|
"You can still join it because this is a public room.": "You can still join it because this is a public room.",
|
||||||
|
"Join the discussion": "Join the discussion",
|
||||||
|
"Try to join anyway": "Try to join anyway",
|
||||||
|
"The room invite wasn't sent to your account": "The room invite wasn't sent to your account",
|
||||||
|
"Sign in with a different account, ask for another invite, or add the e-mail address %(email)s to this account.": "Sign in with a different account, ask for another invite, or add the e-mail address %(email)s to this account.",
|
||||||
|
"Do you want to join this room?": "Do you want to join this room?",
|
||||||
|
"<userName/> invited you": "<userName/> invited you",
|
||||||
|
"Reject": "Reject",
|
||||||
|
"You're previewing this room. Want to join it?": "You're previewing this room. Want to join it?",
|
||||||
|
"%(roomName)s can't be previewed. Do you want to join it?": "%(roomName)s can't be previewed. Do you want to join it?",
|
||||||
"%(roomName)s does not exist.": "%(roomName)s does not exist.",
|
"%(roomName)s does not exist.": "%(roomName)s does not exist.",
|
||||||
|
"This room doesn't exist. Are you sure you're at the right place?": "This room doesn't exist. Are you sure you're at the right place?",
|
||||||
"%(roomName)s is not accessible at this time.": "%(roomName)s is not accessible at this time.",
|
"%(roomName)s is not accessible at this time.": "%(roomName)s is not accessible at this time.",
|
||||||
"You are trying to access %(roomName)s.": "You are trying to access %(roomName)s.",
|
"Try again later, or ask a room admin to check if you have access.": "Try again later, or ask a room admin to check if you have access.",
|
||||||
"You are trying to access a room.": "You are trying to access a room.",
|
"%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please <issueLink>submit a bug report</issueLink>.": "%(errcode)s was returned while trying to access the room. If you think you're seeing this message in error, please <issueLink>submit a bug report</issueLink>.",
|
||||||
"<a>Click here</a> to join the discussion!": "<a>Click here</a> to join the discussion!",
|
|
||||||
"This is a preview of this room. Room interactions have been disabled": "This is a preview of this room. Room interactions have been disabled",
|
|
||||||
"Use Key Backup": "Use Key Backup",
|
"Use Key Backup": "Use Key Backup",
|
||||||
"Never lose encrypted messages": "Never lose encrypted messages",
|
"Never lose encrypted messages": "Never lose encrypted messages",
|
||||||
"Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
|
"Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Messages in this room are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.",
|
||||||
|
@ -1245,7 +1256,6 @@
|
||||||
"Reject invitation": "Reject invitation",
|
"Reject invitation": "Reject invitation",
|
||||||
"Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?",
|
"Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?",
|
||||||
"Unable to reject invite": "Unable to reject invite",
|
"Unable to reject invite": "Unable to reject invite",
|
||||||
"Reject": "Reject",
|
|
||||||
"You cannot delete this message. (%(code)s)": "You cannot delete this message. (%(code)s)",
|
"You cannot delete this message. (%(code)s)": "You cannot delete this message. (%(code)s)",
|
||||||
"Resend": "Resend",
|
"Resend": "Resend",
|
||||||
"Cancel Sending": "Cancel Sending",
|
"Cancel Sending": "Cancel Sending",
|
||||||
|
@ -1279,7 +1289,6 @@
|
||||||
"Hide": "Hide",
|
"Hide": "Hide",
|
||||||
"Home": "Home",
|
"Home": "Home",
|
||||||
"Sign in": "Sign in",
|
"Sign in": "Sign in",
|
||||||
"Login": "Login",
|
|
||||||
"powered by Matrix": "powered by Matrix",
|
"powered by Matrix": "powered by Matrix",
|
||||||
"This homeserver would like to make sure you are not a robot.": "This homeserver would like to make sure you are not a robot.",
|
"This homeserver would like to make sure you are not a robot.": "This homeserver would like to make sure you are not a robot.",
|
||||||
"Custom Server Options": "Custom Server Options",
|
"Custom Server Options": "Custom Server Options",
|
||||||
|
|
|
@ -58,3 +58,8 @@ export function hashCode(str) {
|
||||||
}
|
}
|
||||||
return Math.abs(hash);
|
return Math.abs(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getUserNameColorClass(userId) {
|
||||||
|
const colorNumber = (hashCode(userId) % 8) + 1;
|
||||||
|
return `mx_Username_color${colorNumber}`;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue