From ce68314de96645a0e4b0c98a2579d33855bdf2be Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 9 Jul 2020 14:43:20 +0000 Subject: [PATCH 01/14] Revert "Merge pull request #4932 from matrix-org/travis/room-list/invisible-show-more" This reverts commit f58a0a753897b00b7a8ae5647c6345bb88057aa4. --- res/css/views/rooms/_RoomSublist2.scss | 20 +++++++++++++++----- src/components/views/rooms/RoomSublist2.tsx | 10 ++-------- src/stores/room-list/ListLayout.ts | 4 ++++ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index 83e7e68563..1d13f25b8f 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -187,16 +187,16 @@ limitations under the License. flex-direction: column; overflow: hidden; - .mx_RoomSublist2_placeholder { - height: 44px; // Height of a room tile plus margins - } - .mx_RoomSublist2_showNButton { cursor: pointer; font-size: $font-13px; line-height: $font-18px; color: $roomtile2-preview-color; + // This is the same color as the left panel background because it needs + // to occlude the lastmost tile in the list. + background-color: $roomlist2-bg-color; + // Update the render() function for RoomSublist2 if these change // Update the ListLayout class for minVisibleTiles if these change. // @@ -209,7 +209,7 @@ limitations under the License. // We force this to the bottom so it will overlap rooms as needed. // We account for the space it takes up (24px) in the code through padding. position: absolute; - bottom: 0; + bottom: 0; // the height of the resize handle left: 0; right: 0; @@ -236,6 +236,16 @@ limitations under the License. .mx_RoomSublist2_showLessButtonChevron { mask-image: url('$(res)/img/feather-customised/chevron-up.svg'); } + + &.mx_RoomSublist2_isCutting::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + box-shadow: 0px -2px 3px rgba(46, 47, 50, 0.08); + } } // Class name comes from the ResizableBox component diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index c3ac85e2de..73aa97b6e8 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -562,8 +562,10 @@ export default class RoomSublist2 extends React.Component { if (visibleTiles.length > 0) { const layout = this.layout; // to shorten calls + const maxTilesFactored = layout.tilesWithResizerBoxFactor(this.numTiles); const showMoreBtnClasses = classNames({ 'mx_RoomSublist2_showNButton': true, + 'mx_RoomSublist2_isCutting': this.state.isResizing && layout.visibleTiles < maxTilesFactored, }); // If we're hiding rooms, show a 'show more' button to the user. This button @@ -642,14 +644,6 @@ export default class RoomSublist2 extends React.Component { const tilesWithoutPadding = Math.min(relativeTiles, layout.visibleTiles); const tilesPx = layout.calculateTilesToPixelsMin(relativeTiles, tilesWithoutPadding, padding); - // Now that we know our padding constraints, let's find out if we need to chop off the - // last rendered visible tile so it doesn't collide with the 'show more' button - let visibleUnpaddedTiles = Math.round(layout.visibleTiles - layout.pixelsToTiles(padding)); - if (visibleUnpaddedTiles === visibleTiles.length - 1) { - const placeholder =
; - visibleTiles.splice(visibleUnpaddedTiles, 1, placeholder); - } - const dimensions = { height: tilesPx, }; diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts index 5169c5e4e5..99674fe74f 100644 --- a/src/stores/room-list/ListLayout.ts +++ b/src/stores/room-list/ListLayout.ts @@ -109,6 +109,10 @@ export class ListLayout { return this.tilesToPixels(Math.min(maxTiles, n)) + padding; } + public tilesWithResizerBoxFactor(n: number): number { + return n + RESIZER_BOX_FACTOR; + } + public tilesWithPadding(n: number, paddingPx: number): number { return this.pixelsToTiles(this.tilesToPixelsWithPadding(n, paddingPx)); } From 859f65659c03d2b930f62d142651cd5116c21dd0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 9 Jul 2020 13:07:13 -0600 Subject: [PATCH 02/14] Attempt to support a hard cutoff with the show more button Known issues: * Causes scroll jumps when the button gets added to DOM * Resize handle is invisible when there's a show more button TODO: * Clean up comments * Clean up useless code (all the padding stuff isn't needed) --- res/css/views/rooms/_RoomSublist2.scss | 120 ++++++++++---------- src/components/views/rooms/RoomSublist2.tsx | 41 ++++--- src/stores/room-list/ListLayout.ts | 3 +- 3 files changed, 84 insertions(+), 80 deletions(-) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index 1d13f25b8f..6a77056917 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -179,7 +179,6 @@ limitations under the License. } .mx_RoomSublist2_resizeBox { - margin-bottom: 4px; // for the resize handle position: relative; // Create another flexbox column for the tiles @@ -187,65 +186,12 @@ limitations under the License. flex-direction: column; overflow: hidden; - .mx_RoomSublist2_showNButton { - cursor: pointer; - font-size: $font-13px; - line-height: $font-18px; - color: $roomtile2-preview-color; - - // This is the same color as the left panel background because it needs - // to occlude the lastmost tile in the list. - background-color: $roomlist2-bg-color; - - // Update the render() function for RoomSublist2 if these change - // Update the ListLayout class for minVisibleTiles if these change. - // - // At 24px high, 8px padding on the top and 4px padding on the bottom this equates to 0.73 of - // a tile due to how the padding calculations work. - height: 24px; - padding-top: 8px; - padding-bottom: 4px; - - // We force this to the bottom so it will overlap rooms as needed. - // We account for the space it takes up (24px) in the code through padding. + .mx_RoomSublist2_resizerHandles_showNButton { position: absolute; - bottom: 0; // the height of the resize handle + bottom: -32px; // height of the button left: 0; right: 0; - - // We create a flexbox to cheat at alignment - display: flex; - align-items: center; - - .mx_RoomSublist2_showNButtonChevron { - position: relative; - width: 16px; - height: 16px; - margin-left: 12px; - margin-right: 18px; - mask-position: center; - mask-size: contain; - mask-repeat: no-repeat; - background: $roomtile2-preview-color; - } - - .mx_RoomSublist2_showMoreButtonChevron { - mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); - } - - .mx_RoomSublist2_showLessButtonChevron { - mask-image: url('$(res)/img/feather-customised/chevron-up.svg'); - } - - &.mx_RoomSublist2_isCutting::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - box-shadow: 0px -2px 3px rgba(46, 47, 50, 0.08); - } + height: 4px; // height of the handle } // Class name comes from the ResizableBox component @@ -277,6 +223,56 @@ limitations under the License. } } + .mx_RoomSublist2_showNButton { + cursor: pointer; + font-size: $font-13px; + line-height: $font-18px; + color: $roomtile2-preview-color; + + // Update the render() function for RoomSublist2 if these change + // Update the ListLayout class for minVisibleTiles if these change. + // + // At 24px high, 8px padding on the top and 4px padding on the bottom this equates to 0.73 of + // a tile due to how the padding calculations work. + height: 24px; + padding-top: 8px; + padding-bottom: 4px; + + // We create a flexbox to cheat at alignment + display: flex; + align-items: center; + + .mx_RoomSublist2_showNButtonChevron { + position: relative; + width: 16px; + height: 16px; + margin-left: 12px; + margin-right: 18px; + mask-position: center; + mask-size: contain; + mask-repeat: no-repeat; + background: $roomtile2-preview-color; + } + + .mx_RoomSublist2_showMoreButtonChevron { + mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); + } + + .mx_RoomSublist2_showLessButtonChevron { + mask-image: url('$(res)/img/feather-customised/chevron-up.svg'); + } + + &.mx_RoomSublist2_isCutting::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + box-shadow: 0px -2px 3px rgba(46, 47, 50, 0.08); + } + } + &.mx_RoomSublist2_hasMenuOpen, &:not(.mx_RoomSublist2_minimized) > .mx_RoomSublist2_headerContainer:focus-within, &:not(.mx_RoomSublist2_minimized) > .mx_RoomSublist2_headerContainer:hover { @@ -322,13 +318,13 @@ limitations under the License. .mx_RoomSublist2_resizeBox { align-items: center; + } - .mx_RoomSublist2_showNButton { - flex-direction: column; + .mx_RoomSublist2_showNButton { + flex-direction: column; - .mx_RoomSublist2_showNButtonChevron { - margin-right: 12px; // to center - } + .mx_RoomSublist2_showNButtonChevron { + margin-right: 12px; // to center } } diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 73aa97b6e8..caa679f1d0 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -119,7 +119,7 @@ export default class RoomSublist2 extends React.Component { } private get numVisibleTiles(): number { - const nVisible = Math.floor(this.layout.visibleTiles); + const nVisible = Math.ceil(this.layout.visibleTiles); return Math.min(nVisible, this.numTiles); } @@ -635,8 +635,8 @@ export default class RoomSublist2 extends React.Component { // The padding is variable though, so figure out what we need padding for. let padding = 0; - if (showNButton) padding += SHOW_N_BUTTON_HEIGHT; - padding += RESIZE_HANDLE_HEIGHT; // always append the handle height + //if (showNButton) padding += SHOW_N_BUTTON_HEIGHT; + //padding += RESIZE_HANDLE_HEIGHT; // always append the handle height const relativeTiles = layout.tilesWithPadding(this.numTiles, padding); const minTilesPx = layout.calculateTilesToPixelsMin(relativeTiles, layout.minVisibleTiles, padding); @@ -644,25 +644,32 @@ export default class RoomSublist2 extends React.Component { const tilesWithoutPadding = Math.min(relativeTiles, layout.visibleTiles); const tilesPx = layout.calculateTilesToPixelsMin(relativeTiles, tilesWithoutPadding, padding); + const handleWrapperClasses = classNames({ + 'mx_RoomSublist2_resizerHandles': true, + 'mx_RoomSublist2_resizerHandles_showNButton': !!showNButton, + }); + const dimensions = { height: tilesPx, }; content = ( - - {visibleTiles} + + + {visibleTiles} + {showNButton} - + ); } diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts index 99674fe74f..f1900487bc 100644 --- a/src/stores/room-list/ListLayout.ts +++ b/src/stores/room-list/ListLayout.ts @@ -20,7 +20,8 @@ const TILE_HEIGHT_PX = 44; // this comes from the CSS where the show more button is // mathematically this percent of a tile when floating. -const RESIZER_BOX_FACTOR = 0.78; +//const RESIZER_BOX_FACTOR = 0.78; +const RESIZER_BOX_FACTOR = 0; interface ISerializedListLayout { numTiles: number; From d5a3071518a095f19b82d3fb784b6872372ae063 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:29:39 +0200 Subject: [PATCH 03/14] put show more button inside resizer this way we have a flexbox layout in the resizer with: - the resize handle (fixed) - the show more/less button, if any (fixed) - the list of tiles (grabbing whatever is left) --- res/css/views/rooms/_RoomSublist2.scss | 20 +++++++++++++++----- src/components/views/rooms/RoomSublist2.tsx | 6 ++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index 6a77056917..bd00a7fc72 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -186,12 +186,22 @@ limitations under the License. flex-direction: column; overflow: hidden; + .mx_RoomSublist2_tiles { + flex: 1 0 0; + overflow: hidden; + // need this to be flex otherwise the overflow hidden from above + // sometimes vertically centers the clipped list ... no idea why it would do this + // as the box model should be top aligned. Happens in both FF and Chromium + display: flex; + flex-direction: column; + } + .mx_RoomSublist2_resizerHandles_showNButton { - position: absolute; - bottom: -32px; // height of the button - left: 0; - right: 0; - height: 4px; // height of the handle + flex: 0 0 32px; + } + + .mx_RoomSublist2_resizerHandles { + flex: 0 0 4px; } // Class name comes from the ResizableBox component diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index caa679f1d0..70d65f2437 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -666,9 +666,11 @@ export default class RoomSublist2 extends React.Component { className="mx_RoomSublist2_resizeBox" enable={handles} > - {visibleTiles} +
+ {visibleTiles} +
+ {showNButton} - {showNButton} ); } From 725b7f895015c5af42b6d4535f46e6928f9baca1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:30:52 +0200 Subject: [PATCH 04/14] make show more button a bit less tall --- res/css/views/rooms/_RoomSublist2.scss | 4 ---- src/components/views/rooms/RoomSublist2.tsx | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index bd00a7fc72..3744641390 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -241,11 +241,7 @@ limitations under the License. // Update the render() function for RoomSublist2 if these change // Update the ListLayout class for minVisibleTiles if these change. - // - // At 24px high, 8px padding on the top and 4px padding on the bottom this equates to 0.73 of - // a tile due to how the padding calculations work. height: 24px; - padding-top: 8px; padding-bottom: 4px; // We create a flexbox to cheat at alignment diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 70d65f2437..66b5a4aad1 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -59,7 +59,7 @@ import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore"; * warning disappears. * *******************************************************************/ -const SHOW_N_BUTTON_HEIGHT = 32; // As defined by CSS +const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS export const HEADER_HEIGHT = 32; // As defined by CSS From 49f7170d9591068bff30203bae82e8e52237bded Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:31:53 +0200 Subject: [PATCH 05/14] extract type --- src/components/views/rooms/RoomSublist2.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 66b5a4aad1..c219b87c92 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -86,6 +86,12 @@ interface IProps { // TODO: Account for https://github.com/vector-im/riot-web/issues/14179 } +// TODO: Use re-resizer's NumberSize when it is exposed as the type +interface ResizeDelta { + width: number, + height: number, +} + type PartialDOMRect = Pick; interface IState { @@ -161,7 +167,7 @@ export default class RoomSublist2 extends React.Component { e: MouseEvent | TouchEvent, travelDirection: Direction, refToElement: HTMLDivElement, - delta: { width: number, height: number }, // TODO: Use re-resizer's NumberSize when it is exposed as the type + delta: ResizeDelta, ) => { // Do some sanity checks, but in reality we shouldn't need these. if (travelDirection !== "bottom") return; From 652fb9e6130323553c5fa5aa83646ed7bea589e5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:35:07 +0200 Subject: [PATCH 06/14] track height in pixels in component state --- src/components/views/rooms/RoomSublist2.tsx | 47 +++++++++++++-------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index c219b87c92..13690bd1ca 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -111,15 +111,36 @@ export default class RoomSublist2 extends React.Component { this.layout = RoomListLayoutStore.instance.getLayoutFor(this.props.tagId); + const height = this.calculateInitialHeight(); this.state = { notificationState: RoomNotificationStateStore.instance.getListState(this.props.tagId), contextMenuPosition: null, isResizing: false, + height, }; this.state.notificationState.setRooms(this.props.rooms); this.dispatcherRef = defaultDispatcher.register(this.onAction); } + private calculateInitialHeight() { + const requestedVisibleTiles = Math.max(Math.floor(this.layout.visibleTiles), this.layout.minVisibleTiles); + const tileCount = Math.min(this.numTiles, requestedVisibleTiles); + const height = this.layout.tilesToPixelsWithPadding(tileCount, this.padding); + return height; + } + + private get padding() { + let padding = RESIZE_HANDLE_HEIGHT; + // this is used for calculating the max height of the whole container, + // and takes into account whether there should be room reserved for the show less button + // when fully expanded. Note that the show more button might still be shown when not fully expanded, + // but in this case it will take the space of a tile and we don't need to reserve space for it. + if (this.numTiles > this.layout.defaultVisibleTiles) { + padding += SHOW_N_BUTTON_HEIGHT; + } + return padding; + } + private get numTiles(): number { return (this.props.rooms || []).length + (this.props.extraBadTilesThatShouldntExist || []).length; } @@ -568,7 +589,11 @@ export default class RoomSublist2 extends React.Component { if (visibleTiles.length > 0) { const layout = this.layout; // to shorten calls - const maxTilesFactored = layout.tilesWithResizerBoxFactor(this.numTiles); + const minTiles = Math.min(layout.minVisibleTiles, this.numTiles); + const showMoreAtMinHeight = minTiles < this.numTiles; + const minHeightPadding = RESIZE_HANDLE_HEIGHT + (showMoreAtMinHeight ? SHOW_N_BUTTON_HEIGHT : 0); + const minTilesPx = layout.tilesToPixelsWithPadding(minTiles, minHeightPadding); + const maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, this.padding); const showMoreBtnClasses = classNames({ 'mx_RoomSublist2_showNButton': true, 'mx_RoomSublist2_isCutting': this.state.isResizing && layout.visibleTiles < maxTilesFactored, @@ -578,9 +603,9 @@ export default class RoomSublist2 extends React.Component { // floats above the resize handle, if we have one present. If the user has all // tiles visible, it becomes 'show less'. let showNButton = null; - if (this.numTiles > visibleTiles.length) { // we have a cutoff condition - add the button to show all const numMissing = this.numTiles - visibleTiles.length; + if (maxTilesPx > this.state.height) { let showMoreText = ( {_t("Show %(count)s more", {count: numMissing})} @@ -595,7 +620,7 @@ export default class RoomSublist2 extends React.Component { {showMoreText} ); - } else if (this.numTiles <= visibleTiles.length && this.numTiles > this.layout.defaultVisibleTiles) { + } else if (this.numTiles > this.layout.defaultVisibleTiles) { // we have all tiles visible - add a button to show less let showLessText = ( @@ -639,29 +664,15 @@ export default class RoomSublist2 extends React.Component { // goes backwards and can become wildly incorrect (visibleTiles says 18 when there's // only mathematically 7 possible). - // The padding is variable though, so figure out what we need padding for. - let padding = 0; - //if (showNButton) padding += SHOW_N_BUTTON_HEIGHT; - //padding += RESIZE_HANDLE_HEIGHT; // always append the handle height - - const relativeTiles = layout.tilesWithPadding(this.numTiles, padding); - const minTilesPx = layout.calculateTilesToPixelsMin(relativeTiles, layout.minVisibleTiles, padding); - const maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, padding); - const tilesWithoutPadding = Math.min(relativeTiles, layout.visibleTiles); - const tilesPx = layout.calculateTilesToPixelsMin(relativeTiles, tilesWithoutPadding, padding); - const handleWrapperClasses = classNames({ 'mx_RoomSublist2_resizerHandles': true, 'mx_RoomSublist2_resizerHandles_showNButton': !!showNButton, }); - const dimensions = { - height: tilesPx, - }; content = ( Date: Fri, 10 Jul 2020 18:36:33 +0200 Subject: [PATCH 07/14] make all height changes update component state also set visibleTiles as side-effect --- src/components/views/rooms/RoomSublist2.tsx | 46 ++++++++++----------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 13690bd1ca..713b70ce94 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -110,7 +110,7 @@ export default class RoomSublist2 extends React.Component { super(props); this.layout = RoomListLayoutStore.instance.getLayoutFor(this.props.tagId); - + this.heightAtStart = 0; const height = this.calculateInitialHeight(); this.state = { notificationState: RoomNotificationStateStore.instance.getListState(this.props.tagId), @@ -184,47 +184,45 @@ export default class RoomSublist2 extends React.Component { if (this.props.onAddRoom) this.props.onAddRoom(); }; + private applyHeightChange(newHeight: number) { + const heightInTiles = Math.ceil(this.layout.pixelsToTiles(newHeight - this.padding)); + this.layout.visibleTiles = Math.min(this.numTiles, heightInTiles); + } + private onResize = ( e: MouseEvent | TouchEvent, travelDirection: Direction, refToElement: HTMLDivElement, delta: ResizeDelta, ) => { - // Do some sanity checks, but in reality we shouldn't need these. - if (travelDirection !== "bottom") return; - if (delta.height === 0) return; // something went wrong, so just ignore it. - - // NOTE: the movement in the MouseEvent (not present on a TouchEvent) is inaccurate - // for our purposes. The delta provided by the library is also a change *from when - // resizing started*, meaning it is fairly useless for us. This is why we just use - // the client height and run with it. - - const heightBefore = this.layout.visibleTiles; - const heightInTiles = this.layout.pixelsToTiles(refToElement.clientHeight); - this.layout.setVisibleTilesWithin(heightInTiles, this.numTiles); - if (heightBefore === this.layout.visibleTiles) return; // no-op - this.forceUpdate(); // because the layout doesn't trigger a re-render + const newHeight = this.heightAtStart + delta.height; + this.applyHeightChange(newHeight); + this.setState({height: newHeight}); }; private onResizeStart = () => { + this.heightAtStart = this.state.height; this.setState({isResizing: true}); }; - private onResizeStop = () => { - this.setState({isResizing: false}); + private onResizeStop = (e, direction, ref, d) => { + const newHeight = this.heightAtStart + d.height; + this.applyHeightChange(newHeight); + this.setState({isResizing: false, height: newHeight}); }; private onShowAllClick = () => { - const numVisibleTiles = this.numVisibleTiles; - this.layout.visibleTiles = this.layout.tilesWithPadding(this.numTiles, MAX_PADDING_HEIGHT); - this.forceUpdate(); // because the layout doesn't trigger a re-render - setImmediate(this.focusRoomTile, numVisibleTiles); // focus the tile after the current bottom one + const newHeight = this.layout.tilesToPixelsWithPadding(this.numTiles, this.padding); + this.applyHeightChange(newHeight); + this.setState({height: newHeight}, () => { + this.focusRoomTile(this.numTiles - 1); + }); }; private onShowLessClick = () => { - this.layout.visibleTiles = this.layout.defaultVisibleTiles; - this.forceUpdate(); // because the layout doesn't trigger a re-render - // focus will flow to the show more button here + const newHeight = this.layout.tilesToPixelsWithPadding(this.layout.defaultVisibleTiles, this.padding); + this.applyHeightChange(newHeight); + this.setState({height: newHeight}); }; private focusRoomTile = (index: number) => { From 86817430c51cbad1234c200c61ff8de56f8ab415 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:37:58 +0200 Subject: [PATCH 08/14] update initially shown amount of tiles on component update as rooms aren't all available at ctor time --- src/components/views/rooms/RoomSublist2.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 713b70ce94..6acb5f929c 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -142,7 +142,11 @@ export default class RoomSublist2 extends React.Component { } private get numTiles(): number { - return (this.props.rooms || []).length + (this.props.extraBadTilesThatShouldntExist || []).length; + return RoomSublist2.calcNumTiles(this.props); + } + + private static calcNumTiles(props) { + return (props.rooms || []).length + (props.extraBadTilesThatShouldntExist || []).length; } private get numVisibleTiles(): number { @@ -150,8 +154,13 @@ export default class RoomSublist2 extends React.Component { return Math.min(nVisible, this.numTiles); } - public componentDidUpdate() { + public componentDidUpdate(prevProps) { this.state.notificationState.setRooms(this.props.rooms); + // as the rooms can come in one by one we need to reevaluate + // the amount of available rooms to cap the amount of requested visible rooms by the layout + if (RoomSublist2.calcNumTiles(prevProps) !== this.numTiles) { + this.setState({height: this.calculateInitialHeight()}); + } } public componentWillUnmount() { From e2aa6ecf6b6dd9a9f0290fef092d1de8cc2afee7 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:38:32 +0200 Subject: [PATCH 09/14] fix show X more counter --- src/components/views/rooms/RoomSublist2.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 6acb5f929c..1a1a45b7cf 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -610,9 +610,11 @@ export default class RoomSublist2 extends React.Component { // floats above the resize handle, if we have one present. If the user has all // tiles visible, it becomes 'show less'. let showNButton = null; - // we have a cutoff condition - add the button to show all - const numMissing = this.numTiles - visibleTiles.length; + if (maxTilesPx > this.state.height) { + const nonPaddedHeight = this.state.height - RESIZE_HANDLE_HEIGHT - SHOW_N_BUTTON_HEIGHT; + const amountFullyShown = Math.floor(nonPaddedHeight / this.layout.tileHeight); + const numMissing = this.numTiles - amountFullyShown; let showMoreText = ( {_t("Show %(count)s more", {count: numMissing})} From 85ac256231e75dcef0d3f82d463768e90c39992a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:38:53 +0200 Subject: [PATCH 10/14] cleanup --- res/css/views/rooms/_RoomSublist2.scss | 10 ---------- src/components/views/rooms/RoomSublist2.tsx | 2 -- 2 files changed, 12 deletions(-) diff --git a/res/css/views/rooms/_RoomSublist2.scss b/res/css/views/rooms/_RoomSublist2.scss index 3744641390..73dc7d58b8 100644 --- a/res/css/views/rooms/_RoomSublist2.scss +++ b/res/css/views/rooms/_RoomSublist2.scss @@ -267,16 +267,6 @@ limitations under the License. .mx_RoomSublist2_showLessButtonChevron { mask-image: url('$(res)/img/feather-customised/chevron-up.svg'); } - - &.mx_RoomSublist2_isCutting::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - box-shadow: 0px -2px 3px rgba(46, 47, 50, 0.08); - } } &.mx_RoomSublist2_hasMenuOpen, diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 1a1a45b7cf..5a7bfa3990 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -585,7 +585,6 @@ export default class RoomSublist2 extends React.Component { // TODO: Error boundary: https://github.com/vector-im/riot-web/issues/14185 const visibleTiles = this.renderVisibleTiles(); - const classes = classNames({ 'mx_RoomSublist2': true, 'mx_RoomSublist2_hasMenuOpen': !!this.state.contextMenuPosition, @@ -603,7 +602,6 @@ export default class RoomSublist2 extends React.Component { const maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, this.padding); const showMoreBtnClasses = classNames({ 'mx_RoomSublist2_showNButton': true, - 'mx_RoomSublist2_isCutting': this.state.isResizing && layout.visibleTiles < maxTilesFactored, }); // If we're hiding rooms, show a 'show more' button to the user. This button From 15ea3a528796d6e50271095d8754b7f6fcb25bc2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:42:51 +0200 Subject: [PATCH 11/14] add types --- src/components/views/rooms/RoomSublist2.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index 5a7bfa3990..a059d146e8 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -214,8 +214,13 @@ export default class RoomSublist2 extends React.Component { this.setState({isResizing: true}); }; - private onResizeStop = (e, direction, ref, d) => { - const newHeight = this.heightAtStart + d.height; + private onResizeStop = ( + e: MouseEvent | TouchEvent, + travelDirection: Direction, + refToElement: HTMLDivElement, + delta: ResizeDelta, + ) => { + const newHeight = this.heightAtStart + delta.height; this.applyHeightChange(newHeight); this.setState({isResizing: false, height: newHeight}); }; From ae8d6f5523a3e65548175e6d10410ddce0b67006 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 10 Jul 2020 18:48:54 +0200 Subject: [PATCH 12/14] make tsc happy --- src/components/views/rooms/RoomSublist2.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index a059d146e8..73d53ccae7 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -88,8 +88,8 @@ interface IProps { // TODO: Use re-resizer's NumberSize when it is exposed as the type interface ResizeDelta { - width: number, - height: number, + width: number; + height: number; } type PartialDOMRect = Pick; @@ -98,6 +98,7 @@ interface IState { notificationState: ListNotificationState; contextMenuPosition: PartialDOMRect; isResizing: boolean; + height: number; } export default class RoomSublist2 extends React.Component { @@ -105,6 +106,7 @@ export default class RoomSublist2 extends React.Component { private sublistRef = createRef(); private dispatcherRef: string; private layout: ListLayout; + private heightAtStart: number; constructor(props: IProps) { super(props); @@ -684,7 +686,7 @@ export default class RoomSublist2 extends React.Component { content = ( Date: Fri, 10 Jul 2020 11:01:11 -0600 Subject: [PATCH 13/14] Fix bad merge --- src/components/views/rooms/RoomSublist2.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index b8023cc532..bfbdd3a161 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -120,7 +120,7 @@ export default class RoomSublist2 extends React.Component { notificationState: RoomNotificationStateStore.instance.getListState(this.props.tagId), contextMenuPosition: null, isResizing: false, - isExpanded: this.props.isFiltered ? this.props.isFiltered : !this.layout.isCollapsed + isExpanded: this.props.isFiltered ? this.props.isFiltered : !this.layout.isCollapsed, height, }; this.state.notificationState.setRooms(this.props.rooms); From 9e76a2cebff40ecc7631df69993a560ec4218de6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 10 Jul 2020 11:07:47 -0600 Subject: [PATCH 14/14] Handle off-cycle filtering updates in the new room list --- src/stores/room-list/RoomListStore2.ts | 8 +++++++- src/stores/room-list/algorithms/Algorithm.ts | 11 +++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/stores/room-list/RoomListStore2.ts b/src/stores/room-list/RoomListStore2.ts index 05f678160e..4741e1a30f 100644 --- a/src/stores/room-list/RoomListStore2.ts +++ b/src/stores/room-list/RoomListStore2.ts @@ -25,7 +25,7 @@ import { IListOrderingMap, ITagMap, ITagSortingMap, ListAlgorithm, SortAlgorithm import { ActionPayload } from "../../dispatcher/payloads"; import defaultDispatcher from "../../dispatcher/dispatcher"; import { readReceiptChangeIsFor } from "../../utils/read-receipts"; -import { IFilterCondition } from "./filters/IFilterCondition"; +import { FILTER_CHANGED, IFilterCondition } from "./filters/IFilterCondition"; import { TagWatcher } from "./TagWatcher"; import RoomViewStore from "../RoomViewStore"; import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm"; @@ -65,6 +65,7 @@ export class RoomListStore2 extends AsyncStore { for (const settingName of this.watchedSettings) SettingsStore.monitorSetting(settingName, null); RoomViewStore.addListener(() => this.handleRVSUpdate({})); this.algorithm.on(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated); + this.algorithm.on(FILTER_CHANGED, this.onAlgorithmFilterUpdated); } public get orderedLists(): ITagMap { @@ -479,6 +480,11 @@ export class RoomListStore2 extends AsyncStore { this.updateFn.mark(); }; + private onAlgorithmFilterUpdated = () => { + // The filter can happen off-cycle, so trigger an update if we need to. + this.updateFn.triggerIfWillMark(); + }; + /** * Regenerates the room whole room list, discarding any previous results. * @param trigger Set to false to prevent a list update from being sent. Should only diff --git a/src/stores/room-list/algorithms/Algorithm.ts b/src/stores/room-list/algorithms/Algorithm.ts index d985abd392..17e8283c74 100644 --- a/src/stores/room-list/algorithms/Algorithm.ts +++ b/src/stores/room-list/algorithms/Algorithm.ts @@ -153,11 +153,11 @@ export class Algorithm extends EventEmitter { // Populate the cache of the new filter this.allowedByFilter.set(filterCondition, this.rooms.filter(r => filterCondition.isVisible(r))); this.recalculateFilteredRooms(); - filterCondition.on(FILTER_CHANGED, this.recalculateFilteredRooms.bind(this)); + filterCondition.on(FILTER_CHANGED, this.handleFilterChange.bind(this)); } public removeFilterCondition(filterCondition: IFilterCondition): void { - filterCondition.off(FILTER_CHANGED, this.recalculateFilteredRooms.bind(this)); + filterCondition.off(FILTER_CHANGED, this.handleFilterChange.bind(this)); if (this.allowedByFilter.has(filterCondition)) { this.allowedByFilter.delete(filterCondition); @@ -169,6 +169,13 @@ export class Algorithm extends EventEmitter { } } + private async handleFilterChange() { + await this.recalculateFilteredRooms(); + + // re-emit the update so the list store can fire an off-cycle update if needed + this.emit(FILTER_CHANGED); + } + private async updateStickyRoom(val: Room) { try { return await this.doUpdateStickyRoom(val);