mirror of
https://github.com/element-hq/element-web
synced 2024-11-23 09:46:09 +03:00
Merge pull request #270 from matrix-org/rav/issue_1314_federated_rooms
RoomView: Handle joining federated rooms
This commit is contained in:
commit
85277a237a
2 changed files with 106 additions and 82 deletions
|
@ -628,10 +628,13 @@ module.exports = React.createClass({
|
|||
if (!this.refs.roomView) {
|
||||
return;
|
||||
}
|
||||
|
||||
var roomview = this.refs.roomView;
|
||||
var roomId = this.refs.roomView.getRoomId();
|
||||
if (!roomId) {
|
||||
return;
|
||||
}
|
||||
var state = roomview.getScrollState();
|
||||
this.scrollStateMap[roomview.props.roomId] = state;
|
||||
this.scrollStateMap[roomId] = state;
|
||||
},
|
||||
|
||||
onLoggedIn: function(credentials) {
|
||||
|
@ -1066,8 +1069,7 @@ module.exports = React.createClass({
|
|||
page_element = (
|
||||
<RoomView
|
||||
ref="roomView"
|
||||
roomId={this.state.currentRoom}
|
||||
roomAlias={this.state.currentRoomAlias}
|
||||
roomAddress={this.state.currentRoom || this.state.currentRoomAlias}
|
||||
eventId={this.state.initialEventId}
|
||||
thirdPartyInvite={this.state.thirdPartyInvite}
|
||||
oobData={this.state.roomOobData}
|
||||
|
|
|
@ -54,11 +54,15 @@ module.exports = React.createClass({
|
|||
propTypes: {
|
||||
ConferenceHandler: React.PropTypes.any,
|
||||
|
||||
roomId: React.PropTypes.string.isRequired,
|
||||
|
||||
// if we are referring to this room by a given alias (e.g. in the URL), track it.
|
||||
// useful for joining rooms by alias correctly (and fixing https://github.com/vector-im/vector-web/issues/819)
|
||||
roomAlias: React.PropTypes.string,
|
||||
// the ID for this room (or, if we don't know it, an alias for it)
|
||||
//
|
||||
// XXX: if this is an alias, we will display a 'join' dialogue,
|
||||
// regardless of whether we are already a member, or if the room is
|
||||
// peekable. Currently there is a big mess, where at least four
|
||||
// different components (RoomView, MatrixChat, RoomDirectory,
|
||||
// SlashCommands) have logic for turning aliases into rooms, and each
|
||||
// of them do it differently and have different edge cases.
|
||||
roomAddress: React.PropTypes.string.isRequired,
|
||||
|
||||
// An object representing a third party invite to join this room
|
||||
// Fields:
|
||||
|
@ -93,7 +97,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
getInitialState: function() {
|
||||
var room = this.props.roomId ? MatrixClientPeg.get().getRoom(this.props.roomId) : null;
|
||||
var room = MatrixClientPeg.get().getRoom(this.props.roomAddress);
|
||||
return {
|
||||
room: room,
|
||||
roomLoading: !room,
|
||||
|
@ -123,7 +127,6 @@ module.exports = React.createClass({
|
|||
this.dispatcherRef = dis.register(this.onAction);
|
||||
MatrixClientPeg.get().on("Room", this.onRoom);
|
||||
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
|
||||
MatrixClientPeg.get().on("Room.name", this.onRoomName);
|
||||
MatrixClientPeg.get().on("Room.accountData", this.onRoomAccountData);
|
||||
MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember);
|
||||
// xchat-style tab complete, add a colon if tab
|
||||
|
@ -146,9 +149,9 @@ module.exports = React.createClass({
|
|||
// We can /peek though. If it fails then we present the join UI. If it
|
||||
// succeeds then great, show the preview (but we still may be able to /join!).
|
||||
if (!this.state.room) {
|
||||
console.log("Attempting to peek into room %s", this.props.roomId);
|
||||
console.log("Attempting to peek into room %s", this.props.roomAddress);
|
||||
|
||||
MatrixClientPeg.get().peekInRoom(this.props.roomId).then((room) => {
|
||||
MatrixClientPeg.get().peekInRoom(this.props.roomAddress).then((room) => {
|
||||
this.setState({
|
||||
room: room,
|
||||
roomLoading: false,
|
||||
|
@ -200,7 +203,6 @@ module.exports = React.createClass({
|
|||
if (MatrixClientPeg.get()) {
|
||||
MatrixClientPeg.get().removeListener("Room", this.onRoom);
|
||||
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
|
||||
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
|
||||
MatrixClientPeg.get().removeListener("Room.accountData", this.onRoomAccountData);
|
||||
MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember);
|
||||
}
|
||||
|
@ -233,7 +235,7 @@ module.exports = React.createClass({
|
|||
return;
|
||||
}
|
||||
|
||||
var call = CallHandler.getCallForRoom(payload.room_id);
|
||||
var call = this._getCallForRoom();
|
||||
var callState;
|
||||
|
||||
if (call) {
|
||||
|
@ -256,7 +258,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
componentWillReceiveProps: function(newProps) {
|
||||
if (newProps.roomId != this.props.roomId) {
|
||||
if (newProps.roomAddress != this.props.roomAddress) {
|
||||
throw new Error("changing room on a RoomView is not supported");
|
||||
}
|
||||
|
||||
|
@ -270,7 +272,7 @@ module.exports = React.createClass({
|
|||
if (this.unmounted) return;
|
||||
|
||||
// ignore events for other rooms
|
||||
if (room.roomId != this.props.roomId) return;
|
||||
if (!this.state.room || room.roomId != this.state.room.roomId) return;
|
||||
|
||||
// ignore anything but real-time updates at the end of the room:
|
||||
// updates from pagination will happen when the paginate completes.
|
||||
|
@ -321,30 +323,18 @@ module.exports = React.createClass({
|
|||
// set it in our state and start using it (ie. init the timeline)
|
||||
// This will happen if we start off viewing a room we're not joined,
|
||||
// then join it whilst RoomView is looking at that room.
|
||||
if (room.roomId == this.props.roomId && !this.state.room) {
|
||||
if (!this.state.room && room.roomId == this._joiningRoomId) {
|
||||
this._joiningRoomId = undefined;
|
||||
this.setState({
|
||||
room: room
|
||||
room: room,
|
||||
joining: false,
|
||||
});
|
||||
this._onRoomLoaded(room);
|
||||
}
|
||||
},
|
||||
|
||||
onRoomName: function(room) {
|
||||
// NB don't set state.room here.
|
||||
//
|
||||
// When peeking, this event lands *before* the timeline is correctly
|
||||
// synced; if we set state.room here, the TimelinePanel will be
|
||||
// instantiated, and it will initialise its scroll state, with *no
|
||||
// events*. In short, the scroll state will be all messed up.
|
||||
//
|
||||
// There's no need to set state.room here anyway.
|
||||
if (room.roomId == this.props.roomId) {
|
||||
this.forceUpdate();
|
||||
}
|
||||
},
|
||||
|
||||
updateTint: function() {
|
||||
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
var room = this.state.room;
|
||||
if (!room) return;
|
||||
|
||||
var color_scheme_event = room.getAccountData("org.matrix.room.color_scheme");
|
||||
|
@ -367,28 +357,33 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
onRoomStateMember: function(ev, state, member) {
|
||||
if (member.roomId === this.props.roomId) {
|
||||
// ignore if we don't have a room yet
|
||||
if (!this.state.room) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore members in other rooms
|
||||
if (member.roomId !== this.state.room.roomId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// a member state changed in this room, refresh the tab complete list
|
||||
this._updateTabCompleteList();
|
||||
|
||||
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
if (!room) return;
|
||||
// if we are now a member of the room, where we were not before, that
|
||||
// means we have finished joining a room we were previously peeking
|
||||
// into.
|
||||
var me = MatrixClientPeg.get().credentials.userId;
|
||||
if (this.state.joining && room.hasMembershipState(me, "join")) {
|
||||
if (this.state.joining && this.state.room.hasMembershipState(me, "join")) {
|
||||
this.setState({
|
||||
joining: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.props.ConferenceHandler) {
|
||||
return;
|
||||
}
|
||||
if (member.roomId !== this.props.roomId ||
|
||||
member.userId !== this.props.ConferenceHandler.getConferenceUserIdForRoom(member.roomId)) {
|
||||
return;
|
||||
}
|
||||
if (this.props.ConferenceHandler &&
|
||||
member.userId === this.props.ConferenceHandler.getConferenceUserIdForRoom(member.roomId)) {
|
||||
this._updateConfCallNotification();
|
||||
}
|
||||
},
|
||||
|
||||
_hasUnsentMessages: function(room) {
|
||||
|
@ -403,12 +398,12 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
_updateConfCallNotification: function() {
|
||||
var room = MatrixClientPeg.get().getRoom(this.props.roomId);
|
||||
var room = this.state.room;
|
||||
if (!room || !this.props.ConferenceHandler) {
|
||||
return;
|
||||
}
|
||||
var confMember = room.getMember(
|
||||
this.props.ConferenceHandler.getConferenceUserIdForRoom(this.props.roomId)
|
||||
this.props.ConferenceHandler.getConferenceUserIdForRoom(room.roomId)
|
||||
);
|
||||
|
||||
if (!confMember) {
|
||||
|
@ -427,7 +422,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
var call = CallHandler.getCallForRoom(this.props.roomId);
|
||||
var call = this._getCallForRoom();
|
||||
var callState = call ? call.call_state : "ended";
|
||||
this.setState({
|
||||
callState: callState
|
||||
|
@ -559,25 +554,35 @@ module.exports = React.createClass({
|
|||
|
||||
display_name_promise.then(() => {
|
||||
var sign_url = this.props.thirdPartyInvite ? this.props.thirdPartyInvite.inviteSignUrl : undefined;
|
||||
return MatrixClientPeg.get().joinRoom(this.props.roomAlias || this.props.roomId,
|
||||
return MatrixClientPeg.get().joinRoom(this.props.roomAddress,
|
||||
{ inviteSignUrl: sign_url } )
|
||||
}).done(function() {
|
||||
}).then(function(resp) {
|
||||
var roomId = resp.roomId;
|
||||
|
||||
// It is possible that there is no Room yet if state hasn't come down
|
||||
// from /sync - joinRoom will resolve when the HTTP request to join succeeds,
|
||||
// NOT when it comes down /sync. If there is no room, we'll keep the
|
||||
// joining flag set until we see it. Likewise, if our state is not
|
||||
// "join" we'll keep this flag set until it comes down /sync.
|
||||
// joining flag set until we see it.
|
||||
|
||||
// We'll need to initialise the timeline when joining, but due to
|
||||
// the above, we can't do it here: we do it in onRoom instead,
|
||||
// once we have a useable room object.
|
||||
var room = MatrixClientPeg.get().getRoom(self.props.roomId);
|
||||
var room = MatrixClientPeg.get().getRoom(roomId);
|
||||
if (!room) {
|
||||
// wait for the room to turn up in onRoom.
|
||||
self._joiningRoomId = roomId;
|
||||
} else {
|
||||
// we've got a valid room, but that might also just mean that
|
||||
// it was peekable (so we had one before anyway). If we are
|
||||
// not yet a member of the room, we will need to wait for that
|
||||
// to happen, in onRoomStateMember.
|
||||
var me = MatrixClientPeg.get().credentials.userId;
|
||||
self.setState({
|
||||
joining: room ? !room.hasMembershipState(me, "join") : true,
|
||||
joining: !room.hasMembershipState(me, "join"),
|
||||
room: room
|
||||
});
|
||||
}, function(error) {
|
||||
}
|
||||
}).catch(function(error) {
|
||||
self.setState({
|
||||
joining: false,
|
||||
joinError: error
|
||||
|
@ -612,7 +617,8 @@ module.exports = React.createClass({
|
|||
description: msg
|
||||
});
|
||||
}
|
||||
});
|
||||
}).done();
|
||||
|
||||
this.setState({
|
||||
joining: true
|
||||
});
|
||||
|
@ -667,7 +673,7 @@ module.exports = React.createClass({
|
|||
uploadFile: function(file) {
|
||||
var self = this;
|
||||
ContentMessages.sendContentToRoom(
|
||||
file, this.props.roomId, MatrixClientPeg.get()
|
||||
file, this.state.room.roomId, MatrixClientPeg.get()
|
||||
).done(undefined, function(error) {
|
||||
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
|
@ -702,7 +708,7 @@ module.exports = React.createClass({
|
|||
filter = {
|
||||
// XXX: it's unintuitive that the filter for searching doesn't have the same shape as the v2 filter API :(
|
||||
rooms: [
|
||||
this.props.roomId
|
||||
this.state.room.roomId
|
||||
]
|
||||
};
|
||||
}
|
||||
|
@ -910,12 +916,12 @@ module.exports = React.createClass({
|
|||
onLeaveClick: function() {
|
||||
dis.dispatch({
|
||||
action: 'leave_room',
|
||||
room_id: this.props.roomId,
|
||||
room_id: this.state.room.roomId,
|
||||
});
|
||||
},
|
||||
|
||||
onForgetClick: function() {
|
||||
MatrixClientPeg.get().forget(this.props.roomId).done(function() {
|
||||
MatrixClientPeg.get().forget(this.state.room.roomId).done(function() {
|
||||
dis.dispatch({ action: 'view_next_room' });
|
||||
}, function(err) {
|
||||
var errCode = err.errcode || "unknown error code";
|
||||
|
@ -932,7 +938,7 @@ module.exports = React.createClass({
|
|||
this.setState({
|
||||
rejecting: true
|
||||
});
|
||||
MatrixClientPeg.get().leave(this.props.roomId).done(function() {
|
||||
MatrixClientPeg.get().leave(this.props.roomAddress).done(function() {
|
||||
dis.dispatch({ action: 'view_next_room' });
|
||||
self.setState({
|
||||
rejecting: false
|
||||
|
@ -1090,7 +1096,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
onMuteAudioClick: function() {
|
||||
var call = CallHandler.getCallForRoom(this.props.roomId);
|
||||
var call = this._getCallForRoom();
|
||||
if (!call) {
|
||||
return;
|
||||
}
|
||||
|
@ -1102,7 +1108,7 @@ module.exports = React.createClass({
|
|||
},
|
||||
|
||||
onMuteVideoClick: function() {
|
||||
var call = CallHandler.getCallForRoom(this.props.roomId);
|
||||
var call = this._getCallForRoom();
|
||||
if (!call) {
|
||||
return;
|
||||
}
|
||||
|
@ -1142,6 +1148,29 @@ module.exports = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the ID of the displayed room
|
||||
*
|
||||
* Returns null if the RoomView was instantiated on a room alias and
|
||||
* we haven't yet joined the room.
|
||||
*/
|
||||
getRoomId: function() {
|
||||
if (!this.state.room) {
|
||||
return null;
|
||||
}
|
||||
return this.state.room.roomId;
|
||||
},
|
||||
|
||||
/**
|
||||
* get any current call for this room
|
||||
*/
|
||||
_getCallForRoom: function() {
|
||||
if (!this.state.room) {
|
||||
return null;
|
||||
}
|
||||
return CallHandler.getCallForRoom(this.state.room.roomId);
|
||||
},
|
||||
|
||||
// this has to be a proper method rather than an unnamed function,
|
||||
// otherwise react calls it with null on each update.
|
||||
_gatherTimelinePanelRef: function(r) {
|
||||
|
@ -1164,7 +1193,6 @@ module.exports = React.createClass({
|
|||
var TimelinePanel = sdk.getComponent("structures.TimelinePanel");
|
||||
|
||||
if (!this.state.room) {
|
||||
if (this.props.roomId) {
|
||||
if (this.state.roomLoading) {
|
||||
return (
|
||||
<div className="mx_RoomView">
|
||||
|
@ -1202,12 +1230,6 @@ module.exports = React.createClass({
|
|||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var myUserId = MatrixClientPeg.get().credentials.userId;
|
||||
var myMember = this.state.room.getMember(myUserId);
|
||||
|
@ -1248,7 +1270,7 @@ module.exports = React.createClass({
|
|||
// We have successfully loaded this room, and are not previewing.
|
||||
// Display the "normal" room view.
|
||||
|
||||
var call = CallHandler.getCallForRoom(this.props.roomId);
|
||||
var call = this._getCallForRoom();
|
||||
var inCall = false;
|
||||
if (call && (this.state.callState !== 'ended' && this.state.callState !== 'ringing')) {
|
||||
inCall = true;
|
||||
|
|
Loading…
Reference in a new issue