mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 05:04:57 +08:00
Merge pull request #5027 from matrix-org/t3chguy/room-list/13981
When the room view isn't active don't highlight it in room list
This commit is contained in:
commit
3675128061
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
@ -26,6 +26,7 @@ import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore";
|
||||
import {IntegrationManagers} from "../integrations/IntegrationManagers";
|
||||
import {ModalManager} from "../Modal";
|
||||
import SettingsStore from "../settings/SettingsStore";
|
||||
import {ActiveRoomObserver} from "../ActiveRoomObserver";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -41,6 +42,7 @@ declare global {
|
||||
mxRebrandListener: RebrandListener;
|
||||
mxRoomListStore: RoomListStoreClass;
|
||||
mxRoomListLayoutStore: RoomListLayoutStore;
|
||||
mxActiveRoomObserver: ActiveRoomObserver;
|
||||
mxPlatformPeg: PlatformPeg;
|
||||
mxIntegrationManagers: typeof IntegrationManagers;
|
||||
singletonModalManager: ModalManager;
|
||||
|
@ -16,6 +16,8 @@ limitations under the License.
|
||||
|
||||
import RoomViewStore from './stores/RoomViewStore';
|
||||
|
||||
type Listener = (isActive: boolean) => void;
|
||||
|
||||
/**
|
||||
* Consumes changes from the RoomViewStore and notifies specific things
|
||||
* about when the active room changes. Unlike listening for RoomViewStore
|
||||
@ -25,57 +27,57 @@ import RoomViewStore from './stores/RoomViewStore';
|
||||
* TODO: If we introduce an observer for something else, factor out
|
||||
* the adding / removing of listeners & emitting into a common class.
|
||||
*/
|
||||
class ActiveRoomObserver {
|
||||
constructor() {
|
||||
this._listeners = {}; // key=roomId, value=function(isActive:boolean)
|
||||
export class ActiveRoomObserver {
|
||||
private listeners: {[key: string]: Listener[]} = {};
|
||||
private _activeRoomId = RoomViewStore.getRoomId();
|
||||
private readonly roomStoreToken: string;
|
||||
|
||||
this._activeRoomId = RoomViewStore.getRoomId();
|
||||
// TODO: We could self-destruct when the last listener goes away, or at least
|
||||
// stop listening.
|
||||
this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate.bind(this));
|
||||
constructor() {
|
||||
// TODO: We could self-destruct when the last listener goes away, or at least stop listening.
|
||||
this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
|
||||
}
|
||||
|
||||
get activeRoomId(): string {
|
||||
public get activeRoomId(): string {
|
||||
return this._activeRoomId;
|
||||
}
|
||||
|
||||
addListener(roomId, listener) {
|
||||
if (!this._listeners[roomId]) this._listeners[roomId] = [];
|
||||
this._listeners[roomId].push(listener);
|
||||
public addListener(roomId, listener) {
|
||||
if (!this.listeners[roomId]) this.listeners[roomId] = [];
|
||||
this.listeners[roomId].push(listener);
|
||||
}
|
||||
|
||||
removeListener(roomId, listener) {
|
||||
if (this._listeners[roomId]) {
|
||||
const i = this._listeners[roomId].indexOf(listener);
|
||||
public removeListener(roomId, listener) {
|
||||
if (this.listeners[roomId]) {
|
||||
const i = this.listeners[roomId].indexOf(listener);
|
||||
if (i > -1) {
|
||||
this._listeners[roomId].splice(i, 1);
|
||||
this.listeners[roomId].splice(i, 1);
|
||||
}
|
||||
} else {
|
||||
console.warn("Unregistering unrecognised listener (roomId=" + roomId + ")");
|
||||
}
|
||||
}
|
||||
|
||||
_emit(roomId, isActive: boolean) {
|
||||
if (!this._listeners[roomId]) return;
|
||||
private emit(roomId, isActive: boolean) {
|
||||
if (!this.listeners[roomId]) return;
|
||||
|
||||
for (const l of this._listeners[roomId]) {
|
||||
for (const l of this.listeners[roomId]) {
|
||||
l.call(null, isActive);
|
||||
}
|
||||
}
|
||||
|
||||
_onRoomViewStoreUpdate() {
|
||||
private onRoomViewStoreUpdate = () => {
|
||||
// emit for the old room ID
|
||||
if (this._activeRoomId) this._emit(this._activeRoomId, false);
|
||||
if (this._activeRoomId) this.emit(this._activeRoomId, false);
|
||||
|
||||
// update our cache
|
||||
this._activeRoomId = RoomViewStore.getRoomId();
|
||||
|
||||
// and emit for the new one
|
||||
if (this._activeRoomId) this._emit(this._activeRoomId, true);
|
||||
}
|
||||
if (this._activeRoomId) this.emit(this._activeRoomId, true);
|
||||
};
|
||||
}
|
||||
|
||||
if (global.mx_ActiveRoomObserver === undefined) {
|
||||
global.mx_ActiveRoomObserver = new ActiveRoomObserver();
|
||||
if (window.mxActiveRoomObserver === undefined) {
|
||||
window.mxActiveRoomObserver = new ActiveRoomObserver();
|
||||
}
|
||||
export default global.mx_ActiveRoomObserver;
|
||||
export default window.mxActiveRoomObserver;
|
@ -15,13 +15,17 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import dis from '../dispatcher/dispatcher';
|
||||
|
||||
import React from "react";
|
||||
import {Store} from 'flux/utils';
|
||||
|
||||
import dis from '../dispatcher/dispatcher';
|
||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
||||
import * as sdk from '../index';
|
||||
import Modal from '../Modal';
|
||||
import { _t } from '../languageHandler';
|
||||
import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCache';
|
||||
import {ActionPayload} from "../dispatcher/payloads";
|
||||
|
||||
const INITIAL_STATE = {
|
||||
// Whether we're joining the currently viewed room (see isJoining())
|
||||
@ -33,6 +37,7 @@ const INITIAL_STATE = {
|
||||
|
||||
// The event to scroll to when the room is first viewed
|
||||
initialEventId: null,
|
||||
initialEventPixelOffset: null,
|
||||
// Whether to highlight the initial event
|
||||
isInitialEventHighlighted: false,
|
||||
|
||||
@ -46,6 +51,10 @@ const INITIAL_STATE = {
|
||||
forwardingEvent: null,
|
||||
|
||||
quotingEvent: null,
|
||||
|
||||
replyingToEvent: null,
|
||||
|
||||
shouldPeek: false,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -53,21 +62,20 @@ const INITIAL_STATE = {
|
||||
* with a subset of the js-sdk.
|
||||
* ```
|
||||
*/
|
||||
class RoomViewStore extends Store {
|
||||
class RoomViewStore extends Store<ActionPayload> {
|
||||
private state = INITIAL_STATE; // initialize state
|
||||
|
||||
constructor() {
|
||||
super(dis);
|
||||
|
||||
// Initialise state
|
||||
this._state = INITIAL_STATE;
|
||||
}
|
||||
|
||||
_setState(newState) {
|
||||
setState(newState: Partial<typeof INITIAL_STATE>) {
|
||||
// If values haven't changed, there's nothing to do.
|
||||
// This only tries a shallow comparison, so unchanged objects will slip
|
||||
// through, but that's probably okay for now.
|
||||
let stateChanged = false;
|
||||
for (const key of Object.keys(newState)) {
|
||||
if (this._state[key] !== newState[key]) {
|
||||
if (this.state[key] !== newState[key]) {
|
||||
stateChanged = true;
|
||||
break;
|
||||
}
|
||||
@ -76,7 +84,7 @@ class RoomViewStore extends Store {
|
||||
return;
|
||||
}
|
||||
|
||||
this._state = Object.assign(this._state, newState);
|
||||
this.state = Object.assign(this.state, newState);
|
||||
this.__emitChange();
|
||||
}
|
||||
|
||||
@ -89,59 +97,63 @@ class RoomViewStore extends Store {
|
||||
// - event_offset: 100
|
||||
// - highlighted: true
|
||||
case 'view_room':
|
||||
this._viewRoom(payload);
|
||||
this.viewRoom(payload);
|
||||
break;
|
||||
// for these events blank out the roomId as we are no longer in the RoomView
|
||||
case 'view_create_group':
|
||||
case 'view_welcome_page':
|
||||
case 'view_home_page':
|
||||
case 'view_my_groups':
|
||||
case 'view_group':
|
||||
this._setState({
|
||||
this.setState({
|
||||
roomId: null,
|
||||
roomAlias: null,
|
||||
});
|
||||
break;
|
||||
case 'view_room_error':
|
||||
this._viewRoomError(payload);
|
||||
this.viewRoomError(payload);
|
||||
break;
|
||||
case 'will_join':
|
||||
this._setState({
|
||||
this.setState({
|
||||
joining: true,
|
||||
});
|
||||
break;
|
||||
case 'cancel_join':
|
||||
this._setState({
|
||||
this.setState({
|
||||
joining: false,
|
||||
});
|
||||
break;
|
||||
// join_room:
|
||||
// - opts: options for joinRoom
|
||||
case 'join_room':
|
||||
this._joinRoom(payload);
|
||||
this.joinRoom(payload);
|
||||
break;
|
||||
case 'join_room_error':
|
||||
this._joinRoomError(payload);
|
||||
this.joinRoomError(payload);
|
||||
break;
|
||||
case 'join_room_ready':
|
||||
this._setState({ shouldPeek: false });
|
||||
this.setState({ shouldPeek: false });
|
||||
break;
|
||||
case 'on_client_not_viable':
|
||||
case 'on_logged_out':
|
||||
this.reset();
|
||||
break;
|
||||
case 'forward_event':
|
||||
this._setState({
|
||||
this.setState({
|
||||
forwardingEvent: payload.event,
|
||||
});
|
||||
break;
|
||||
case 'reply_to_event':
|
||||
// If currently viewed room does not match the room in which we wish to reply then change rooms
|
||||
// this can happen when performing a search across all rooms
|
||||
if (payload.event && payload.event.getRoomId() !== this._state.roomId) {
|
||||
if (payload.event && payload.event.getRoomId() !== this.state.roomId) {
|
||||
dis.dispatch({
|
||||
action: 'view_room',
|
||||
room_id: payload.event.getRoomId(),
|
||||
replyingToEvent: payload.event,
|
||||
});
|
||||
} else {
|
||||
this._setState({
|
||||
this.setState({
|
||||
replyingToEvent: payload.event,
|
||||
});
|
||||
}
|
||||
@ -149,14 +161,14 @@ class RoomViewStore extends Store {
|
||||
case 'open_room_settings': {
|
||||
const RoomSettingsDialog = sdk.getComponent("dialogs.RoomSettingsDialog");
|
||||
Modal.createTrackedDialog('Room settings', '', RoomSettingsDialog, {
|
||||
roomId: payload.room_id || this._state.roomId,
|
||||
roomId: payload.room_id || this.state.roomId,
|
||||
}, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async _viewRoom(payload) {
|
||||
private async viewRoom(payload: ActionPayload) {
|
||||
if (payload.room_id) {
|
||||
const newState = {
|
||||
roomId: payload.room_id,
|
||||
@ -181,18 +193,18 @@ class RoomViewStore extends Store {
|
||||
newState.replyingToEvent = payload.replyingToEvent;
|
||||
}
|
||||
|
||||
if (this._state.forwardingEvent) {
|
||||
if (this.state.forwardingEvent) {
|
||||
dis.dispatch({
|
||||
action: 'send_event',
|
||||
room_id: newState.roomId,
|
||||
event: this._state.forwardingEvent,
|
||||
event: this.state.forwardingEvent,
|
||||
});
|
||||
}
|
||||
|
||||
this._setState(newState);
|
||||
this.setState(newState);
|
||||
|
||||
if (payload.auto_join) {
|
||||
this._joinRoom(payload);
|
||||
this.joinRoom(payload);
|
||||
}
|
||||
} else if (payload.room_alias) {
|
||||
// Try the room alias to room ID navigation cache first to avoid
|
||||
@ -201,7 +213,7 @@ class RoomViewStore extends Store {
|
||||
if (!roomId) {
|
||||
// Room alias cache miss, so let's ask the homeserver. Resolve the alias
|
||||
// and then do a second dispatch with the room ID acquired.
|
||||
this._setState({
|
||||
this.setState({
|
||||
roomId: null,
|
||||
initialEventId: null,
|
||||
initialEventPixelOffset: null,
|
||||
@ -238,8 +250,8 @@ class RoomViewStore extends Store {
|
||||
}
|
||||
}
|
||||
|
||||
_viewRoomError(payload) {
|
||||
this._setState({
|
||||
private viewRoomError(payload: ActionPayload) {
|
||||
this.setState({
|
||||
roomId: payload.room_id,
|
||||
roomAlias: payload.room_alias,
|
||||
roomLoading: false,
|
||||
@ -247,12 +259,12 @@ class RoomViewStore extends Store {
|
||||
});
|
||||
}
|
||||
|
||||
_joinRoom(payload) {
|
||||
this._setState({
|
||||
private joinRoom(payload: ActionPayload) {
|
||||
this.setState({
|
||||
joining: true,
|
||||
});
|
||||
MatrixClientPeg.get().joinRoom(
|
||||
this._state.roomAlias || this._state.roomId, payload.opts,
|
||||
this.state.roomAlias || this.state.roomId, payload.opts,
|
||||
).then(() => {
|
||||
// We do *not* clear the 'joining' flag because the Room object and/or our 'joined' member event may not
|
||||
// have come down the sync stream yet, and that's the point at which we'd consider the user joined to the
|
||||
@ -273,7 +285,7 @@ class RoomViewStore extends Store {
|
||||
{_t("Please contact your homeserver administrator.")}
|
||||
</div>;
|
||||
} else if (err.httpStatus === 404) {
|
||||
const invitingUserId = this._getInvitingUserId(this._state.roomId);
|
||||
const invitingUserId = this.getInvitingUserId(this.state.roomId);
|
||||
// only provide a better error message for invites
|
||||
if (invitingUserId) {
|
||||
// if the inviting user is on the same HS, there can only be one cause: they left.
|
||||
@ -292,7 +304,7 @@ class RoomViewStore extends Store {
|
||||
});
|
||||
}
|
||||
|
||||
_getInvitingUserId(roomId) {
|
||||
private getInvitingUserId(roomId: string): string {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const room = cli.getRoom(roomId);
|
||||
if (room && room.getMyMembership() === "invite") {
|
||||
@ -302,45 +314,45 @@ class RoomViewStore extends Store {
|
||||
}
|
||||
}
|
||||
|
||||
_joinRoomError(payload) {
|
||||
this._setState({
|
||||
private joinRoomError(payload: ActionPayload) {
|
||||
this.setState({
|
||||
joining: false,
|
||||
joinError: payload.err,
|
||||
});
|
||||
}
|
||||
|
||||
reset() {
|
||||
this._state = Object.assign({}, INITIAL_STATE);
|
||||
public reset() {
|
||||
this.state = Object.assign({}, INITIAL_STATE);
|
||||
}
|
||||
|
||||
// The room ID of the room currently being viewed
|
||||
getRoomId() {
|
||||
return this._state.roomId;
|
||||
public getRoomId() {
|
||||
return this.state.roomId;
|
||||
}
|
||||
|
||||
// The event to scroll to when the room is first viewed
|
||||
getInitialEventId() {
|
||||
return this._state.initialEventId;
|
||||
public getInitialEventId() {
|
||||
return this.state.initialEventId;
|
||||
}
|
||||
|
||||
// Whether to highlight the initial event
|
||||
isInitialEventHighlighted() {
|
||||
return this._state.isInitialEventHighlighted;
|
||||
public isInitialEventHighlighted() {
|
||||
return this.state.isInitialEventHighlighted;
|
||||
}
|
||||
|
||||
// The room alias of the room (or null if not originally specified in view_room)
|
||||
getRoomAlias() {
|
||||
return this._state.roomAlias;
|
||||
public getRoomAlias() {
|
||||
return this.state.roomAlias;
|
||||
}
|
||||
|
||||
// Whether the current room is loading (true whilst resolving an alias)
|
||||
isRoomLoading() {
|
||||
return this._state.roomLoading;
|
||||
public isRoomLoading() {
|
||||
return this.state.roomLoading;
|
||||
}
|
||||
|
||||
// Any error that has occurred during loading
|
||||
getRoomLoadError() {
|
||||
return this._state.roomLoadError;
|
||||
public getRoomLoadError() {
|
||||
return this.state.roomLoadError;
|
||||
}
|
||||
|
||||
// True if we're expecting the user to be joined to the room currently being
|
||||
@ -366,27 +378,27 @@ class RoomViewStore extends Store {
|
||||
// // show join prompt
|
||||
// }
|
||||
// }
|
||||
isJoining() {
|
||||
return this._state.joining;
|
||||
public isJoining() {
|
||||
return this.state.joining;
|
||||
}
|
||||
|
||||
// Any error that has occurred during joining
|
||||
getJoinError() {
|
||||
return this._state.joinError;
|
||||
public getJoinError() {
|
||||
return this.state.joinError;
|
||||
}
|
||||
|
||||
// The mxEvent if one is about to be forwarded
|
||||
getForwardingEvent() {
|
||||
return this._state.forwardingEvent;
|
||||
public getForwardingEvent() {
|
||||
return this.state.forwardingEvent;
|
||||
}
|
||||
|
||||
// The mxEvent if one is currently being replied to/quoted
|
||||
getQuotingEvent() {
|
||||
return this._state.replyingToEvent;
|
||||
public getQuotingEvent() {
|
||||
return this.state.replyingToEvent;
|
||||
}
|
||||
|
||||
shouldPeek() {
|
||||
return this._state.shouldPeek;
|
||||
public shouldPeek() {
|
||||
return this.state.shouldPeek;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user