2015-11-30 19:55:00 +03:00
|
|
|
|
/*
|
2016-01-07 07:06:39 +03:00
|
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
2018-08-13 15:49:22 +03:00
|
|
|
|
Copyright 2017, 2018 Vector Creations Ltd
|
2015-11-30 19:55:00 +03:00
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-06-30 19:07:28 +03:00
|
|
|
|
import SettingsStore from "../../../settings/SettingsStore";
|
2019-02-11 18:17:15 +03:00
|
|
|
|
import Timer from "../../../utils/Timer";
|
2019-09-06 17:04:46 +03:00
|
|
|
|
import React from "react";
|
|
|
|
|
import ReactDOM from "react-dom";
|
|
|
|
|
import createReactClass from 'create-react-class';
|
2017-12-26 04:03:18 +03:00
|
|
|
|
import PropTypes from 'prop-types';
|
2020-01-10 00:16:32 +03:00
|
|
|
|
import * as utils from "matrix-js-sdk/src/utils";
|
2017-11-13 22:19:33 +03:00
|
|
|
|
import { _t } from '../../../languageHandler';
|
2019-12-21 00:13:46 +03:00
|
|
|
|
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
2019-12-13 05:33:08 +03:00
|
|
|
|
import rate_limited_func from "../../../ratelimitedfunc";
|
2018-01-26 00:16:03 +03:00
|
|
|
|
import * as Rooms from '../../../Rooms';
|
2016-10-02 14:57:45 +03:00
|
|
|
|
import DMRoomMap from '../../../utils/DMRoomMap';
|
2018-01-03 14:33:59 +03:00
|
|
|
|
import TagOrderStore from '../../../stores/TagOrderStore';
|
2020-02-25 05:43:11 +03:00
|
|
|
|
import RoomListStore, {TAG_DM} from '../../../stores/RoomListStore';
|
2019-02-05 20:38:36 +03:00
|
|
|
|
import CustomRoomTagStore from '../../../stores/CustomRoomTagStore';
|
2018-05-01 13:18:45 +03:00
|
|
|
|
import GroupStore from '../../../stores/GroupStore';
|
2018-11-02 17:27:17 +03:00
|
|
|
|
import RoomSubList from '../../structures/RoomSubList';
|
2018-10-18 16:19:45 +03:00
|
|
|
|
import ResizeHandle from '../elements/ResizeHandle';
|
2019-12-21 00:41:07 +03:00
|
|
|
|
import CallHandler from "../../../CallHandler";
|
|
|
|
|
import dis from "../../../dispatcher";
|
|
|
|
|
import * as sdk from "../../../index";
|
|
|
|
|
import * as Receipt from "../../../utils/Receipt";
|
2019-02-05 20:38:36 +03:00
|
|
|
|
import {Resizer} from '../../../resizer';
|
2019-01-24 17:43:49 +03:00
|
|
|
|
import {Layout, Distributor} from '../../../resizer/distributors/roomsublist2';
|
2020-01-20 23:31:36 +03:00
|
|
|
|
import {RovingTabIndexProvider} from "../../../accessibility/RovingTabIndex";
|
2019-12-21 00:41:07 +03:00
|
|
|
|
|
2017-04-26 20:59:16 +03:00
|
|
|
|
const HIDE_CONFERENCE_CHANS = true;
|
2018-08-06 20:00:40 +03:00
|
|
|
|
const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/;
|
2019-02-11 18:17:15 +03:00
|
|
|
|
const HOVER_MOVE_TIMEOUT = 1000;
|
2017-04-26 20:59:16 +03:00
|
|
|
|
|
2018-08-06 18:58:54 +03:00
|
|
|
|
function labelForTagName(tagName) {
|
|
|
|
|
if (tagName.startsWith('u.')) return tagName.slice(2);
|
|
|
|
|
return tagName;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-20 03:45:24 +03:00
|
|
|
|
export default createReactClass({
|
2015-11-30 19:55:00 +03:00
|
|
|
|
displayName: 'RoomList',
|
|
|
|
|
|
|
|
|
|
propTypes: {
|
2017-12-26 04:03:18 +03:00
|
|
|
|
ConferenceHandler: PropTypes.any,
|
|
|
|
|
collapsed: PropTypes.bool.isRequired,
|
|
|
|
|
searchFilter: PropTypes.string,
|
2015-11-30 19:55:00 +03:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getInitialState: function() {
|
2018-11-26 18:46:57 +03:00
|
|
|
|
|
2019-02-11 18:17:15 +03:00
|
|
|
|
this._hoverClearTimer = null;
|
2018-12-14 19:06:51 +03:00
|
|
|
|
this._subListRefs = {
|
|
|
|
|
// key => RoomSubList ref
|
|
|
|
|
};
|
|
|
|
|
|
2018-11-26 18:46:57 +03:00
|
|
|
|
const sizesJson = window.localStorage.getItem("mx_roomlist_sizes");
|
2018-12-03 12:39:31 +03:00
|
|
|
|
const collapsedJson = window.localStorage.getItem("mx_roomlist_collapsed");
|
2018-11-26 18:46:57 +03:00
|
|
|
|
this.subListSizes = sizesJson ? JSON.parse(sizesJson) : {};
|
2018-12-03 12:39:31 +03:00
|
|
|
|
this.collapsedState = collapsedJson ? JSON.parse(collapsedJson) : {};
|
2019-01-24 17:43:49 +03:00
|
|
|
|
this._layoutSections = [];
|
|
|
|
|
|
2019-01-28 20:28:04 +03:00
|
|
|
|
const unfilteredOptions = {
|
2019-01-29 19:21:14 +03:00
|
|
|
|
allowWhitespace: false,
|
2019-01-28 20:02:36 +03:00
|
|
|
|
handleHeight: 1,
|
|
|
|
|
};
|
2019-01-28 20:28:04 +03:00
|
|
|
|
this._unfilteredlayout = new Layout((key, size) => {
|
2019-01-24 17:43:49 +03:00
|
|
|
|
const subList = this._subListRefs[key];
|
|
|
|
|
if (subList) {
|
|
|
|
|
subList.setHeight(size);
|
|
|
|
|
}
|
|
|
|
|
// update overflow indicators
|
|
|
|
|
this._checkSubListsOverflow();
|
2019-01-28 16:35:04 +03:00
|
|
|
|
// don't store height for collapsed sublists
|
2019-02-11 18:27:29 +03:00
|
|
|
|
if (!this.collapsedState[key]) {
|
2019-01-28 16:35:04 +03:00
|
|
|
|
this.subListSizes[key] = size;
|
|
|
|
|
window.localStorage.setItem("mx_roomlist_sizes",
|
|
|
|
|
JSON.stringify(this.subListSizes));
|
|
|
|
|
}
|
2019-01-28 20:28:04 +03:00
|
|
|
|
}, this.subListSizes, this.collapsedState, unfilteredOptions);
|
|
|
|
|
|
|
|
|
|
this._filteredLayout = new Layout((key, size) => {
|
|
|
|
|
const subList = this._subListRefs[key];
|
|
|
|
|
if (subList) {
|
|
|
|
|
subList.setHeight(size);
|
|
|
|
|
}
|
|
|
|
|
}, null, null, {
|
|
|
|
|
allowWhitespace: false,
|
|
|
|
|
handleHeight: 0,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this._layout = this._unfilteredlayout;
|
2019-01-24 17:43:49 +03:00
|
|
|
|
|
2015-11-30 19:55:00 +03:00
|
|
|
|
return {
|
2015-12-18 18:13:59 +03:00
|
|
|
|
isLoadingLeftRooms: false,
|
2017-04-26 20:59:16 +03:00
|
|
|
|
totalRoomCount: null,
|
2015-11-30 19:55:00 +03:00
|
|
|
|
lists: {},
|
2018-12-06 21:45:58 +03:00
|
|
|
|
incomingCallTag: null,
|
2015-12-17 05:49:09 +03:00
|
|
|
|
incomingCall: null,
|
2017-11-29 19:35:16 +03:00
|
|
|
|
selectedTags: [],
|
2019-01-03 23:57:20 +03:00
|
|
|
|
hover: false,
|
2019-02-05 20:38:36 +03:00
|
|
|
|
customTags: CustomRoomTagStore.getTags(),
|
2017-01-20 17:22:27 +03:00
|
|
|
|
};
|
2015-11-30 19:55:00 +03:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
componentWillMount: function() {
|
2017-05-18 19:33:32 +03:00
|
|
|
|
this.mounted = false;
|
|
|
|
|
|
2017-10-11 19:56:17 +03:00
|
|
|
|
const cli = MatrixClientPeg.get();
|
2017-12-05 14:25:30 +03:00
|
|
|
|
|
2015-11-30 19:55:00 +03:00
|
|
|
|
cli.on("Room", this.onRoom);
|
2015-12-16 19:27:46 +03:00
|
|
|
|
cli.on("deleteRoom", this.onDeleteRoom);
|
2017-04-19 00:36:54 +03:00
|
|
|
|
cli.on("Room.receipt", this.onRoomReceipt);
|
2015-11-30 19:55:00 +03:00
|
|
|
|
cli.on("RoomMember.name", this.onRoomMemberName);
|
2017-09-12 16:47:26 +03:00
|
|
|
|
cli.on("Event.decrypted", this.onEventDecrypted);
|
2016-09-07 19:46:45 +03:00
|
|
|
|
cli.on("accountData", this.onAccountData);
|
2017-09-21 18:28:49 +03:00
|
|
|
|
cli.on("Group.myMembership", this._onGroupMyMembership);
|
2019-01-11 01:43:22 +03:00
|
|
|
|
cli.on("RoomState.events", this.onRoomStateEvents);
|
2015-11-30 19:55:00 +03:00
|
|
|
|
|
2017-12-14 19:34:49 +03:00
|
|
|
|
const dmRoomMap = DMRoomMap.shared();
|
2017-12-14 19:17:06 +03:00
|
|
|
|
// A map between tags which are group IDs and the room IDs of rooms that should be kept
|
|
|
|
|
// in the room list when filtering by that tag.
|
2017-12-15 20:29:06 +03:00
|
|
|
|
this._visibleRoomsForGroup = {
|
2017-12-14 19:17:06 +03:00
|
|
|
|
// $groupId: [$roomId1, $roomId2, ...],
|
|
|
|
|
};
|
2018-01-05 15:33:26 +03:00
|
|
|
|
// All rooms that should be kept in the room list when filtering.
|
|
|
|
|
// By default, show all rooms.
|
2018-08-22 14:01:29 +03:00
|
|
|
|
this._visibleRooms = MatrixClientPeg.get().getVisibleRooms();
|
2018-05-01 16:24:58 +03:00
|
|
|
|
|
|
|
|
|
// Listen to updates to group data. RoomList cares about members and rooms in order
|
|
|
|
|
// to filter the room list when group tags are selected.
|
|
|
|
|
this._groupStoreToken = GroupStore.registerListener(null, () => {
|
2018-01-03 17:12:28 +03:00
|
|
|
|
(TagOrderStore.getOrderedTags() || []).forEach((tag) => {
|
2018-05-01 13:18:45 +03:00
|
|
|
|
if (tag[0] !== '+') {
|
2017-11-29 19:35:16 +03:00
|
|
|
|
return;
|
|
|
|
|
}
|
2018-05-01 16:24:58 +03:00
|
|
|
|
// This group's rooms or members may have updated, update rooms for its tag
|
|
|
|
|
this.updateVisibleRoomsForTag(dmRoomMap, tag);
|
|
|
|
|
this.updateVisibleRooms();
|
2017-11-29 19:35:16 +03:00
|
|
|
|
});
|
2018-05-01 16:24:58 +03:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this._tagStoreToken = TagOrderStore.addListener(() => {
|
|
|
|
|
// Filters themselves have changed
|
2017-12-15 20:29:06 +03:00
|
|
|
|
this.updateVisibleRooms();
|
2017-11-29 19:35:16 +03:00
|
|
|
|
});
|
|
|
|
|
|
2018-01-26 00:16:03 +03:00
|
|
|
|
this._roomListStoreToken = RoomListStore.addListener(() => {
|
|
|
|
|
this._delayedRefreshRoomList();
|
|
|
|
|
});
|
|
|
|
|
|
2019-02-07 21:04:30 +03:00
|
|
|
|
|
|
|
|
|
if (SettingsStore.isFeatureEnabled("feature_custom_tags")) {
|
|
|
|
|
this._customTagStoreToken = CustomRoomTagStore.addListener(() => {
|
|
|
|
|
this.setState({
|
|
|
|
|
customTags: CustomRoomTagStore.getTags(),
|
|
|
|
|
});
|
2019-02-05 20:38:36 +03:00
|
|
|
|
});
|
2019-02-07 21:04:30 +03:00
|
|
|
|
}
|
2019-02-05 20:38:36 +03:00
|
|
|
|
|
2017-04-26 20:59:16 +03:00
|
|
|
|
this.refreshRoomList();
|
|
|
|
|
|
|
|
|
|
// order of the sublists
|
|
|
|
|
//this.listOrder = [];
|
|
|
|
|
|
|
|
|
|
// loop count to stop a stack overflow if the user keeps waggling the
|
|
|
|
|
// mouse for >30s in a row, or if running under mocha
|
2017-10-11 19:56:17 +03:00
|
|
|
|
this._delayedRefreshRoomListLoopCount = 0;
|
2015-11-30 19:55:00 +03:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
componentDidMount: function() {
|
|
|
|
|
this.dispatcherRef = dis.register(this.onAction);
|
2018-11-26 18:46:57 +03:00
|
|
|
|
const cfg = {
|
2019-02-04 21:38:31 +03:00
|
|
|
|
getLayout: () => this._layout,
|
2018-11-26 18:46:57 +03:00
|
|
|
|
};
|
2019-01-24 17:43:49 +03:00
|
|
|
|
this.resizer = new Resizer(this.resizeContainer, Distributor, cfg);
|
2018-10-18 16:51:58 +03:00
|
|
|
|
this.resizer.setClassNames({
|
|
|
|
|
handle: "mx_ResizeHandle",
|
|
|
|
|
vertical: "mx_ResizeHandle_vertical",
|
2019-10-14 18:08:56 +03:00
|
|
|
|
reverse: "mx_ResizeHandle_reverse",
|
2018-10-18 16:51:58 +03:00
|
|
|
|
});
|
2019-01-24 17:43:49 +03:00
|
|
|
|
this._layout.update(
|
|
|
|
|
this._layoutSections,
|
2019-01-24 18:45:26 +03:00
|
|
|
|
this.resizeContainer && this.resizeContainer.offsetHeight,
|
2019-01-24 17:43:49 +03:00
|
|
|
|
);
|
2018-12-18 16:26:33 +03:00
|
|
|
|
this._checkSubListsOverflow();
|
2017-05-18 19:33:32 +03:00
|
|
|
|
|
2018-10-18 16:51:58 +03:00
|
|
|
|
this.resizer.attach();
|
2019-03-28 19:56:12 +03:00
|
|
|
|
if (this.props.resizeNotifier) {
|
|
|
|
|
this.props.resizeNotifier.on("leftPanelResized", this.onResize);
|
|
|
|
|
}
|
2017-05-18 19:33:32 +03:00
|
|
|
|
this.mounted = true;
|
2015-11-30 19:55:00 +03:00
|
|
|
|
},
|
|
|
|
|
|
2018-12-14 19:06:51 +03:00
|
|
|
|
componentDidUpdate: function(prevProps) {
|
2019-01-28 20:28:04 +03:00
|
|
|
|
let forceLayoutUpdate = false;
|
2016-09-15 17:33:08 +03:00
|
|
|
|
this._repositionIncomingCallBox(undefined, false);
|
2019-01-28 20:28:04 +03:00
|
|
|
|
if (!this.props.searchFilter && prevProps.searchFilter) {
|
|
|
|
|
this._layout = this._unfilteredlayout;
|
|
|
|
|
forceLayoutUpdate = true;
|
|
|
|
|
} else if (this.props.searchFilter && !prevProps.searchFilter) {
|
|
|
|
|
this._layout = this._filteredLayout;
|
|
|
|
|
forceLayoutUpdate = true;
|
|
|
|
|
}
|
2019-01-24 17:43:49 +03:00
|
|
|
|
this._layout.update(
|
|
|
|
|
this._layoutSections,
|
|
|
|
|
this.resizeContainer && this.resizeContainer.clientHeight,
|
2019-01-28 20:28:04 +03:00
|
|
|
|
forceLayoutUpdate,
|
2019-01-24 17:43:49 +03:00
|
|
|
|
);
|
2019-01-28 20:28:04 +03:00
|
|
|
|
this._checkSubListsOverflow();
|
2016-08-25 21:46:01 +03:00
|
|
|
|
},
|
|
|
|
|
|
2015-11-30 19:55:00 +03:00
|
|
|
|
onAction: function(payload) {
|
|
|
|
|
switch (payload.action) {
|
|
|
|
|
case 'view_tooltip':
|
|
|
|
|
this.tooltip = payload.tooltip;
|
2015-12-17 05:49:09 +03:00
|
|
|
|
break;
|
|
|
|
|
case 'call_state':
|
|
|
|
|
var call = CallHandler.getCall(payload.room_id);
|
|
|
|
|
if (call && call.call_state === 'ringing') {
|
|
|
|
|
this.setState({
|
2017-10-11 19:56:17 +03:00
|
|
|
|
incomingCall: call,
|
2018-12-06 21:45:58 +03:00
|
|
|
|
incomingCallTag: this.getTagNameForRoomId(payload.room_id),
|
2015-12-17 05:49:09 +03:00
|
|
|
|
});
|
|
|
|
|
this._repositionIncomingCallBox(undefined, true);
|
2017-10-11 19:56:17 +03:00
|
|
|
|
} else {
|
2015-12-17 05:49:09 +03:00
|
|
|
|
this.setState({
|
2017-10-11 19:56:17 +03:00
|
|
|
|
incomingCall: null,
|
2018-12-06 21:45:58 +03:00
|
|
|
|
incomingCallTag: null,
|
2016-04-15 19:55:00 +03:00
|
|
|
|
});
|
2015-12-17 05:49:09 +03:00
|
|
|
|
}
|
|
|
|
|
break;
|
2015-11-30 19:55:00 +03:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
componentWillUnmount: function() {
|
2017-05-18 19:33:32 +03:00
|
|
|
|
this.mounted = false;
|
|
|
|
|
|
2015-11-30 19:55:00 +03:00
|
|
|
|
dis.unregister(this.dispatcherRef);
|
|
|
|
|
if (MatrixClientPeg.get()) {
|
|
|
|
|
MatrixClientPeg.get().removeListener("Room", this.onRoom);
|
2016-02-04 18:55:24 +03:00
|
|
|
|
MatrixClientPeg.get().removeListener("deleteRoom", this.onDeleteRoom);
|
2017-04-19 00:36:54 +03:00
|
|
|
|
MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt);
|
2016-02-04 18:55:24 +03:00
|
|
|
|
MatrixClientPeg.get().removeListener("RoomMember.name", this.onRoomMemberName);
|
2017-09-12 16:47:26 +03:00
|
|
|
|
MatrixClientPeg.get().removeListener("Event.decrypted", this.onEventDecrypted);
|
2016-09-07 19:46:45 +03:00
|
|
|
|
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
|
2017-09-21 18:28:49 +03:00
|
|
|
|
MatrixClientPeg.get().removeListener("Group.myMembership", this._onGroupMyMembership);
|
2019-01-11 01:43:22 +03:00
|
|
|
|
MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
|
2015-11-30 19:55:00 +03:00
|
|
|
|
}
|
2019-03-28 19:56:12 +03:00
|
|
|
|
|
|
|
|
|
if (this.props.resizeNotifier) {
|
|
|
|
|
this.props.resizeNotifier.removeListener("leftPanelResized", this.onResize);
|
|
|
|
|
}
|
2019-03-12 20:00:05 +03:00
|
|
|
|
|
2017-11-29 19:35:16 +03:00
|
|
|
|
|
2018-01-03 14:33:59 +03:00
|
|
|
|
if (this._tagStoreToken) {
|
|
|
|
|
this._tagStoreToken.remove();
|
2017-11-29 19:35:16 +03:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-15 14:23:00 +03:00
|
|
|
|
if (this._roomListStoreToken) {
|
|
|
|
|
this._roomListStoreToken.remove();
|
|
|
|
|
}
|
2019-02-06 17:24:17 +03:00
|
|
|
|
if (this._customTagStoreToken) {
|
|
|
|
|
this._customTagStoreToken.remove();
|
|
|
|
|
}
|
2018-02-15 14:23:00 +03:00
|
|
|
|
|
2018-05-01 13:18:45 +03:00
|
|
|
|
// NB: GroupStore is not a Flux.Store
|
2018-05-01 13:38:57 +03:00
|
|
|
|
if (this._groupStoreToken) {
|
|
|
|
|
this._groupStoreToken.unregister();
|
|
|
|
|
}
|
2017-12-15 17:12:21 +03:00
|
|
|
|
|
2016-08-10 15:39:47 +03:00
|
|
|
|
// cancel any pending calls to the rate_limited_funcs
|
|
|
|
|
this._delayedRefreshRoomList.cancelPendingCall();
|
2015-11-30 19:55:00 +03:00
|
|
|
|
},
|
|
|
|
|
|
2019-03-12 20:00:05 +03:00
|
|
|
|
|
|
|
|
|
onResize: function() {
|
2019-01-25 20:48:25 +03:00
|
|
|
|
if (this.mounted && this._layout && this.resizeContainer &&
|
|
|
|
|
Array.isArray(this._layoutSections)
|
|
|
|
|
) {
|
|
|
|
|
this._layout.update(
|
|
|
|
|
this._layoutSections,
|
2019-03-12 20:00:05 +03:00
|
|
|
|
this.resizeContainer.offsetHeight,
|
2019-01-25 20:48:25 +03:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
},
|
2015-11-30 19:55:00 +03:00
|
|
|
|
|
|
|
|
|
onRoom: function(room) {
|
2018-01-05 15:33:26 +03:00
|
|
|
|
this.updateVisibleRooms();
|
2015-11-30 19:55:00 +03:00
|
|
|
|
},
|
|
|
|
|
|
2019-01-11 01:43:22 +03:00
|
|
|
|
onRoomStateEvents: function(ev, state) {
|
|
|
|
|
if (ev.getType() === "m.room.create" || ev.getType() === "m.room.tombstone") {
|
|
|
|
|
this.updateVisibleRooms();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2015-12-16 19:27:46 +03:00
|
|
|
|
onDeleteRoom: function(roomId) {
|
2018-01-05 15:33:26 +03:00
|
|
|
|
this.updateVisibleRooms();
|
2015-12-16 19:27:46 +03:00
|
|
|
|
},
|
|
|
|
|
|
2016-08-30 13:55:51 +03:00
|
|
|
|
onArchivedHeaderClick: function(isHidden, scrollToPosition) {
|
2015-12-18 14:55:43 +03:00
|
|
|
|
if (!isHidden) {
|
2017-10-11 19:56:17 +03:00
|
|
|
|
const self = this;
|
2015-12-18 18:13:59 +03:00
|
|
|
|
this.setState({ isLoadingLeftRooms: true });
|
2015-12-18 14:55:43 +03:00
|
|
|
|
// we don't care about the response since it comes down via "Room"
|
|
|
|
|
// events.
|
|
|
|
|
MatrixClientPeg.get().syncLeftRooms().catch(function(err) {
|
|
|
|
|
console.error("Failed to sync left rooms: %s", err);
|
|
|
|
|
console.error(err);
|
2015-12-18 18:13:59 +03:00
|
|
|
|
}).finally(function() {
|
|
|
|
|
self.setState({ isLoadingLeftRooms: false });
|
2015-12-18 14:55:43 +03:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2015-12-18 20:51:17 +03:00
|
|
|
|
onRoomReceipt: function(receiptEvent, room) {
|
|
|
|
|
// because if we read a notification, it will affect notification count
|
2016-01-07 13:38:44 +03:00
|
|
|
|
// only bother updating if there's a receipt from us
|
2016-09-09 18:59:59 +03:00
|
|
|
|
if (Receipt.findReadReceiptFromUserId(receiptEvent, MatrixClientPeg.get().credentials.userId)) {
|
2017-05-16 18:11:01 +03:00
|
|
|
|
this._delayedRefreshRoomList();
|
2016-01-07 13:38:44 +03:00
|
|
|
|
}
|
2015-12-18 20:51:17 +03:00
|
|
|
|
},
|
|
|
|
|
|
2015-11-30 19:55:00 +03:00
|
|
|
|
onRoomMemberName: function(ev, member) {
|
2017-05-16 18:11:01 +03:00
|
|
|
|
this._delayedRefreshRoomList();
|
2015-12-18 18:13:59 +03:00
|
|
|
|
},
|
|
|
|
|
|
2017-09-12 16:47:26 +03:00
|
|
|
|
onEventDecrypted: function(ev) {
|
|
|
|
|
// An event being decrypted may mean we need to re-order the room list
|
|
|
|
|
this._delayedRefreshRoomList();
|
|
|
|
|
},
|
|
|
|
|
|
2016-09-07 19:46:45 +03:00
|
|
|
|
onAccountData: function(ev) {
|
|
|
|
|
if (ev.getType() == 'm.direct') {
|
2017-04-24 17:44:45 +03:00
|
|
|
|
this._delayedRefreshRoomList();
|
2017-04-20 03:12:57 +03:00
|
|
|
|
}
|
2016-09-07 19:46:45 +03:00
|
|
|
|
},
|
|
|
|
|
|
2017-09-21 18:28:49 +03:00
|
|
|
|
_onGroupMyMembership: function(group) {
|
|
|
|
|
this.forceUpdate();
|
|
|
|
|
},
|
|
|
|
|
|
2019-02-11 18:17:15 +03:00
|
|
|
|
onMouseMove: async function(ev) {
|
|
|
|
|
if (!this._hoverClearTimer) {
|
|
|
|
|
this.setState({hover: true});
|
|
|
|
|
this._hoverClearTimer = new Timer(HOVER_MOVE_TIMEOUT);
|
|
|
|
|
this._hoverClearTimer.start();
|
|
|
|
|
let finished = true;
|
|
|
|
|
try {
|
|
|
|
|
await this._hoverClearTimer.finished();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
finished = false;
|
|
|
|
|
}
|
|
|
|
|
this._hoverClearTimer = null;
|
|
|
|
|
if (finished) {
|
|
|
|
|
this.setState({hover: false});
|
|
|
|
|
this._delayedRefreshRoomList();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this._hoverClearTimer.restart();
|
|
|
|
|
}
|
2019-01-03 23:57:20 +03:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onMouseLeave: function(ev) {
|
2019-02-11 18:17:15 +03:00
|
|
|
|
if (this._hoverClearTimer) {
|
|
|
|
|
this._hoverClearTimer.abort();
|
|
|
|
|
this._hoverClearTimer = null;
|
|
|
|
|
}
|
2019-01-03 23:57:20 +03:00
|
|
|
|
this.setState({hover: false});
|
|
|
|
|
|
|
|
|
|
// Refresh the room list just in case the user missed something.
|
|
|
|
|
this._delayedRefreshRoomList();
|
|
|
|
|
},
|
|
|
|
|
|
2019-12-13 05:33:08 +03:00
|
|
|
|
_delayedRefreshRoomList: rate_limited_func(function() {
|
2017-05-16 18:11:01 +03:00
|
|
|
|
this.refreshRoomList();
|
2016-02-04 21:06:24 +03:00
|
|
|
|
}, 500),
|
2015-11-30 19:55:00 +03:00
|
|
|
|
|
2017-12-15 20:21:20 +03:00
|
|
|
|
// Update which rooms and users should appear in RoomList for a given group tag
|
2017-12-15 20:29:06 +03:00
|
|
|
|
updateVisibleRoomsForTag: function(dmRoomMap, tag) {
|
2017-11-29 19:35:16 +03:00
|
|
|
|
if (!this.mounted) return;
|
2017-12-15 17:23:35 +03:00
|
|
|
|
// For now, only handle group tags
|
2018-05-01 13:18:45 +03:00
|
|
|
|
if (tag[0] !== '+') return;
|
2017-12-15 17:23:35 +03:00
|
|
|
|
|
2017-12-15 20:29:06 +03:00
|
|
|
|
this._visibleRoomsForGroup[tag] = [];
|
2018-05-01 13:18:45 +03:00
|
|
|
|
GroupStore.getGroupRooms(tag).forEach((room) => this._visibleRoomsForGroup[tag].push(room.roomId));
|
|
|
|
|
GroupStore.getGroupMembers(tag).forEach((member) => {
|
2017-12-15 17:23:35 +03:00
|
|
|
|
if (member.userId === MatrixClientPeg.get().credentials.userId) return;
|
|
|
|
|
dmRoomMap.getDMRoomsForUserId(member.userId).forEach(
|
2017-12-15 20:29:06 +03:00
|
|
|
|
(roomId) => this._visibleRoomsForGroup[tag].push(roomId),
|
2017-12-15 17:23:35 +03:00
|
|
|
|
);
|
2017-12-05 14:25:30 +03:00
|
|
|
|
});
|
2017-12-15 17:23:35 +03:00
|
|
|
|
// TODO: Check if room has been tagged to the group by the user
|
|
|
|
|
},
|
2017-11-29 19:35:16 +03:00
|
|
|
|
|
2017-12-15 20:30:21 +03:00
|
|
|
|
// Update which rooms and users should appear according to which tags are selected
|
2017-12-15 20:29:06 +03:00
|
|
|
|
updateVisibleRooms: function() {
|
2018-01-05 13:23:20 +03:00
|
|
|
|
const selectedTags = TagOrderStore.getSelectedTags();
|
|
|
|
|
const visibleGroupRooms = [];
|
2018-01-04 14:50:33 +03:00
|
|
|
|
selectedTags.forEach((tag) => {
|
2017-12-15 20:29:06 +03:00
|
|
|
|
(this._visibleRoomsForGroup[tag] || []).forEach(
|
2018-01-05 13:23:20 +03:00
|
|
|
|
(roomId) => visibleGroupRooms.push(roomId),
|
2017-11-29 19:35:16 +03:00
|
|
|
|
);
|
|
|
|
|
});
|
2017-12-05 14:25:30 +03:00
|
|
|
|
|
2018-01-04 14:50:33 +03:00
|
|
|
|
// If there are any tags selected, constrain the rooms listed to the
|
|
|
|
|
// visible rooms as determined by visibleGroupRooms. Here, we
|
|
|
|
|
// de-duplicate and filter out rooms that the client doesn't know
|
|
|
|
|
// about (hence the Set and the null-guard on `room`).
|
|
|
|
|
if (selectedTags.length > 0) {
|
|
|
|
|
const roomSet = new Set();
|
|
|
|
|
visibleGroupRooms.forEach((roomId) => {
|
|
|
|
|
const room = MatrixClientPeg.get().getRoom(roomId);
|
|
|
|
|
if (room) {
|
|
|
|
|
roomSet.add(room);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
this._visibleRooms = Array.from(roomSet);
|
|
|
|
|
} else {
|
|
|
|
|
// Show all rooms
|
2018-08-22 14:01:29 +03:00
|
|
|
|
this._visibleRooms = MatrixClientPeg.get().getVisibleRooms();
|
2018-01-04 14:50:33 +03:00
|
|
|
|
}
|
2018-01-15 17:42:41 +03:00
|
|
|
|
this._delayedRefreshRoomList();
|
2017-11-29 19:35:16 +03:00
|
|
|
|
},
|
|
|
|
|
|
2015-11-30 19:55:00 +03:00
|
|
|
|
refreshRoomList: function() {
|
2019-01-03 23:57:20 +03:00
|
|
|
|
if (this.state.hover) {
|
|
|
|
|
// Don't re-sort the list if we're hovering over the list
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-26 20:59:16 +03:00
|
|
|
|
// TODO: ideally we'd calculate this once at start, and then maintain
|
|
|
|
|
// any changes to it incrementally, updating the appropriate sublists
|
|
|
|
|
// as needed.
|
|
|
|
|
// Alternatively we'd do something magical with Immutable.js or similar.
|
|
|
|
|
const lists = this.getRoomLists();
|
|
|
|
|
let totalRooms = 0;
|
|
|
|
|
for (const l of Object.values(lists)) {
|
|
|
|
|
totalRooms += l.length;
|
|
|
|
|
}
|
|
|
|
|
this.setState({
|
2018-01-26 00:16:03 +03:00
|
|
|
|
lists,
|
2017-04-26 20:59:16 +03:00
|
|
|
|
totalRoomCount: totalRooms,
|
2018-01-15 17:42:41 +03:00
|
|
|
|
// Do this here so as to not render every time the selected tags
|
|
|
|
|
// themselves change.
|
|
|
|
|
selectedTags: TagOrderStore.getSelectedTags(),
|
2018-12-18 16:26:33 +03:00
|
|
|
|
}, () => {
|
|
|
|
|
// we don't need to restore any size here, do we?
|
|
|
|
|
// i guess we could have triggered a new group to appear
|
|
|
|
|
// that already an explicit size the last time it appeared ...
|
|
|
|
|
this._checkSubListsOverflow();
|
2017-04-26 20:59:16 +03:00
|
|
|
|
});
|
2017-05-16 16:49:55 +03:00
|
|
|
|
|
2017-04-15 15:23:52 +03:00
|
|
|
|
// this._lastRefreshRoomListTs = Date.now();
|
2015-11-30 19:55:00 +03:00
|
|
|
|
},
|
|
|
|
|
|
2018-12-06 21:45:58 +03:00
|
|
|
|
getTagNameForRoomId: function(roomId) {
|
|
|
|
|
const lists = RoomListStore.getRoomLists();
|
|
|
|
|
for (const tagName of Object.keys(lists)) {
|
|
|
|
|
for (const room of lists[tagName]) {
|
|
|
|
|
// Should be impossible, but guard anyways.
|
|
|
|
|
if (!room) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const myUserId = MatrixClientPeg.get().getUserId();
|
|
|
|
|
if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(room, myUserId, this.props.ConferenceHandler)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (room.roomId === roomId) return tagName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
},
|
|
|
|
|
|
2015-11-30 19:55:00 +03:00
|
|
|
|
getRoomLists: function() {
|
2018-01-26 00:16:03 +03:00
|
|
|
|
const lists = RoomListStore.getRoomLists();
|
2015-11-30 19:55:00 +03:00
|
|
|
|
|
2018-01-26 00:16:03 +03:00
|
|
|
|
const filteredLists = {};
|
2018-01-03 20:12:31 +03:00
|
|
|
|
|
2018-02-06 12:55:58 +03:00
|
|
|
|
const isRoomVisible = {
|
|
|
|
|
// $roomId: true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this._visibleRooms.forEach((r) => {
|
|
|
|
|
isRoomVisible[r.roomId] = true;
|
|
|
|
|
});
|
|
|
|
|
|
2018-01-26 00:16:03 +03:00
|
|
|
|
Object.keys(lists).forEach((tagName) => {
|
2018-02-16 20:11:04 +03:00
|
|
|
|
const filteredRooms = lists[tagName].filter((taggedRoom) => {
|
2018-01-26 00:16:03 +03:00
|
|
|
|
// Somewhat impossible, but guard against it anyway
|
|
|
|
|
if (!taggedRoom) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-07-25 15:54:10 +03:00
|
|
|
|
const myUserId = MatrixClientPeg.get().getUserId();
|
|
|
|
|
if (HIDE_CONFERENCE_CHANS && Rooms.isConfCallRoom(taggedRoom, myUserId, this.props.ConferenceHandler)) {
|
2018-01-26 00:16:03 +03:00
|
|
|
|
return;
|
2016-08-11 18:45:19 +03:00
|
|
|
|
}
|
2017-04-18 04:43:29 +03:00
|
|
|
|
|
2018-02-12 21:35:13 +03:00
|
|
|
|
return Boolean(isRoomVisible[taggedRoom.roomId]);
|
2018-01-26 00:16:03 +03:00
|
|
|
|
});
|
2018-03-21 15:00:56 +03:00
|
|
|
|
|
2018-02-16 20:11:04 +03:00
|
|
|
|
if (filteredRooms.length > 0 || tagName.match(STANDARD_TAGS_REGEX)) {
|
|
|
|
|
filteredLists[tagName] = filteredRooms;
|
|
|
|
|
}
|
2018-01-26 00:16:03 +03:00
|
|
|
|
});
|
2017-04-26 20:59:16 +03:00
|
|
|
|
|
2018-01-26 00:16:03 +03:00
|
|
|
|
return filteredLists;
|
2015-11-30 19:55:00 +03:00
|
|
|
|
},
|
|
|
|
|
|
2015-12-17 05:49:09 +03:00
|
|
|
|
_getScrollNode: function() {
|
2017-05-18 19:33:32 +03:00
|
|
|
|
if (!this.mounted) return null;
|
2017-10-11 19:56:17 +03:00
|
|
|
|
const panel = ReactDOM.findDOMNode(this);
|
2015-12-17 05:49:09 +03:00
|
|
|
|
if (!panel) return null;
|
|
|
|
|
|
2017-05-18 21:03:51 +03:00
|
|
|
|
if (panel.classList.contains('gm-prevented')) {
|
|
|
|
|
return panel;
|
|
|
|
|
} else {
|
|
|
|
|
return panel.children[2]; // XXX: Fragile!
|
|
|
|
|
}
|
2015-12-17 05:49:09 +03:00
|
|
|
|
},
|
|
|
|
|
|
2016-08-25 21:46:01 +03:00
|
|
|
|
_whenScrolling: function(e) {
|
2016-09-03 14:44:55 +03:00
|
|
|
|
this._hideTooltip(e);
|
2015-12-17 05:49:09 +03:00
|
|
|
|
this._repositionIncomingCallBox(e, false);
|
|
|
|
|
},
|
|
|
|
|
|
2016-09-03 14:44:55 +03:00
|
|
|
|
_hideTooltip: function(e) {
|
|
|
|
|
// Hide tooltip when scrolling, as we'll no longer be over the one we were on
|
|
|
|
|
if (this.tooltip && this.tooltip.style.display !== "none") {
|
|
|
|
|
this.tooltip.style.display = "none";
|
2015-12-17 05:49:09 +03:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_repositionIncomingCallBox: function(e, firstTime) {
|
2017-10-11 19:56:17 +03:00
|
|
|
|
const incomingCallBox = document.getElementById("incomingCallBox");
|
2015-12-17 05:49:09 +03:00
|
|
|
|
if (incomingCallBox && incomingCallBox.parentElement) {
|
2017-10-11 19:56:17 +03:00
|
|
|
|
const scrollArea = this._getScrollNode();
|
2017-05-18 19:33:32 +03:00
|
|
|
|
if (!scrollArea) return;
|
2016-09-15 16:39:34 +03:00
|
|
|
|
// Use the offset of the top of the scroll area from the window
|
|
|
|
|
// as this is used to calculate the CSS fixed top position for the stickies
|
2017-10-11 19:56:17 +03:00
|
|
|
|
const scrollAreaOffset = scrollArea.getBoundingClientRect().top + window.pageYOffset;
|
2017-04-22 19:28:28 +03:00
|
|
|
|
// Use the offset of the top of the component from the window
|
2016-09-15 17:33:08 +03:00
|
|
|
|
// as this is used to calculate the CSS fixed top position for the stickies
|
2017-10-11 19:56:17 +03:00
|
|
|
|
const scrollAreaHeight = ReactDOM.findDOMNode(this).getBoundingClientRect().height;
|
2016-09-15 16:39:34 +03:00
|
|
|
|
|
2017-10-11 19:56:17 +03:00
|
|
|
|
let top = (incomingCallBox.parentElement.getBoundingClientRect().top + window.pageYOffset);
|
2016-09-15 17:33:08 +03:00
|
|
|
|
// Make sure we don't go too far up, if the headers aren't sticky
|
|
|
|
|
top = (top < scrollAreaOffset) ? scrollAreaOffset : top;
|
|
|
|
|
// make sure we don't go too far down, if the headers aren't sticky
|
2017-10-11 19:56:17 +03:00
|
|
|
|
const bottomMargin = scrollAreaOffset + (scrollAreaHeight - 45);
|
2016-09-15 17:33:08 +03:00
|
|
|
|
top = (top > bottomMargin) ? bottomMargin : top;
|
2016-02-19 05:21:17 +03:00
|
|
|
|
|
2015-12-17 05:49:09 +03:00
|
|
|
|
incomingCallBox.style.top = top + "px";
|
2016-09-15 17:33:08 +03:00
|
|
|
|
incomingCallBox.style.left = scrollArea.offsetLeft + scrollArea.offsetWidth + 12 + "px";
|
2015-11-30 19:55:00 +03:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2018-06-14 16:18:39 +03:00
|
|
|
|
_makeGroupInviteTiles(filter) {
|
2017-08-18 13:22:50 +03:00
|
|
|
|
const ret = [];
|
2018-06-14 16:18:39 +03:00
|
|
|
|
const lcFilter = filter && filter.toLowerCase();
|
2017-08-18 13:22:50 +03:00
|
|
|
|
|
|
|
|
|
const GroupInviteTile = sdk.getComponent('groups.GroupInviteTile');
|
|
|
|
|
for (const group of MatrixClientPeg.get().getGroups()) {
|
2018-06-14 18:48:00 +03:00
|
|
|
|
const {groupId, name, myMembership} = group;
|
2018-06-14 16:18:39 +03:00
|
|
|
|
// filter to only groups in invite state and group_id starts with filter or group name includes it
|
2018-06-14 18:48:00 +03:00
|
|
|
|
if (myMembership !== 'invite') continue;
|
|
|
|
|
if (lcFilter && !groupId.toLowerCase().startsWith(lcFilter) &&
|
2018-06-14 16:18:39 +03:00
|
|
|
|
!(name && name.toLowerCase().includes(lcFilter))) continue;
|
2018-06-14 18:48:00 +03:00
|
|
|
|
ret.push(<GroupInviteTile key={groupId} group={group} collapsed={this.props.collapsed} />);
|
2017-08-18 13:22:50 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
},
|
|
|
|
|
|
2018-11-02 17:27:17 +03:00
|
|
|
|
_applySearchFilter: function(list, filter) {
|
|
|
|
|
if (filter === "") return list;
|
|
|
|
|
const lcFilter = filter.toLowerCase();
|
2019-12-21 14:13:37 +03:00
|
|
|
|
// apply toLowerCase before and after removeHiddenChars because different rules get applied
|
2019-12-21 23:26:32 +03:00
|
|
|
|
// e.g M -> M but m -> n, yet some unicode homoglyphs come out as uppercase, e.g 𝚮 -> H
|
2019-12-21 14:13:37 +03:00
|
|
|
|
const fuzzyFilter = utils.removeHiddenChars(lcFilter).toLowerCase();
|
2018-11-02 17:27:17 +03:00
|
|
|
|
// case insensitive if room name includes filter,
|
|
|
|
|
// or if starts with `#` and one of room's aliases starts with filter
|
2019-12-19 18:26:04 +03:00
|
|
|
|
return list.filter((room) => {
|
|
|
|
|
if (filter[0] === "#" && room.getAliases().some((alias) => alias.toLowerCase().startsWith(lcFilter))) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-12-21 14:13:37 +03:00
|
|
|
|
return room.name && utils.removeHiddenChars(room.name.toLowerCase()).toLowerCase().includes(fuzzyFilter);
|
2019-12-19 18:26:04 +03:00
|
|
|
|
});
|
2018-03-21 18:58:14 +03:00
|
|
|
|
},
|
|
|
|
|
|
2018-12-18 12:56:00 +03:00
|
|
|
|
_handleCollapsedState: function(key, collapsed) {
|
|
|
|
|
// persist collapsed state
|
2018-12-03 12:39:31 +03:00
|
|
|
|
this.collapsedState[key] = collapsed;
|
|
|
|
|
window.localStorage.setItem("mx_roomlist_collapsed", JSON.stringify(this.collapsedState));
|
2018-12-18 12:56:00 +03:00
|
|
|
|
// load the persisted size configuration of the expanded sub list
|
2019-01-28 16:35:04 +03:00
|
|
|
|
if (collapsed) {
|
|
|
|
|
this._layout.collapseSection(key);
|
|
|
|
|
} else {
|
|
|
|
|
this._layout.expandSection(key, this.subListSizes[key]);
|
2018-12-18 12:56:00 +03:00
|
|
|
|
}
|
|
|
|
|
// check overflow, as sub lists sizes have changed
|
|
|
|
|
// important this happens after calling resize above
|
2018-12-18 16:26:33 +03:00
|
|
|
|
this._checkSubListsOverflow();
|
|
|
|
|
},
|
2017-08-18 13:22:50 +03:00
|
|
|
|
|
2018-12-18 16:26:33 +03:00
|
|
|
|
// check overflow for scroll indicator gradient
|
|
|
|
|
_checkSubListsOverflow() {
|
2018-12-18 12:56:00 +03:00
|
|
|
|
Object.values(this._subListRefs).forEach(l => l.checkOverflow());
|
2018-12-03 12:39:31 +03:00
|
|
|
|
},
|
|
|
|
|
|
2018-12-14 19:06:51 +03:00
|
|
|
|
_subListRef: function(key, ref) {
|
|
|
|
|
if (!ref) {
|
|
|
|
|
delete this._subListRefs[key];
|
|
|
|
|
} else {
|
|
|
|
|
this._subListRefs[key] = ref;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2018-11-02 17:27:17 +03:00
|
|
|
|
_mapSubListProps: function(subListsProps) {
|
2019-01-24 17:43:49 +03:00
|
|
|
|
this._layoutSections = [];
|
2018-11-02 17:27:17 +03:00
|
|
|
|
const defaultProps = {
|
|
|
|
|
collapsed: this.props.collapsed,
|
|
|
|
|
isFiltered: !!this.props.searchFilter,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
subListsProps.forEach((p) => {
|
|
|
|
|
p.list = this._applySearchFilter(p.list, this.props.searchFilter);
|
|
|
|
|
});
|
2018-06-30 19:07:28 +03:00
|
|
|
|
|
2018-11-02 17:27:17 +03:00
|
|
|
|
subListsProps = subListsProps.filter((props => {
|
|
|
|
|
const len = props.list.length + (props.extraTiles ? props.extraTiles.length : 0);
|
2019-01-22 19:54:04 +03:00
|
|
|
|
return len !== 0 || props.onAddRoom;
|
2018-11-02 17:27:17 +03:00
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
return subListsProps.reduce((components, props, i) => {
|
2019-12-23 20:57:53 +03:00
|
|
|
|
props = {...defaultProps, ...props};
|
2018-11-02 17:27:17 +03:00
|
|
|
|
const isLast = i === subListsProps.length - 1;
|
2019-01-24 17:43:49 +03:00
|
|
|
|
const len = props.list.length + (props.extraTiles ? props.extraTiles.length : 0);
|
2019-10-14 18:08:56 +03:00
|
|
|
|
const {key, label, onHeaderClick, ...otherProps} = props;
|
2018-11-02 17:27:17 +03:00
|
|
|
|
const chosenKey = key || label;
|
2018-12-03 12:39:31 +03:00
|
|
|
|
const onSubListHeaderClick = (collapsed) => {
|
2018-12-18 12:56:00 +03:00
|
|
|
|
this._handleCollapsedState(chosenKey, collapsed);
|
2018-12-03 12:39:31 +03:00
|
|
|
|
if (onHeaderClick) {
|
|
|
|
|
onHeaderClick(collapsed);
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-12-23 20:57:53 +03:00
|
|
|
|
const startAsHidden = props.startAsHidden || this.collapsedState[chosenKey];
|
2019-01-24 17:43:49 +03:00
|
|
|
|
this._layoutSections.push({
|
|
|
|
|
id: chosenKey,
|
|
|
|
|
count: len,
|
|
|
|
|
});
|
2019-12-23 20:57:53 +03:00
|
|
|
|
const subList = (<RoomSubList
|
2018-12-14 19:06:51 +03:00
|
|
|
|
ref={this._subListRef.bind(this, chosenKey)}
|
2018-12-03 12:39:31 +03:00
|
|
|
|
startAsHidden={startAsHidden}
|
2019-01-28 20:28:04 +03:00
|
|
|
|
forceExpand={!!this.props.searchFilter}
|
2018-12-03 12:39:31 +03:00
|
|
|
|
onHeaderClick={onSubListHeaderClick}
|
|
|
|
|
key={chosenKey}
|
|
|
|
|
label={label}
|
|
|
|
|
{...otherProps} />);
|
2018-11-02 17:27:17 +03:00
|
|
|
|
|
|
|
|
|
if (!isLast) {
|
|
|
|
|
return components.concat(
|
|
|
|
|
subList,
|
2018-11-26 18:46:57 +03:00
|
|
|
|
<ResizeHandle key={chosenKey+"-resizer"} vertical={true} id={chosenKey} />
|
2018-11-02 17:27:17 +03:00
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
return components.concat(subList);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
},
|
|
|
|
|
|
2018-11-26 18:46:57 +03:00
|
|
|
|
_collectResizeContainer: function(el) {
|
|
|
|
|
this.resizeContainer = el;
|
|
|
|
|
},
|
|
|
|
|
|
2018-11-02 17:27:17 +03:00
|
|
|
|
render: function() {
|
2018-12-06 21:45:58 +03:00
|
|
|
|
const incomingCallIfTaggedAs = (tagName) => {
|
|
|
|
|
if (!this.state.incomingCall) return null;
|
|
|
|
|
if (this.state.incomingCallTag !== tagName) return null;
|
|
|
|
|
return this.state.incomingCall;
|
|
|
|
|
};
|
|
|
|
|
|
2018-10-18 16:09:58 +03:00
|
|
|
|
let subLists = [
|
|
|
|
|
{
|
|
|
|
|
list: [],
|
2018-10-19 15:43:54 +03:00
|
|
|
|
extraTiles: this._makeGroupInviteTiles(this.props.searchFilter),
|
2018-10-18 16:09:58 +03:00
|
|
|
|
label: _t('Community Invites'),
|
|
|
|
|
isInvite: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
2018-10-19 15:43:54 +03:00
|
|
|
|
list: this.state.lists['im.vector.fake.invite'],
|
2018-10-18 16:09:58 +03:00
|
|
|
|
label: _t('Invites'),
|
2019-01-04 02:00:23 +03:00
|
|
|
|
incomingCall: incomingCallIfTaggedAs('im.vector.fake.invite'),
|
2018-10-18 16:09:58 +03:00
|
|
|
|
isInvite: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
2018-10-19 15:43:54 +03:00
|
|
|
|
list: this.state.lists['m.favourite'],
|
2018-10-18 16:09:58 +03:00
|
|
|
|
label: _t('Favourites'),
|
|
|
|
|
tagName: "m.favourite",
|
2019-01-04 02:00:23 +03:00
|
|
|
|
incomingCall: incomingCallIfTaggedAs('m.favourite'),
|
2018-10-18 16:09:58 +03:00
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-25 05:43:11 +03:00
|
|
|
|
list: this.state.lists[TAG_DM],
|
2020-01-24 15:59:46 +03:00
|
|
|
|
label: _t('Direct Messages'),
|
2020-02-25 05:43:11 +03:00
|
|
|
|
tagName: TAG_DM,
|
|
|
|
|
incomingCall: incomingCallIfTaggedAs(TAG_DM),
|
2019-10-14 18:08:56 +03:00
|
|
|
|
onAddRoom: () => {dis.dispatch({action: 'view_create_chat'});},
|
2019-05-21 21:16:34 +03:00
|
|
|
|
addRoomLabel: _t("Start chat"),
|
2018-10-18 16:09:58 +03:00
|
|
|
|
},
|
|
|
|
|
{
|
2018-10-19 15:43:54 +03:00
|
|
|
|
list: this.state.lists['im.vector.fake.recent'],
|
2018-10-18 16:09:58 +03:00
|
|
|
|
label: _t('Rooms'),
|
2019-01-04 02:00:23 +03:00
|
|
|
|
incomingCall: incomingCallIfTaggedAs('im.vector.fake.recent'),
|
2019-09-10 12:59:59 +03:00
|
|
|
|
onAddRoom: () => {dis.dispatch({action: 'view_create_room'});},
|
2018-10-18 16:09:58 +03:00
|
|
|
|
},
|
|
|
|
|
];
|
2018-10-19 15:43:54 +03:00
|
|
|
|
const tagSubLists = Object.keys(this.state.lists)
|
2018-10-18 16:09:58 +03:00
|
|
|
|
.filter((tagName) => {
|
2019-02-08 15:03:58 +03:00
|
|
|
|
return (!this.state.customTags || this.state.customTags[tagName]) &&
|
2019-02-07 21:04:30 +03:00
|
|
|
|
!tagName.match(STANDARD_TAGS_REGEX);
|
2018-10-18 16:09:58 +03:00
|
|
|
|
}).map((tagName) => {
|
|
|
|
|
return {
|
2018-10-19 15:43:54 +03:00
|
|
|
|
list: this.state.lists[tagName],
|
2018-10-18 16:09:58 +03:00
|
|
|
|
key: tagName,
|
|
|
|
|
label: labelForTagName(tagName),
|
|
|
|
|
tagName: tagName,
|
2019-01-04 02:00:23 +03:00
|
|
|
|
incomingCall: incomingCallIfTaggedAs(tagName),
|
2018-10-18 16:09:58 +03:00
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
subLists = subLists.concat(tagSubLists);
|
|
|
|
|
subLists = subLists.concat([
|
|
|
|
|
{
|
2018-10-19 15:43:54 +03:00
|
|
|
|
list: this.state.lists['m.lowpriority'],
|
2018-10-18 16:09:58 +03:00
|
|
|
|
label: _t('Low priority'),
|
|
|
|
|
tagName: "m.lowpriority",
|
2019-01-04 02:00:23 +03:00
|
|
|
|
incomingCall: incomingCallIfTaggedAs('m.lowpriority'),
|
2018-10-18 16:09:58 +03:00
|
|
|
|
},
|
|
|
|
|
{
|
2018-10-19 15:43:54 +03:00
|
|
|
|
list: this.state.lists['im.vector.fake.archived'],
|
2018-10-18 16:09:58 +03:00
|
|
|
|
label: _t('Historical'),
|
2019-01-04 02:00:23 +03:00
|
|
|
|
incomingCall: incomingCallIfTaggedAs('im.vector.fake.archived'),
|
2018-10-18 16:09:58 +03:00
|
|
|
|
startAsHidden: true,
|
2018-10-19 15:43:54 +03:00
|
|
|
|
showSpinner: this.state.isLoadingLeftRooms,
|
|
|
|
|
onHeaderClick: this.onArchivedHeaderClick,
|
2018-10-18 16:09:58 +03:00
|
|
|
|
},
|
|
|
|
|
{
|
2018-10-19 15:43:54 +03:00
|
|
|
|
list: this.state.lists['m.server_notice'],
|
2018-10-18 16:09:58 +03:00
|
|
|
|
label: _t('System Alerts'),
|
|
|
|
|
tagName: "m.lowpriority",
|
2019-01-04 02:00:23 +03:00
|
|
|
|
incomingCall: incomingCallIfTaggedAs('m.server_notice'),
|
2018-10-18 16:09:58 +03:00
|
|
|
|
},
|
|
|
|
|
]);
|
|
|
|
|
|
2018-11-02 17:27:17 +03:00
|
|
|
|
const subListComponents = this._mapSubListProps(subLists);
|
2018-10-18 16:09:58 +03:00
|
|
|
|
|
2020-01-22 13:36:20 +03:00
|
|
|
|
const {resizeNotifier, collapsed, searchFilter, ConferenceHandler, onKeyDown, ...props} = this.props; // eslint-disable-line
|
2015-11-30 19:55:00 +03:00
|
|
|
|
return (
|
2020-01-22 13:36:20 +03:00
|
|
|
|
<RovingTabIndexProvider handleHomeEnd={true} onKeyDown={onKeyDown}>
|
|
|
|
|
{({onKeyDownHandler}) => <div
|
|
|
|
|
{...props}
|
|
|
|
|
onKeyDown={onKeyDownHandler}
|
|
|
|
|
ref={this._collectResizeContainer}
|
|
|
|
|
className="mx_RoomList"
|
|
|
|
|
role="tree"
|
|
|
|
|
aria-label={_t("Rooms")}
|
2020-03-10 18:24:42 +03:00
|
|
|
|
// Firefox sometimes makes this element focusable due to
|
|
|
|
|
// overflow:scroll;, so force it out of tab order.
|
2020-03-13 20:52:06 +03:00
|
|
|
|
tabIndex="-1"
|
2020-01-22 13:36:20 +03:00
|
|
|
|
onMouseMove={this.onMouseMove}
|
|
|
|
|
onMouseLeave={this.onMouseLeave}
|
|
|
|
|
>
|
2020-01-20 23:31:36 +03:00
|
|
|
|
{ subListComponents }
|
2020-01-22 13:36:20 +03:00
|
|
|
|
</div> }
|
|
|
|
|
</RovingTabIndexProvider>
|
2015-11-30 19:55:00 +03:00
|
|
|
|
);
|
2017-10-11 19:56:17 +03:00
|
|
|
|
},
|
2019-01-10 20:40:26 +03:00
|
|
|
|
});
|