From c07b5ebe9a789eaca974cb79090f97474774d09f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 3 Jun 2020 15:07:12 -0600 Subject: [PATCH 01/14] Initial experiments with resizing of room lists --- res/css/views/rooms/_RoomList.scss | 8 ++ src/components/views/rooms/RoomList2.tsx | 76 ++++++++++-------- src/components/views/rooms/RoomSublist2.tsx | 13 ++-- src/stores/room-list/RoomListLayoutStore.ts | 85 +++++++++++++++++++++ src/stores/room-list/RoomListStore2.ts | 3 + 5 files changed, 145 insertions(+), 40 deletions(-) create mode 100644 src/stores/room-list/RoomListLayoutStore.ts diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss index 50a9e7ee1f..7abf86cb0e 100644 --- a/res/css/views/rooms/_RoomList.scss +++ b/res/css/views/rooms/_RoomList.scss @@ -15,6 +15,14 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_RoomList2_resizer { + cursor: ns-resize; +} + +.mx_RoomList.mx_RoomList2 { + overflow-y: auto; +} + .mx_RoomList { /* take up remaining space below TopLeftMenu */ flex: 1; diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index e732e70edf..5e9f6ffb23 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -21,14 +21,13 @@ import { _t, _td } from "../../../languageHandler"; import { Layout } from '../../../resizer/distributors/roomsublist2'; import { RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex"; import { ResizeNotifier } from "../../../utils/ResizeNotifier"; -import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore2"; +import RoomListStore, { LISTS_UPDATE_EVENT, RoomListStore2 } from "../../../stores/room-list/RoomListStore2"; import { ITagMap } from "../../../stores/room-list/algorithms/models"; import { DefaultTagID, TagID } from "../../../stores/room-list/models"; import { Dispatcher } from "flux"; import dis from "../../../dispatcher/dispatcher"; import RoomSublist2 from "./RoomSublist2"; import { ActionPayload } from "../../../dispatcher/payloads"; -import { IFilterCondition } from "../../../stores/room-list/filters/IFilterCondition"; import { NameFilterCondition } from "../../../stores/room-list/filters/NameFilterCondition"; /******************************************************************* @@ -50,6 +49,7 @@ interface IProps { interface IState { sublists: ITagMap; + heights: Map; } const TAG_ORDER: TagID[] = [ @@ -133,13 +133,16 @@ export default class RoomList2 extends React.Component { private unfilteredLayout: Layout; private filteredLayout: Layout; private searchFilter: NameFilterCondition = new NameFilterCondition(); + private currentTagResize: TagID = null; constructor(props: IProps) { super(props); - this.state = {sublists: {}}; + this.state = { + sublists: {}, + heights: new Map(), + }; this.loadSublistSizes(); - this.prepareLayouts(); } public componentDidUpdate(prevProps: Readonly): void { @@ -158,9 +161,16 @@ export default class RoomList2 extends React.Component { } public componentDidMount(): void { - RoomListStore.instance.on(LISTS_UPDATE_EVENT, (store) => { - console.log("new lists", store.orderedLists); - this.setState({sublists: store.orderedLists}); + RoomListStore.instance.on(LISTS_UPDATE_EVENT, (store: RoomListStore2) => { + const newLists = store.orderedLists; + console.log("new lists", newLists); + + const heightMap = new Map(); + for (const tagId of Object.keys(newLists)) { + heightMap.set(tagId, store.layout.getPixelHeight(tagId)); + } + + this.setState({sublists: newLists, heights: heightMap}); }); } @@ -177,32 +187,24 @@ export default class RoomList2 extends React.Component { window.localStorage.setItem("mx_roomlist_collapsed", JSON.stringify(this.sublistCollapseStates)); } - private prepareLayouts() { - // TODO: Change layout engine for FTUE support - this.unfilteredLayout = new Layout((tagId: string, height: number) => { - const sublist = this.sublistRefs[tagId]; - if (sublist) sublist.current.setHeight(height); + private onResizerMouseDown = (ev: React.MouseEvent) => { + const hr = ev.target as HTMLHRElement; + this.currentTagResize = hr.getAttribute("data-id"); + }; - // TODO: Check overflow (see old impl) + private onResizerMouseUp = (ev: React.MouseEvent) => { + this.currentTagResize = null; + }; - // Don't store a height for collapsed sublists - if (!this.sublistCollapseStates[tagId]) { - this.sublistSizes[tagId] = height; - this.saveSublistSizes(); - } - }, this.sublistSizes, this.sublistCollapseStates, { - allowWhitespace: false, - handleHeight: 1, - }); - - this.filteredLayout = new Layout((tagId: string, height: number) => { - const sublist = this.sublistRefs[tagId]; - if (sublist) sublist.current.setHeight(height); - }, null, null, { - allowWhitespace: false, - handleHeight: 0, - }); - } + private onMouseMove = (ev: React.MouseEvent) => { + ev.preventDefault(); + if (this.currentTagResize) { + const pixelHeight = this.state.heights.get(this.currentTagResize); + RoomListStore.instance.layout.setPixelHeight(this.currentTagResize, pixelHeight + ev.movementY); + this.state.heights.set(this.currentTagResize, RoomListStore.instance.layout.getPixelHeight(this.currentTagResize)); + this.forceUpdate(); + } + }; private renderSublists(): React.ReactElement[] { const components: React.ReactElement[] = []; @@ -235,6 +237,14 @@ export default class RoomList2 extends React.Component { onAddRoom={onAddRoomFn} addRoomLabel={aesthetics.addRoomLabel} isInvite={aesthetics.isInvite} + height={this.state.heights.get(orderedTagId)} + />); + components.push(
); } @@ -250,7 +260,9 @@ export default class RoomList2 extends React.Component { onFocus={this.props.onFocus} onBlur={this.props.onBlur} onKeyDown={onKeyDownHandler} - className="mx_RoomList" + onMouseUp={this.onResizerMouseUp} + onMouseMove={this.onMouseMove} + className="mx_RoomList mx_RoomList2" role="tree" aria-label={_t("Rooms")} // Firefox sometimes makes this element focusable due to diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index e2f489b959..2b5b131393 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -45,9 +45,9 @@ interface IProps { onAddRoom?: () => void; addRoomLabel: string; isInvite: boolean; + height: number; // pixels // TODO: Collapsed state - // TODO: Height // TODO: Group invites // TODO: Calls // TODO: forceExpand? @@ -61,10 +61,6 @@ interface IState { export default class RoomSublist2 extends React.Component { private headerButton = createRef(); - public setHeight(size: number) { - // TODO: Do a thing (maybe - height changes are different in FTUE) - } - private hasTiles(): boolean { return this.numTiles > 0; } @@ -205,9 +201,10 @@ export default class RoomSublist2 extends React.Component { // TODO: Lazy list rendering // TODO: Whatever scrolling magic needs to happen here content = ( - - {tiles} - + {tiles} ) } diff --git a/src/stores/room-list/RoomListLayoutStore.ts b/src/stores/room-list/RoomListLayoutStore.ts new file mode 100644 index 0000000000..cbd570b579 --- /dev/null +++ b/src/stores/room-list/RoomListLayoutStore.ts @@ -0,0 +1,85 @@ +/* +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. +*/ + +// TODO: Simplify the class load when we pick an approach for the list layout + +import { TagID } from "./models"; + +const TILE_HEIGHT_PX = 34; + +export class LayoutUnit { + constructor(public readonly multiplier: number) { + } + + public convert(val: number): number { + return Math.ceil(val * this.multiplier); + } + + public normalizePixels(pixels: number): number { + return this.convert(Math.ceil(pixels / this.multiplier)); + } + + public forNumTiles(n: number): number { + const unitsPerTile = TILE_HEIGHT_PX / this.multiplier; + return unitsPerTile * n; + } +} + +export const SMOOTH_RESIZE = new LayoutUnit(1); +export const CHUNKED_RESIZE = new LayoutUnit(TILE_HEIGHT_PX); + +export class RoomListLayoutStore { + public unit: LayoutUnit = SMOOTH_RESIZE; + public minTilesShown = 1; + + /** + * Minimum list height in pixels. + */ + public get minListHeight(): number { + return this.unit.forNumTiles(this.minTilesShown); + } + + private getStorageKey(tagId: TagID) { + return `mx_rlls_${tagId}_m_${this.unit.multiplier}`; + } + + public setPixelHeight(tagId: TagID, pixels: number): void { + localStorage.setItem(this.getStorageKey(tagId), JSON.stringify({pixels})); + } + + public getPixelHeight(tagId: TagID): number { + const stored = JSON.parse(localStorage.getItem(this.getStorageKey(tagId))); + let storedHeight = 0; + if (stored && stored.pixels) { + storedHeight = stored.pixels; + } + return this.unit.normalizePixels(Math.max(this.minListHeight, storedHeight)); + } + + // TODO: Remove helper functions for design iteration + + public beSmooth() { + this.unit = SMOOTH_RESIZE; + } + + public beChunked() { + this.unit = CHUNKED_RESIZE; + } + + public beDifferent(multiplier: number) { + this.unit = new LayoutUnit(multiplier); + } +} diff --git a/src/stores/room-list/RoomListStore2.ts b/src/stores/room-list/RoomListStore2.ts index af9970d3cc..84033b5cca 100644 --- a/src/stores/room-list/RoomListStore2.ts +++ b/src/stores/room-list/RoomListStore2.ts @@ -29,6 +29,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher"; import { readReceiptChangeIsFor } from "../../utils/read-receipts"; import { IFilterCondition } from "./filters/IFilterCondition"; import { TagWatcher } from "./TagWatcher"; +import { RoomListLayoutStore } from "./RoomListLayoutStore"; interface IState { tagsEnabled?: boolean; @@ -44,6 +45,8 @@ interface IState { export const LISTS_UPDATE_EVENT = "lists_update"; export class RoomListStore2 extends AsyncStore { + public readonly layout = new RoomListLayoutStore(); + private _matrixClient: MatrixClient; private initialListsGenerated = false; private enabled = false; From dbf996439bb5cd0e09835f427db97b00046e8d6a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 3 Jun 2020 21:16:53 -0600 Subject: [PATCH 02/14] Wedge t3chguy's resizer prototype into the sublist --- package.json | 1 + res/css/_components.scss | 1 + res/css/views/rooms/_RoomSublist2.scss | 17 +++++ src/components/views/rooms/RoomList2.tsx | 73 +++++------------- src/components/views/rooms/RoomSublist2.tsx | 37 +++++++-- src/stores/room-list/ListLayout.ts | 65 ++++++++++++++++ src/stores/room-list/RoomListLayoutStore.ts | 85 --------------------- src/stores/room-list/RoomListStore2.ts | 3 - yarn.lock | 20 ++++- 9 files changed, 152 insertions(+), 150 deletions(-) create mode 100644 res/css/views/rooms/_RoomSublist2.scss create mode 100644 src/stores/room-list/ListLayout.ts delete mode 100644 src/stores/room-list/RoomListLayoutStore.ts diff --git a/package.json b/package.json index 11906452e7..1029efaccd 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "react-beautiful-dnd": "^4.0.1", "react-dom": "^16.9.0", "react-focus-lock": "^2.2.1", + "react-resizable": "^1.10.1", "resize-observer-polyfill": "^1.5.0", "sanitize-html": "^1.18.4", "text-encoding-utf-8": "^1.0.1", diff --git a/res/css/_components.scss b/res/css/_components.scss index 5a7630a51f..b047519d99 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -179,6 +179,7 @@ @import "./views/rooms/_RoomList.scss"; @import "./views/rooms/_RoomPreviewBar.scss"; @import "./views/rooms/_RoomRecoveryReminder.scss"; +@import "./views/rooms/_RoomSublist2.scss"; @import "./views/rooms/_RoomTile.scss"; @import "./views/rooms/_RoomUpgradeWarningBar.scss"; @import "./views/rooms/_SearchBar.scss"; diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss new file mode 100644 index 0000000000..bb760e7e6e --- /dev/null +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -0,0 +1,17 @@ +/* +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 "../../../../node_modules/react-resizable/css/styles.css"; diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index 5e9f6ffb23..b6fe37589c 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -18,7 +18,6 @@ limitations under the License. import * as React from "react"; import { _t, _td } from "../../../languageHandler"; -import { Layout } from '../../../resizer/distributors/roomsublist2'; import { RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex"; import { ResizeNotifier } from "../../../utils/ResizeNotifier"; import RoomListStore, { LISTS_UPDATE_EVENT, RoomListStore2 } from "../../../stores/room-list/RoomListStore2"; @@ -29,6 +28,7 @@ import dis from "../../../dispatcher/dispatcher"; import RoomSublist2 from "./RoomSublist2"; import { ActionPayload } from "../../../dispatcher/payloads"; import { NameFilterCondition } from "../../../stores/room-list/filters/NameFilterCondition"; +import { ListLayout } from "../../../stores/room-list/ListLayout"; /******************************************************************* * CAUTION * @@ -49,7 +49,7 @@ interface IProps { interface IState { sublists: ITagMap; - heights: Map; + layouts: Map; } const TAG_ORDER: TagID[] = [ @@ -127,20 +127,16 @@ const TAG_AESTHETICS: { }; export default class RoomList2 extends React.Component { - private sublistRefs: { [tagId: string]: React.RefObject } = {}; private sublistSizes: { [tagId: string]: number } = {}; private sublistCollapseStates: { [tagId: string]: boolean } = {}; - private unfilteredLayout: Layout; - private filteredLayout: Layout; private searchFilter: NameFilterCondition = new NameFilterCondition(); - private currentTagResize: TagID = null; constructor(props: IProps) { super(props); this.state = { sublists: {}, - heights: new Map(), + layouts: new Map(), }; this.loadSublistSizes(); } @@ -165,12 +161,12 @@ export default class RoomList2 extends React.Component { const newLists = store.orderedLists; console.log("new lists", newLists); - const heightMap = new Map(); + const layoutMap = new Map(); for (const tagId of Object.keys(newLists)) { - heightMap.set(tagId, store.layout.getPixelHeight(tagId)); + layoutMap.set(tagId, new ListLayout(tagId)); } - this.setState({sublists: newLists, heights: heightMap}); + this.setState({sublists: newLists, layouts: layoutMap}); }); } @@ -182,30 +178,6 @@ export default class RoomList2 extends React.Component { if (collapsedJson) this.sublistCollapseStates = JSON.parse(collapsedJson); } - private saveSublistSizes() { - window.localStorage.setItem("mx_roomlist_sizes", JSON.stringify(this.sublistSizes)); - window.localStorage.setItem("mx_roomlist_collapsed", JSON.stringify(this.sublistCollapseStates)); - } - - private onResizerMouseDown = (ev: React.MouseEvent) => { - const hr = ev.target as HTMLHRElement; - this.currentTagResize = hr.getAttribute("data-id"); - }; - - private onResizerMouseUp = (ev: React.MouseEvent) => { - this.currentTagResize = null; - }; - - private onMouseMove = (ev: React.MouseEvent) => { - ev.preventDefault(); - if (this.currentTagResize) { - const pixelHeight = this.state.heights.get(this.currentTagResize); - RoomListStore.instance.layout.setPixelHeight(this.currentTagResize, pixelHeight + ev.movementY); - this.state.heights.set(this.currentTagResize, RoomListStore.instance.layout.getPixelHeight(this.currentTagResize)); - this.forceUpdate(); - } - }; - private renderSublists(): React.ReactElement[] { const components: React.ReactElement[] = []; @@ -228,24 +200,19 @@ export default class RoomList2 extends React.Component { if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`); const onAddRoomFn = aesthetics.onAddRoom ? () => aesthetics.onAddRoom(dis) : null; - components.push(); - components.push(
); + components.push( + + ); } return components; @@ -260,8 +227,6 @@ export default class RoomList2 extends React.Component { onFocus={this.props.onFocus} onBlur={this.props.onBlur} onKeyDown={onKeyDownHandler} - onMouseUp={this.onResizerMouseUp} - onMouseMove={this.onMouseMove} className="mx_RoomList mx_RoomList2" role="tree" aria-label={_t("Rooms")} diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 2b5b131393..6705448764 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -20,7 +20,6 @@ import * as React from "react"; import { createRef } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; import classNames from 'classnames'; -import IndicatorScrollbar from "../../structures/IndicatorScrollbar"; import * as RoomNotifs from '../../../RoomNotifs'; import { RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex"; import { _t } from "../../../languageHandler"; @@ -28,6 +27,8 @@ import AccessibleButton from "../../views/elements/AccessibleButton"; import AccessibleTooltipButton from "../../views/elements/AccessibleTooltipButton"; import * as FormattingUtils from '../../../utils/FormattingUtils'; import RoomTile2 from "./RoomTile2"; +import { ResizableBox, ResizeCallbackData } from "react-resizable"; +import { ListLayout } from "../../../stores/room-list/ListLayout"; /******************************************************************* * CAUTION * @@ -45,7 +46,7 @@ interface IProps { onAddRoom?: () => void; addRoomLabel: string; isInvite: boolean; - height: number; // pixels + layout: ListLayout; // TODO: Collapsed state // TODO: Group invites @@ -183,6 +184,12 @@ export default class RoomSublist2 extends React.Component { ); } + private onResize = (e: React.MouseEvent, data: ResizeCallbackData) => { + const tileDiff = e.movementY < 0 ? -1 : +1; + this.props.layout.visibleTiles += tileDiff; + this.forceUpdate(); // because the layout doesn't trigger a re-render + }; + public render(): React.ReactElement { // TODO: Proper rendering // TODO: Error boundary @@ -200,11 +207,29 @@ export default class RoomSublist2 extends React.Component { if (tiles.length > 0) { // TODO: Lazy list rendering // TODO: Whatever scrolling magic needs to happen here + const layout = this.props.layout; // to shorten calls + const minTilesPx = layout.tilesToPixels(Math.min(tiles.length, layout.minVisibleTiles)); + const maxTilesPx = layout.tilesToPixels(tiles.length); + const tilesPx = layout.tilesToPixels(Math.min(tiles.length, layout.visibleTiles)); + let handles = ['s']; + if (layout.visibleTiles >= tiles.length && tiles.length <= layout.minVisibleTiles) { + handles = []; // no handles, we're at a minimum + } + const visibleTiles = tiles.slice(0, layout.visibleTiles); content = ( - {tiles} + + {visibleTiles} + ) } diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts new file mode 100644 index 0000000000..af6abe3297 --- /dev/null +++ b/src/stores/room-list/ListLayout.ts @@ -0,0 +1,65 @@ +/* +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. +*/ + +const TILE_HEIGHT_PX = 34; + +interface ISerializedListLayout { + numTiles: number; +} + +export class ListLayout { + private _n = 0; + + constructor(public readonly tagId) { + const serialized = localStorage.getItem(this.key); + if (serialized) { + // We don't use the setters as they cause writes. + const parsed = JSON.parse(serialized); + this._n = parsed.numTiles; + } + } + + public get tileHeight(): number { + return TILE_HEIGHT_PX; + } + + private get key(): string { + return `mx_sublist_layout_${this.tagId}_boxed`; + } + + public get visibleTiles(): number { + return Math.max(this._n, this.minVisibleTiles); + } + + public set visibleTiles(v: number) { + this._n = v; + localStorage.setItem(this.key, JSON.stringify(this.serialize())); + } + + public get minVisibleTiles(): number { + return 3; + } + + public tilesToPixels(n: number): number { + return n * this.tileHeight; + } + + private serialize(): ISerializedListLayout { + return { + numTiles: this.visibleTiles, + }; + } +} diff --git a/src/stores/room-list/RoomListLayoutStore.ts b/src/stores/room-list/RoomListLayoutStore.ts deleted file mode 100644 index cbd570b579..0000000000 --- a/src/stores/room-list/RoomListLayoutStore.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* -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. -*/ - -// TODO: Simplify the class load when we pick an approach for the list layout - -import { TagID } from "./models"; - -const TILE_HEIGHT_PX = 34; - -export class LayoutUnit { - constructor(public readonly multiplier: number) { - } - - public convert(val: number): number { - return Math.ceil(val * this.multiplier); - } - - public normalizePixels(pixels: number): number { - return this.convert(Math.ceil(pixels / this.multiplier)); - } - - public forNumTiles(n: number): number { - const unitsPerTile = TILE_HEIGHT_PX / this.multiplier; - return unitsPerTile * n; - } -} - -export const SMOOTH_RESIZE = new LayoutUnit(1); -export const CHUNKED_RESIZE = new LayoutUnit(TILE_HEIGHT_PX); - -export class RoomListLayoutStore { - public unit: LayoutUnit = SMOOTH_RESIZE; - public minTilesShown = 1; - - /** - * Minimum list height in pixels. - */ - public get minListHeight(): number { - return this.unit.forNumTiles(this.minTilesShown); - } - - private getStorageKey(tagId: TagID) { - return `mx_rlls_${tagId}_m_${this.unit.multiplier}`; - } - - public setPixelHeight(tagId: TagID, pixels: number): void { - localStorage.setItem(this.getStorageKey(tagId), JSON.stringify({pixels})); - } - - public getPixelHeight(tagId: TagID): number { - const stored = JSON.parse(localStorage.getItem(this.getStorageKey(tagId))); - let storedHeight = 0; - if (stored && stored.pixels) { - storedHeight = stored.pixels; - } - return this.unit.normalizePixels(Math.max(this.minListHeight, storedHeight)); - } - - // TODO: Remove helper functions for design iteration - - public beSmooth() { - this.unit = SMOOTH_RESIZE; - } - - public beChunked() { - this.unit = CHUNKED_RESIZE; - } - - public beDifferent(multiplier: number) { - this.unit = new LayoutUnit(multiplier); - } -} diff --git a/src/stores/room-list/RoomListStore2.ts b/src/stores/room-list/RoomListStore2.ts index 84033b5cca..af9970d3cc 100644 --- a/src/stores/room-list/RoomListStore2.ts +++ b/src/stores/room-list/RoomListStore2.ts @@ -29,7 +29,6 @@ import defaultDispatcher from "../../dispatcher/dispatcher"; import { readReceiptChangeIsFor } from "../../utils/read-receipts"; import { IFilterCondition } from "./filters/IFilterCondition"; import { TagWatcher } from "./TagWatcher"; -import { RoomListLayoutStore } from "./RoomListLayoutStore"; interface IState { tagsEnabled?: boolean; @@ -45,8 +44,6 @@ interface IState { export const LISTS_UPDATE_EVENT = "lists_update"; export class RoomListStore2 extends AsyncStore { - public readonly layout = new RoomListLayoutStore(); - private _matrixClient: MatrixClient; private initialListsGenerated = false; private enabled = false; diff --git a/yarn.lock b/yarn.lock index 56cf596fcf..ded8aa13f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2458,7 +2458,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@^2.1.2: +classnames@^2.1.2, classnames@^2.2.5: version "2.2.6" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== @@ -6858,7 +6858,7 @@ prop-types-exact@^1.2.0: object.assign "^4.1.0" reflect.ownkeys "^0.2.0" -prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@15.x, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -7062,6 +7062,14 @@ react-dom@^16.9.0: prop-types "^15.6.2" scheduler "^0.19.1" +react-draggable@^4.0.3: + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.2.tgz#f3cefecee25f467f865144cda0d066e5f05f94a0" + integrity sha512-zLQs4R4bnBCGnCVTZiD8hPsHtkiJxgMpGDlRESM+EHQo8ysXhKJ2GKdJ8UxxLJdRVceX1j19jy+hQS2wHislPQ== + dependencies: + classnames "^2.2.5" + prop-types "^15.6.0" + react-focus-lock@^2.2.1: version "2.3.1" resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.3.1.tgz#9d5d85899773609c7eefa4fc54fff6a0f5f2fc47" @@ -7106,6 +7114,14 @@ react-redux@^5.0.6: react-is "^16.6.0" react-lifecycles-compat "^3.0.0" +react-resizable@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-1.10.1.tgz#f0c2cf1d83b3470b87676ce6d6b02bbe3f4d8cd4" + integrity sha512-Jd/bKOKx6+19NwC4/aMLRu/J9/krfxlDnElP41Oc+oLiUWs/zwV1S9yBfBZRnqAwQb6vQ/HRSk3bsSWGSgVbpw== + dependencies: + prop-types "15.x" + react-draggable "^4.0.3" + react-test-renderer@^16.0.0-0, react-test-renderer@^16.9.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1" From be4f75bca920b0a9f45414aea9cc39d8701aba7a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 3 Jun 2020 21:52:05 -0600 Subject: [PATCH 03/14] Add a 'show more' button to room lists --- src/components/views/rooms/RoomSublist2.tsx | 44 ++++++++++++++++++--- src/i18n/strings/en_EN.json | 1 + 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 6705448764..a9852dd3d3 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -76,6 +76,17 @@ export default class RoomSublist2 extends React.Component { if (this.props.onAddRoom) this.props.onAddRoom(); }; + private onResize = (e: React.MouseEvent, data: ResizeCallbackData) => { + const tileDiff = e.movementY < 0 ? -1 : +1; + this.props.layout.visibleTiles += tileDiff; + this.forceUpdate(); // because the layout doesn't trigger a re-render + }; + + private onShowAllClick = () => { + this.props.layout.visibleTiles = this.numTiles; + this.forceUpdate(); // because the layout doesn't trigger a re-render + }; + private renderTiles(): React.ReactElement[] { const tiles: React.ReactElement[] = []; @@ -184,12 +195,6 @@ export default class RoomSublist2 extends React.Component { ); } - private onResize = (e: React.MouseEvent, data: ResizeCallbackData) => { - const tileDiff = e.movementY < 0 ? -1 : +1; - this.props.layout.visibleTiles += tileDiff; - this.forceUpdate(); // because the layout doesn't trigger a re-render - }; - public render(): React.ReactElement { // TODO: Proper rendering // TODO: Error boundary @@ -216,6 +221,33 @@ export default class RoomSublist2 extends React.Component { handles = []; // no handles, we're at a minimum } const visibleTiles = tiles.slice(0, layout.visibleTiles); + console.log({n: tiles.length, c: layout.visibleTiles}); + + // If we're hiding rooms, show a 'show more' button to the user. This button + // replaces the last visible tile, so will always show 2+ rooms. We do this + // because if it said "show 1 more room" we had might as well show that room + // instead. We also replace the last item so we don't have to adjust our math + // on pixel heights, etc. It's much easier to pretend the button is a tile. + if (tiles.length > layout.visibleTiles) { + // we have a cutoff condition - add the button to show all + + // we +1 to account for the room we're about to hide with our 'show more' button + const numMissing = (tiles.length - visibleTiles.length) + 1; + + // TODO: Copy TBD + // TODO: CSS TBD + // TODO: Show N more instead of infinity more? + // TODO: Safely use the same height of a tile, not hardcoded hacks + visibleTiles.splice(visibleTiles.length - 1, 1, ( +
+ {_t("Show %(n)s more rooms", {n: numMissing})} +
+ )); + } content = ( Date: Wed, 3 Jun 2020 21:53:58 -0600 Subject: [PATCH 04/14] Remove debugging --- src/components/views/rooms/RoomSublist2.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index a9852dd3d3..f2e5329ab0 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -221,7 +221,6 @@ export default class RoomSublist2 extends React.Component { handles = []; // no handles, we're at a minimum } const visibleTiles = tiles.slice(0, layout.visibleTiles); - console.log({n: tiles.length, c: layout.visibleTiles}); // If we're hiding rooms, show a 'show more' button to the user. This button // replaces the last visible tile, so will always show 2+ rooms. We do this From 83df79aab92f7d4e1c69580f848cb59328cc01a9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 09:19:03 -0600 Subject: [PATCH 05/14] Try variable resizing --- src/components/views/rooms/RoomSublist2.tsx | 5 +++-- src/stores/room-list/ListLayout.ts | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index f2e5329ab0..9c034ce749 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -77,7 +77,8 @@ export default class RoomSublist2 extends React.Component { }; private onResize = (e: React.MouseEvent, data: ResizeCallbackData) => { - const tileDiff = e.movementY < 0 ? -1 : +1; + const direction = e.movementY < 0 ? -1 : +1; + const tileDiff = this.props.layout.pixelsToTiles(Math.abs(e.movementY)) * direction; this.props.layout.visibleTiles += tileDiff; this.forceUpdate(); // because the layout doesn't trigger a re-render }; @@ -254,7 +255,7 @@ export default class RoomSublist2 extends React.Component { axis="y" minConstraints={[-1, minTilesPx]} maxConstraints={[-1, maxTilesPx]} - draggableOpts={{grid: [-1, layout.tileHeight]}} + draggableOpts={{grid: [-1, 1]}} resizeHandles={handles} onResize={this.onResize} className="mx_RoomSublist2_resizeBox" diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts index af6abe3297..fd57a03ca1 100644 --- a/src/stores/room-list/ListLayout.ts +++ b/src/stores/room-list/ListLayout.ts @@ -57,6 +57,10 @@ export class ListLayout { return n * this.tileHeight; } + public pixelsToTiles(px: number): number { + return px / this.tileHeight; + } + private serialize(): ISerializedListLayout { return { numTiles: this.visibleTiles, From a3fdd643d79ec3b2eb725380991b8d08d9db1c0c Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 09:57:16 -0600 Subject: [PATCH 06/14] Add hacky math support --- src/components/views/rooms/RoomSublist2.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 9c034ce749..cc56f92769 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -221,14 +221,20 @@ export default class RoomSublist2 extends React.Component { if (layout.visibleTiles >= tiles.length && tiles.length <= layout.minVisibleTiles) { handles = []; // no handles, we're at a minimum } - const visibleTiles = tiles.slice(0, layout.visibleTiles); + + let nVisible = Math.floor(layout.visibleTiles); + if (localStorage.getItem("mx_rl_mathfn")) { + nVisible = Math[localStorage.getItem("mx_rl_mathfn")](layout.visibleTiles); + } + console.log({nVisible}) + const visibleTiles = tiles.slice(0, nVisible); // If we're hiding rooms, show a 'show more' button to the user. This button // replaces the last visible tile, so will always show 2+ rooms. We do this // because if it said "show 1 more room" we had might as well show that room // instead. We also replace the last item so we don't have to adjust our math // on pixel heights, etc. It's much easier to pretend the button is a tile. - if (tiles.length > layout.visibleTiles) { + if (tiles.length > nVisible) { // we have a cutoff condition - add the button to show all // we +1 to account for the room we're about to hide with our 'show more' button From 2fe56276f2bdf2f24fbe64149993710122e83549 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 10:07:41 -0600 Subject: [PATCH 07/14] css for vis --- res/css/views/rooms/_RoomSublist2.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index bb760e7e6e..abc3133fc1 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -15,3 +15,8 @@ limitations under the License. */ @import "../../../../node_modules/react-resizable/css/styles.css"; + +.mx_RoomList2 .mx_RoomSubList_labelContainer { + z-index: 12; + background-color: purple; +} From 434f6ea4d470ac6d1de2cd16c7663ebc8030d97c Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 16:36:14 -0600 Subject: [PATCH 08/14] Remove legacy sublist sizing --- src/components/views/rooms/RoomList2.tsx | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index b6fe37589c..15aa880109 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -127,8 +127,6 @@ const TAG_AESTHETICS: { }; export default class RoomList2 extends React.Component { - private sublistSizes: { [tagId: string]: number } = {}; - private sublistCollapseStates: { [tagId: string]: boolean } = {}; private searchFilter: NameFilterCondition = new NameFilterCondition(); constructor(props: IProps) { @@ -138,7 +136,6 @@ export default class RoomList2 extends React.Component { sublists: {}, layouts: new Map(), }; - this.loadSublistSizes(); } public componentDidUpdate(prevProps: Readonly): void { @@ -170,14 +167,6 @@ export default class RoomList2 extends React.Component { }); } - private loadSublistSizes() { - const sizesJson = window.localStorage.getItem("mx_roomlist_sizes"); - if (sizesJson) this.sublistSizes = JSON.parse(sizesJson); - - const collapsedJson = window.localStorage.getItem("mx_roomlist_collapsed"); - if (collapsedJson) this.sublistCollapseStates = JSON.parse(collapsedJson); - } - private renderSublists(): React.ReactElement[] { const components: React.ReactElement[] = []; From f347019cf86bf8243fb643c949fa804ce6c6a0c4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 21:37:10 -0600 Subject: [PATCH 09/14] Remove obviously questionable color choices --- res/css/views/rooms/_RoomSublist2.scss | 1 - src/components/views/rooms/RoomSublist2.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index abc3133fc1..1dfaf3fb1a 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -18,5 +18,4 @@ limitations under the License. .mx_RoomList2 .mx_RoomSubList_labelContainer { z-index: 12; - background-color: purple; } diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index cc56f92769..3aa1ea3566 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -247,7 +247,7 @@ export default class RoomSublist2 extends React.Component { visibleTiles.splice(visibleTiles.length - 1, 1, (
{_t("Show %(n)s more rooms", {n: numMissing})} From 0694637b06af0288b268deec4e271b4026395640 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 21:38:06 -0600 Subject: [PATCH 10/14] Remove debug --- src/components/views/rooms/RoomSublist2.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 3aa1ea3566..a64f4bf6ba 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -226,7 +226,6 @@ export default class RoomSublist2 extends React.Component { if (localStorage.getItem("mx_rl_mathfn")) { nVisible = Math[localStorage.getItem("mx_rl_mathfn")](layout.visibleTiles); } - console.log({nVisible}) const visibleTiles = tiles.slice(0, nVisible); // If we're hiding rooms, show a 'show more' button to the user. This button From e90e70bd77f9de1ad408a8f714c60b2ccec62d4c Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 21:43:33 -0600 Subject: [PATCH 11/14] Misc cleanup --- res/css/views/rooms/_RoomList.scss | 4 ---- res/css/views/rooms/_RoomSublist2.scss | 2 +- src/components/views/rooms/RoomSublist2.tsx | 7 ++----- src/i18n/strings/en_EN.json | 2 +- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss index 7abf86cb0e..c23c19699d 100644 --- a/res/css/views/rooms/_RoomList.scss +++ b/res/css/views/rooms/_RoomList.scss @@ -15,10 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_RoomList2_resizer { - cursor: ns-resize; -} - .mx_RoomList.mx_RoomList2 { overflow-y: auto; } diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index 1dfaf3fb1a..9ab1785566 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -17,5 +17,5 @@ limitations under the License. @import "../../../../node_modules/react-resizable/css/styles.css"; .mx_RoomList2 .mx_RoomSubList_labelContainer { - z-index: 12; + z-index: 12; } diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index a64f4bf6ba..548166815f 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -239,17 +239,15 @@ export default class RoomSublist2 extends React.Component { // we +1 to account for the room we're about to hide with our 'show more' button const numMissing = (tiles.length - visibleTiles.length) + 1; - // TODO: Copy TBD // TODO: CSS TBD - // TODO: Show N more instead of infinity more? - // TODO: Safely use the same height of a tile, not hardcoded hacks + // TODO: Make this an actual tile visibleTiles.splice(visibleTiles.length - 1, 1, (
- {_t("Show %(n)s more rooms", {n: numMissing})} + {_t("Show %(n)s more", {n: numMissing})}
)); } @@ -260,7 +258,6 @@ export default class RoomSublist2 extends React.Component { axis="y" minConstraints={[-1, minTilesPx]} maxConstraints={[-1, maxTilesPx]} - draggableOpts={{grid: [-1, 1]}} resizeHandles={handles} onResize={this.onResize} className="mx_RoomSublist2_resizeBox" diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 884192b22a..0aa4c3779e 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1136,7 +1136,7 @@ "Jump to first unread room.": "Jump to first unread room.", "Jump to first invite.": "Jump to first invite.", "Add room": "Add room", - "Show %(n)s more rooms": "Show %(n)s more rooms", + "Show %(n)s more": "Show %(n)s more", "Options": "Options", "%(count)s unread messages including mentions.|other": "%(count)s unread messages including mentions.", "%(count)s unread messages including mentions.|one": "1 unread mention.", From 1f11298aa327d15067ea0b14d10ecd6d50c14d3e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 4 Jun 2020 21:45:32 -0600 Subject: [PATCH 12/14] Annotate hacky math --- src/components/views/rooms/RoomSublist2.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 548166815f..e20a36d6ce 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -222,6 +222,7 @@ export default class RoomSublist2 extends React.Component { handles = []; // no handles, we're at a minimum } + // TODO: Remove Math hacks let nVisible = Math.floor(layout.visibleTiles); if (localStorage.getItem("mx_rl_mathfn")) { nVisible = Math[localStorage.getItem("mx_rl_mathfn")](layout.visibleTiles); From 51038b0c02d934ae14a94fddeb9d889acdc8d6d0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jun 2020 11:03:18 -0600 Subject: [PATCH 13/14] Replace math hacks with temporary placeholder --- src/components/views/rooms/RoomSublist2.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index e20a36d6ce..dd0d591c53 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -222,11 +222,8 @@ export default class RoomSublist2 extends React.Component { handles = []; // no handles, we're at a minimum } - // TODO: Remove Math hacks - let nVisible = Math.floor(layout.visibleTiles); - if (localStorage.getItem("mx_rl_mathfn")) { - nVisible = Math[localStorage.getItem("mx_rl_mathfn")](layout.visibleTiles); - } + // TODO: This might need adjustment, however for now it is fine as a round. + const nVisible = Math.round(layout.visibleTiles); const visibleTiles = tiles.slice(0, nVisible); // If we're hiding rooms, show a 'show more' button to the user. This button @@ -242,6 +239,7 @@ export default class RoomSublist2 extends React.Component { // TODO: CSS TBD // TODO: Make this an actual tile + // TODO: This is likely to pop out of the list, consider that. visibleTiles.splice(visibleTiles.length - 1, 1, (
Date: Fri, 5 Jun 2020 13:14:44 -0600 Subject: [PATCH 14/14] Minor clarity --- src/components/views/rooms/RoomSublist2.tsx | 1 + src/stores/room-list/ListLayout.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index dd0d591c53..d3bb19729d 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -235,6 +235,7 @@ export default class RoomSublist2 extends React.Component { // we have a cutoff condition - add the button to show all // we +1 to account for the room we're about to hide with our 'show more' button + // this results in the button always being 1+, and not needing an i18n `count`. const numMissing = (tiles.length - visibleTiles.length) + 1; // TODO: CSS TBD diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts index fd57a03ca1..b41d56be3e 100644 --- a/src/stores/room-list/ListLayout.ts +++ b/src/stores/room-list/ListLayout.ts @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { TagID } from "./models"; + const TILE_HEIGHT_PX = 34; interface ISerializedListLayout { @@ -23,7 +25,7 @@ interface ISerializedListLayout { export class ListLayout { private _n = 0; - constructor(public readonly tagId) { + constructor(public readonly tagId: TagID) { const serialized = localStorage.getItem(this.key); if (serialized) { // We don't use the setters as they cause writes.