Merge branch 'develop' into travis/room-list/perf/notifications
This commit is contained in:
commit
57b2ae9a0d
7 changed files with 127 additions and 55 deletions
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
|
@ -21,6 +21,7 @@ import ToastStore from "../stores/ToastStore";
|
||||||
import DeviceListener from "../DeviceListener";
|
import DeviceListener from "../DeviceListener";
|
||||||
import { RoomListStore2 } from "../stores/room-list/RoomListStore2";
|
import { RoomListStore2 } from "../stores/room-list/RoomListStore2";
|
||||||
import { PlatformPeg } from "../PlatformPeg";
|
import { PlatformPeg } from "../PlatformPeg";
|
||||||
|
import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
@ -34,6 +35,7 @@ declare global {
|
||||||
mx_ToastStore: ToastStore;
|
mx_ToastStore: ToastStore;
|
||||||
mx_DeviceListener: DeviceListener;
|
mx_DeviceListener: DeviceListener;
|
||||||
mx_RoomListStore2: RoomListStore2;
|
mx_RoomListStore2: RoomListStore2;
|
||||||
|
mx_RoomListLayoutStore: RoomListLayoutStore;
|
||||||
mxPlatformPeg: PlatformPeg;
|
mxPlatformPeg: PlatformPeg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { BreadcrumbsStore } from "../../../stores/BreadcrumbsStore";
|
import { BreadcrumbsStore } from "../../../stores/BreadcrumbsStore";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
|
||||||
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
@ -92,9 +91,6 @@ export default class RoomBreadcrumbs2 extends React.PureComponent<IProps, IState
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): React.ReactElement {
|
public render(): React.ReactElement {
|
||||||
// TODO: Decorate crumbs with icons: https://github.com/vector-im/riot-web/issues/14040
|
|
||||||
// TODO: Scrolling: https://github.com/vector-im/riot-web/issues/14040
|
|
||||||
// TODO: Tooltips: https://github.com/vector-im/riot-web/issues/14040
|
|
||||||
const tiles = BreadcrumbsStore.instance.rooms.map((r, i) => {
|
const tiles = BreadcrumbsStore.instance.rooms.map((r, i) => {
|
||||||
const roomTags = RoomListStore.instance.getTagsForRoom(r);
|
const roomTags = RoomListStore.instance.getTagsForRoom(r);
|
||||||
const roomTag = roomTags.includes(DefaultTagID.DM) ? DefaultTagID.DM : roomTags[0];
|
const roomTag = roomTags.includes(DefaultTagID.DM) ? DefaultTagID.DM : roomTags[0];
|
||||||
|
|
|
@ -32,7 +32,6 @@ import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
import RoomSublist2 from "./RoomSublist2";
|
import RoomSublist2 from "./RoomSublist2";
|
||||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||||
import { NameFilterCondition } from "../../../stores/room-list/filters/NameFilterCondition";
|
import { NameFilterCondition } from "../../../stores/room-list/filters/NameFilterCondition";
|
||||||
import { ListLayout } from "../../../stores/room-list/ListLayout";
|
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import GroupAvatar from "../avatars/GroupAvatar";
|
import GroupAvatar from "../avatars/GroupAvatar";
|
||||||
import TemporaryTile from "./TemporaryTile";
|
import TemporaryTile from "./TemporaryTile";
|
||||||
|
@ -66,7 +65,6 @@ interface IProps {
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
sublists: ITagMap;
|
sublists: ITagMap;
|
||||||
layouts: Map<TagID, ListLayout>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TAG_ORDER: TagID[] = [
|
const TAG_ORDER: TagID[] = [
|
||||||
|
@ -151,7 +149,6 @@ export default class RoomList2 extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
sublists: {},
|
sublists: {},
|
||||||
layouts: new Map<TagID, ListLayout>(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
||||||
|
@ -224,12 +221,7 @@ export default class RoomList2 extends React.Component<IProps, IState> {
|
||||||
const newLists = RoomListStore.instance.orderedLists;
|
const newLists = RoomListStore.instance.orderedLists;
|
||||||
console.log("new lists", newLists);
|
console.log("new lists", newLists);
|
||||||
|
|
||||||
const layoutMap = new Map<TagID, ListLayout>();
|
this.setState({sublists: newLists}, () => {
|
||||||
for (const tagId of Object.keys(newLists)) {
|
|
||||||
layoutMap.set(tagId, new ListLayout(tagId));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({sublists: newLists, layouts: layoutMap}, () => {
|
|
||||||
this.props.onResize();
|
this.props.onResize();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -298,7 +290,6 @@ export default class RoomList2 extends React.Component<IProps, IState> {
|
||||||
label={_t(aesthetics.sectionLabel)}
|
label={_t(aesthetics.sectionLabel)}
|
||||||
onAddRoom={onAddRoomFn}
|
onAddRoom={onAddRoomFn}
|
||||||
addRoomLabel={aesthetics.addRoomLabel}
|
addRoomLabel={aesthetics.addRoomLabel}
|
||||||
layout={this.state.layouts.get(orderedTagId)}
|
|
||||||
isMinimized={this.props.isMinimized}
|
isMinimized={this.props.isMinimized}
|
||||||
onResize={this.props.onResize}
|
onResize={this.props.onResize}
|
||||||
extraBadTilesThatShouldntExist={extraTiles}
|
extraBadTilesThatShouldntExist={extraTiles}
|
||||||
|
|
|
@ -46,6 +46,7 @@ import { Enable, Resizable } from "re-resizable";
|
||||||
import { Direction } from "re-resizable/lib/resizer";
|
import { Direction } from "re-resizable/lib/resizer";
|
||||||
import { polyfillTouchEvent } from "../../../@types/polyfill";
|
import { polyfillTouchEvent } from "../../../@types/polyfill";
|
||||||
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
||||||
|
import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore";
|
||||||
|
|
||||||
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
|
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
|
||||||
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
|
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
|
||||||
|
@ -74,7 +75,6 @@ interface IProps {
|
||||||
label: string;
|
label: string;
|
||||||
onAddRoom?: () => void;
|
onAddRoom?: () => void;
|
||||||
addRoomLabel: string;
|
addRoomLabel: string;
|
||||||
layout?: ListLayout;
|
|
||||||
isMinimized: boolean;
|
isMinimized: boolean;
|
||||||
tagId: TagID;
|
tagId: TagID;
|
||||||
onResize: () => void;
|
onResize: () => void;
|
||||||
|
@ -98,10 +98,13 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
private headerButton = createRef<HTMLDivElement>();
|
private headerButton = createRef<HTMLDivElement>();
|
||||||
private sublistRef = createRef<HTMLDivElement>();
|
private sublistRef = createRef<HTMLDivElement>();
|
||||||
private dispatcherRef: string;
|
private dispatcherRef: string;
|
||||||
|
private layout: ListLayout;
|
||||||
|
|
||||||
constructor(props: IProps) {
|
constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
this.layout = RoomListLayoutStore.instance.getLayoutFor(this.props.tagId);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
notificationState: RoomNotificationStateStore.instance.getListState(this.props.tagId),
|
notificationState: RoomNotificationStateStore.instance.getListState(this.props.tagId),
|
||||||
contextMenuPosition: null,
|
contextMenuPosition: null,
|
||||||
|
@ -116,8 +119,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private get numVisibleTiles(): number {
|
private get numVisibleTiles(): number {
|
||||||
if (!this.props.layout) return 0;
|
const nVisible = Math.floor(this.layout.visibleTiles);
|
||||||
const nVisible = Math.floor(this.props.layout.visibleTiles);
|
|
||||||
return Math.min(nVisible, this.numTiles);
|
return Math.min(nVisible, this.numTiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +137,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
// XXX: we have to do this a tick later because we have incorrect intermediate props during a room change
|
// XXX: we have to do this a tick later because we have incorrect intermediate props during a room change
|
||||||
// where we lose the room we are changing from temporarily and then it comes back in an update right after.
|
// where we lose the room we are changing from temporarily and then it comes back in an update right after.
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
const isCollapsed = this.props.layout.isCollapsed;
|
const isCollapsed = this.layout.isCollapsed;
|
||||||
const roomIndex = this.props.rooms.findIndex((r) => r.roomId === payload.room_id);
|
const roomIndex = this.props.rooms.findIndex((r) => r.roomId === payload.room_id);
|
||||||
|
|
||||||
if (isCollapsed && roomIndex > -1) {
|
if (isCollapsed && roomIndex > -1) {
|
||||||
|
@ -143,7 +145,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
// extend the visible section to include the room if it is entirely invisible
|
// extend the visible section to include the room if it is entirely invisible
|
||||||
if (roomIndex >= this.numVisibleTiles) {
|
if (roomIndex >= this.numVisibleTiles) {
|
||||||
this.props.layout.visibleTiles = this.props.layout.tilesWithPadding(roomIndex + 1, MAX_PADDING_HEIGHT);
|
this.layout.visibleTiles = this.layout.tilesWithPadding(roomIndex + 1, MAX_PADDING_HEIGHT);
|
||||||
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -170,10 +172,10 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
// resizing started*, meaning it is fairly useless for us. This is why we just use
|
// resizing started*, meaning it is fairly useless for us. This is why we just use
|
||||||
// the client height and run with it.
|
// the client height and run with it.
|
||||||
|
|
||||||
const heightBefore = this.props.layout.visibleTiles;
|
const heightBefore = this.layout.visibleTiles;
|
||||||
const heightInTiles = this.props.layout.pixelsToTiles(refToElement.clientHeight);
|
const heightInTiles = this.layout.pixelsToTiles(refToElement.clientHeight);
|
||||||
this.props.layout.setVisibleTilesWithin(heightInTiles, this.numTiles);
|
this.layout.setVisibleTilesWithin(heightInTiles, this.numTiles);
|
||||||
if (heightBefore === this.props.layout.visibleTiles) return; // no-op
|
if (heightBefore === this.layout.visibleTiles) return; // no-op
|
||||||
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -187,13 +189,13 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
private onShowAllClick = () => {
|
private onShowAllClick = () => {
|
||||||
const numVisibleTiles = this.numVisibleTiles;
|
const numVisibleTiles = this.numVisibleTiles;
|
||||||
this.props.layout.visibleTiles = this.props.layout.tilesWithPadding(this.numTiles, MAX_PADDING_HEIGHT);
|
this.layout.visibleTiles = this.layout.tilesWithPadding(this.numTiles, MAX_PADDING_HEIGHT);
|
||||||
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
||||||
setImmediate(this.focusRoomTile, numVisibleTiles); // focus the tile after the current bottom one
|
setImmediate(this.focusRoomTile, numVisibleTiles); // focus the tile after the current bottom one
|
||||||
};
|
};
|
||||||
|
|
||||||
private onShowLessClick = () => {
|
private onShowLessClick = () => {
|
||||||
this.props.layout.visibleTiles = this.props.layout.defaultVisibleTiles;
|
this.layout.visibleTiles = this.layout.defaultVisibleTiles;
|
||||||
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
||||||
// focus will flow to the show more button here
|
// focus will flow to the show more button here
|
||||||
};
|
};
|
||||||
|
@ -241,7 +243,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onMessagePreviewChanged = () => {
|
private onMessagePreviewChanged = () => {
|
||||||
this.props.layout.showPreviews = !this.props.layout.showPreviews;
|
this.layout.showPreviews = !this.layout.showPreviews;
|
||||||
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -293,13 +295,13 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private toggleCollapsed = () => {
|
private toggleCollapsed = () => {
|
||||||
this.props.layout.isCollapsed = !this.props.layout.isCollapsed;
|
this.layout.isCollapsed = !this.layout.isCollapsed;
|
||||||
this.forceUpdate(); // because the layout doesn't trigger an update
|
this.forceUpdate(); // because the layout doesn't trigger an update
|
||||||
setImmediate(() => this.props.onResize()); // needs to happen when the DOM is updated
|
setImmediate(() => this.props.onResize()); // needs to happen when the DOM is updated
|
||||||
};
|
};
|
||||||
|
|
||||||
private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
|
private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
|
||||||
const isCollapsed = this.props.layout && this.props.layout.isCollapsed;
|
const isCollapsed = this.layout && this.layout.isCollapsed;
|
||||||
switch (ev.key) {
|
switch (ev.key) {
|
||||||
case Key.ARROW_LEFT:
|
case Key.ARROW_LEFT:
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
@ -339,7 +341,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderVisibleTiles(): React.ReactElement[] {
|
private renderVisibleTiles(): React.ReactElement[] {
|
||||||
if (this.props.layout && this.props.layout.isCollapsed) {
|
if (this.layout && this.layout.isCollapsed) {
|
||||||
// don't waste time on rendering
|
// don't waste time on rendering
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -353,7 +355,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
<RoomTile2
|
<RoomTile2
|
||||||
room={room}
|
room={room}
|
||||||
key={`room-${room.roomId}`}
|
key={`room-${room.roomId}`}
|
||||||
showMessagePreview={this.props.layout.showPreviews}
|
showMessagePreview={this.layout.showPreviews}
|
||||||
isMinimized={this.props.isMinimized}
|
isMinimized={this.props.isMinimized}
|
||||||
tag={this.props.tagId}
|
tag={this.props.tagId}
|
||||||
/>
|
/>
|
||||||
|
@ -404,7 +406,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
<StyledMenuItemCheckbox
|
<StyledMenuItemCheckbox
|
||||||
onClose={this.onCloseMenu}
|
onClose={this.onCloseMenu}
|
||||||
onChange={this.onMessagePreviewChanged}
|
onChange={this.onMessagePreviewChanged}
|
||||||
checked={this.props.layout.showPreviews}
|
checked={this.layout.showPreviews}
|
||||||
>
|
>
|
||||||
{_t("Message preview")}
|
{_t("Message preview")}
|
||||||
</StyledMenuItemCheckbox>
|
</StyledMenuItemCheckbox>
|
||||||
|
@ -496,7 +498,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
const collapseClasses = classNames({
|
const collapseClasses = classNames({
|
||||||
'mx_RoomSublist2_collapseBtn': true,
|
'mx_RoomSublist2_collapseBtn': true,
|
||||||
'mx_RoomSublist2_collapseBtn_collapsed': this.props.layout && this.props.layout.isCollapsed,
|
'mx_RoomSublist2_collapseBtn_collapsed': this.layout && this.layout.isCollapsed,
|
||||||
});
|
});
|
||||||
|
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
|
@ -524,7 +526,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
className="mx_RoomSublist2_headerText"
|
className="mx_RoomSublist2_headerText"
|
||||||
role="treeitem"
|
role="treeitem"
|
||||||
aria-expanded={!this.props.layout || !this.props.layout.isCollapsed}
|
aria-expanded={!this.layout.isCollapsed}
|
||||||
aria-level={1}
|
aria-level={1}
|
||||||
onClick={this.onHeaderClick}
|
onClick={this.onHeaderClick}
|
||||||
onContextMenu={this.onContextMenu}
|
onContextMenu={this.onContextMenu}
|
||||||
|
@ -558,7 +560,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
let content = null;
|
let content = null;
|
||||||
if (visibleTiles.length > 0) {
|
if (visibleTiles.length > 0) {
|
||||||
const layout = this.props.layout; // to shorten calls
|
const layout = this.layout; // to shorten calls
|
||||||
|
|
||||||
const maxTilesFactored = layout.tilesWithResizerBoxFactor(this.numTiles);
|
const maxTilesFactored = layout.tilesWithResizerBoxFactor(this.numTiles);
|
||||||
const showMoreBtnClasses = classNames({
|
const showMoreBtnClasses = classNames({
|
||||||
|
@ -587,7 +589,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
{showMoreText}
|
{showMoreText}
|
||||||
</RovingAccessibleButton>
|
</RovingAccessibleButton>
|
||||||
);
|
);
|
||||||
} else if (this.numTiles <= visibleTiles.length && this.numTiles > this.props.layout.defaultVisibleTiles) {
|
} else if (this.numTiles <= visibleTiles.length && this.numTiles > this.layout.defaultVisibleTiles) {
|
||||||
// we have all tiles visible - add a button to show less
|
// we have all tiles visible - add a button to show less
|
||||||
let showLessText = (
|
let showLessText = (
|
||||||
<span className='mx_RoomSublist2_showNButtonText'>
|
<span className='mx_RoomSublist2_showNButtonText'>
|
||||||
|
|
|
@ -125,6 +125,7 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async appendRoom(room: Room) {
|
private async appendRoom(room: Room) {
|
||||||
|
let updated = false;
|
||||||
const rooms = (this.state.rooms || []).slice(); // cheap clone
|
const rooms = (this.state.rooms || []).slice(); // cheap clone
|
||||||
|
|
||||||
// If the room is upgraded, use that room instead. We'll also splice out
|
// If the room is upgraded, use that room instead. We'll also splice out
|
||||||
|
@ -136,25 +137,36 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
|
||||||
// Take out any room that isn't the most recent room
|
// Take out any room that isn't the most recent room
|
||||||
for (let i = 0; i < history.length - 1; i++) {
|
for (let i = 0; i < history.length - 1; i++) {
|
||||||
const idx = rooms.findIndex(r => r.roomId === history[i].roomId);
|
const idx = rooms.findIndex(r => r.roomId === history[i].roomId);
|
||||||
if (idx !== -1) rooms.splice(idx, 1);
|
if (idx !== -1) {
|
||||||
|
rooms.splice(idx, 1);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the existing room, if it is present
|
// Remove the existing room, if it is present
|
||||||
const existingIdx = rooms.findIndex(r => r.roomId === room.roomId);
|
const existingIdx = rooms.findIndex(r => r.roomId === room.roomId);
|
||||||
|
|
||||||
|
// If we're focusing on the first room no-op
|
||||||
|
if (existingIdx !== 0) {
|
||||||
if (existingIdx !== -1) {
|
if (existingIdx !== -1) {
|
||||||
rooms.splice(existingIdx, 1);
|
rooms.splice(existingIdx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splice the room to the start of the list
|
// Splice the room to the start of the list
|
||||||
rooms.splice(0, 0, room);
|
rooms.splice(0, 0, room);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (rooms.length > MAX_ROOMS) {
|
if (rooms.length > MAX_ROOMS) {
|
||||||
// This looks weird, but it's saying to start at the MAX_ROOMS point in the
|
// This looks weird, but it's saying to start at the MAX_ROOMS point in the
|
||||||
// list and delete everything after it.
|
// list and delete everything after it.
|
||||||
rooms.splice(MAX_ROOMS, rooms.length - MAX_ROOMS);
|
rooms.splice(MAX_ROOMS, rooms.length - MAX_ROOMS);
|
||||||
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (updated) {
|
||||||
// Update the breadcrumbs
|
// Update the breadcrumbs
|
||||||
await this.updateState({rooms});
|
await this.updateState({rooms});
|
||||||
const roomIds = rooms.map(r => r.roomId);
|
const roomIds = rooms.map(r => r.roomId);
|
||||||
|
@ -162,5 +174,6 @@ export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
|
||||||
await SettingsStore.setValue("breadcrumb_rooms", null, SettingLevel.ACCOUNT, roomIds);
|
await SettingsStore.setValue("breadcrumb_rooms", null, SettingLevel.ACCOUNT, roomIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
73
src/stores/room-list/RoomListLayoutStore.ts
Normal file
73
src/stores/room-list/RoomListLayoutStore.ts
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TagID } from "./models";
|
||||||
|
import { ListLayout } from "./ListLayout";
|
||||||
|
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
|
||||||
|
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||||
|
import { ActionPayload } from "../../dispatcher/payloads";
|
||||||
|
|
||||||
|
interface IState {}
|
||||||
|
|
||||||
|
export default class RoomListLayoutStore extends AsyncStoreWithClient<IState> {
|
||||||
|
private static internalInstance: RoomListLayoutStore;
|
||||||
|
|
||||||
|
private readonly layoutMap = new Map<TagID, ListLayout>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(defaultDispatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get instance(): RoomListLayoutStore {
|
||||||
|
if (!RoomListLayoutStore.internalInstance) {
|
||||||
|
RoomListLayoutStore.internalInstance = new RoomListLayoutStore();
|
||||||
|
}
|
||||||
|
return RoomListLayoutStore.internalInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ensureLayoutExists(tagId: TagID) {
|
||||||
|
if (!this.layoutMap.has(tagId)) {
|
||||||
|
this.layoutMap.set(tagId, new ListLayout(tagId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLayoutFor(tagId: TagID): ListLayout {
|
||||||
|
if (!this.layoutMap.has(tagId)) {
|
||||||
|
this.layoutMap.set(tagId, new ListLayout(tagId));
|
||||||
|
}
|
||||||
|
return this.layoutMap.get(tagId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: this primarily exists for debugging, and isn't really intended to be used by anything.
|
||||||
|
public async resetLayouts() {
|
||||||
|
console.warn("Resetting layouts for room list");
|
||||||
|
for (const layout of this.layoutMap.values()) {
|
||||||
|
layout.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onNotReady(): Promise<any> {
|
||||||
|
// On logout, clear the map.
|
||||||
|
this.layoutMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need this function, but our contract says we do
|
||||||
|
protected async onAction(payload: ActionPayload): Promise<any> {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.mx_RoomListLayoutStore = RoomListLayoutStore.instance;
|
|
@ -32,6 +32,7 @@ import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm";
|
||||||
import { EffectiveMembership, getEffectiveMembership } from "./membership";
|
import { EffectiveMembership, getEffectiveMembership } from "./membership";
|
||||||
import { ListLayout } from "./ListLayout";
|
import { ListLayout } from "./ListLayout";
|
||||||
import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
|
import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
|
||||||
|
import RoomListLayoutStore from "./RoomListLayoutStore";
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
tagsEnabled?: boolean;
|
tagsEnabled?: boolean;
|
||||||
|
@ -50,6 +51,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
private algorithm = new Algorithm();
|
private algorithm = new Algorithm();
|
||||||
private filterConditions: IFilterCondition[] = [];
|
private filterConditions: IFilterCondition[] = [];
|
||||||
private tagWatcher = new TagWatcher(this);
|
private tagWatcher = new TagWatcher(this);
|
||||||
|
private layoutMap: Map<TagID, ListLayout> = new Map<TagID, ListLayout>();
|
||||||
|
|
||||||
private readonly watchedSettings = [
|
private readonly watchedSettings = [
|
||||||
'feature_custom_tags',
|
'feature_custom_tags',
|
||||||
|
@ -416,6 +418,8 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
for (const tagId of OrderedDefaultTagIDs) {
|
for (const tagId of OrderedDefaultTagIDs) {
|
||||||
sorts[tagId] = this.calculateTagSorting(tagId);
|
sorts[tagId] = this.calculateTagSorting(tagId);
|
||||||
orders[tagId] = this.calculateListOrder(tagId);
|
orders[tagId] = this.calculateListOrder(tagId);
|
||||||
|
|
||||||
|
RoomListLayoutStore.instance.ensureLayoutExists(tagId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.tagsEnabled) {
|
if (this.state.tagsEnabled) {
|
||||||
|
@ -434,15 +438,6 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
this.emit(LISTS_UPDATE_EVENT, this);
|
this.emit(LISTS_UPDATE_EVENT, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this primarily exists for debugging, and isn't really intended to be used by anything.
|
|
||||||
public async resetLayouts() {
|
|
||||||
console.warn("Resetting layouts for room list");
|
|
||||||
for (const tagId of Object.keys(this.orderedLists)) {
|
|
||||||
new ListLayout(tagId).reset();
|
|
||||||
}
|
|
||||||
await this.regenerateAllLists();
|
|
||||||
}
|
|
||||||
|
|
||||||
public addFilter(filter: IFilterCondition): void {
|
public addFilter(filter: IFilterCondition): void {
|
||||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||||
console.log("Adding filter condition:", filter);
|
console.log("Adding filter condition:", filter);
|
||||||
|
|
Loading…
Reference in a new issue