From 8773d67df7c19732ef9acaffdff60b30dc7ef19e Mon Sep 17 00:00:00 2001 From: Jorik Schellekens Date: Wed, 8 Jul 2020 17:28:15 +0100 Subject: [PATCH 1/6] Auto expand room list on search --- src/components/structures/RoomSearch.tsx | 9 ++++++++- src/components/views/rooms/RoomList2.tsx | 11 +++++++++++ src/dispatcher/actions.ts | 10 ++++++++++ src/stores/room-list/ListLayout.ts | 12 ++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index 15f3bd5b54..349025782d 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -76,6 +76,7 @@ export default class RoomSearch extends React.PureComponent { private clearInput = () => { if (!this.inputRef.current) return; this.inputRef.current.value = ""; + defaultDispatcher.dispatch({action: Action.StopRoomFilter}) this.onChange(); }; @@ -102,9 +103,15 @@ export default class RoomSearch extends React.PureComponent { private onFocus = (ev: React.FocusEvent) => { this.setState({focused: true}); ev.target.select(); + if (ev.target.value === "") { + defaultDispatcher.dispatch({action: Action.StartRoomFilter}) + } }; - private onBlur = () => { + private onBlur = (ev: React.FocusEvent) => { + if (ev.target.value === "") { + defaultDispatcher.dispatch({action: Action.StopRoomFilter}) + } this.setState({focused: false}); }; diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index fb0136fb29..c294b2e1b0 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -194,6 +194,17 @@ export default class RoomList2 extends React.Component { show_room_tile: true, // to make sure the room gets scrolled into view }); } + } else if (payload.action === Action.StartRoomFilter) { + this.state.layouts.forEach(x => { + x.saveCollapsedState(); + x.isCollapsed = false; + }); + this.forceUpdate(); + } else if (payload.action === Action.StopRoomFilter) { + this.state.layouts.forEach(x => { + x.restoreCollapsedState(); + }); + this.forceUpdate(); } }; diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 9be674b59e..89b2216db1 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -84,4 +84,14 @@ export enum Action { * Changes room based on room list order and payload parameters. Should be used with ViewRoomDeltaPayload. */ ViewRoomDelta = "view_room_delta", + + /** + * Informs the room list when room filtering has begun. No additional payload information required. + */ + StartRoomFilter = "start_room_filter", + + /** + * Informs the room list when room filtering has ended. No additional payload information required. + */ + StopRoomFilter = "stop_room_filter", } diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts index f31e92b8ae..7be284b0e5 100644 --- a/src/stores/room-list/ListLayout.ts +++ b/src/stores/room-list/ListLayout.ts @@ -26,12 +26,14 @@ interface ISerializedListLayout { numTiles: number; showPreviews: boolean; collapsed: boolean; + savedCollapsed: boolean; } export class ListLayout { private _n = 0; private _previews = false; private _collapsed = false; + private _savedCollapsed = false; constructor(public readonly tagId: TagID) { const serialized = localStorage.getItem(this.key); @@ -41,6 +43,7 @@ export class ListLayout { this._n = parsed.numTiles; this._previews = parsed.showPreviews; this._collapsed = parsed.collapsed; + this._savedCollapsed = parsed.savedCollapsed; } } @@ -136,11 +139,20 @@ export class ListLayout { localStorage.setItem(this.key, JSON.stringify(this.serialize())); } + public saveCollapsedState() { + this._savedCollapsed = this.isCollapsed; + } + + public restoreCollapsedState() { + this.isCollapsed = this._savedCollapsed; + } + private serialize(): ISerializedListLayout { return { numTiles: this.visibleTiles, showPreviews: this.showPreviews, collapsed: this.isCollapsed, + savedCollapsed: this._savedCollapsed, }; } } From bb18e677f9020348a1a4d4188f1a16bc90523177 Mon Sep 17 00:00:00 2001 From: Jorik Schellekens Date: Wed, 8 Jul 2020 18:05:07 +0100 Subject: [PATCH 2/6] Lint semis --- src/components/structures/RoomSearch.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index 349025782d..dad05fb577 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -76,7 +76,7 @@ export default class RoomSearch extends React.PureComponent { private clearInput = () => { if (!this.inputRef.current) return; this.inputRef.current.value = ""; - defaultDispatcher.dispatch({action: Action.StopRoomFilter}) + defaultDispatcher.dispatch({action: Action.StopRoomFilter}); this.onChange(); }; @@ -104,13 +104,13 @@ export default class RoomSearch extends React.PureComponent { this.setState({focused: true}); ev.target.select(); if (ev.target.value === "") { - defaultDispatcher.dispatch({action: Action.StartRoomFilter}) + defaultDispatcher.dispatch({action: Action.StartRoomFilter}); } }; private onBlur = (ev: React.FocusEvent) => { if (ev.target.value === "") { - defaultDispatcher.dispatch({action: Action.StopRoomFilter}) + defaultDispatcher.dispatch({action: Action.StopRoomFilter}); } this.setState({focused: false}); }; From ade89ab4e90cf8882a68445f110e3e83f715a5e7 Mon Sep 17 00:00:00 2001 From: Jorik Schellekens Date: Thu, 9 Jul 2020 18:32:28 +0100 Subject: [PATCH 3/6] Move sublist auto expand to out from layouts Co-authored-by: Travis Ralston --- src/components/views/rooms/RoomList2.tsx | 14 ++-------- src/components/views/rooms/RoomSublist2.tsx | 31 +++++++++++++-------- src/stores/room-list/ListLayout.ts | 12 -------- 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index 5cb60655ce..79f6ed0d10 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -191,18 +191,7 @@ export default class RoomList2 extends React.Component { show_room_tile: true, // to make sure the room gets scrolled into view }); } - } else if (payload.action === Action.StartRoomFilter) { - this.state.layouts.forEach(x => { - x.saveCollapsedState(); - x.isCollapsed = false; - }); - this.forceUpdate(); - } else if (payload.action === Action.StopRoomFilter) { - this.state.layouts.forEach(x => { - x.restoreCollapsedState(); - }); - this.forceUpdate(); - } + } }; private getRoomDelta = (roomId: string, delta: number, unread = false) => { @@ -304,6 +293,7 @@ export default class RoomList2 extends React.Component { isMinimized={this.props.isMinimized} onResize={this.props.onResize} extraBadTilesThatShouldntExist={extraTiles} + isFiltered={!!this.searchFilter.search} /> ); } diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index c3ac85e2de..e7deca2543 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -47,6 +47,7 @@ import { Direction } from "re-resizable/lib/resizer"; import { polyfillTouchEvent } from "../../../@types/polyfill"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore"; +import { Action } from "../../../dispatcher/actions"; // 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 @@ -78,6 +79,7 @@ interface IProps { isMinimized: boolean; tagId: TagID; onResize: () => void; + isFiltered: boolean; // TODO: Don't use this. It's for community invites, and community invites shouldn't be here. // You should feel bad if you use this. @@ -92,6 +94,7 @@ interface IState { notificationState: ListNotificationState; contextMenuPosition: PartialDOMRect; isResizing: boolean; + isExpanded: boolean; // used for the for expand of the sublist when the room list is being filtered } export default class RoomSublist2 extends React.Component { @@ -109,6 +112,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 }; this.state.notificationState.setRooms(this.props.rooms); this.dispatcherRef = defaultDispatcher.register(this.onAction); @@ -123,8 +127,15 @@ export default class RoomSublist2 extends React.Component { return Math.min(nVisible, this.numTiles); } - public componentDidUpdate() { + public componentDidUpdate(prevProps: Readonly) { this.state.notificationState.setRooms(this.props.rooms); + if (prevProps.isFiltered !== this.props.isFiltered) { + if (this.props.isFiltered) { + this.setState({isExpanded: true}); + } else { + this.setState({isExpanded: !this.layout.isCollapsed}); + } + } } public componentWillUnmount() { @@ -137,10 +148,9 @@ export default class RoomSublist2 extends React.Component { // 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. setImmediate(() => { - const isCollapsed = this.layout.isCollapsed; const roomIndex = this.props.rooms.findIndex((r) => r.roomId === payload.room_id); - if (isCollapsed && roomIndex > -1) { + if (!this.state.isExpanded && roomIndex > -1) { this.toggleCollapsed(); } // extend the visible section to include the room if it is entirely invisible @@ -295,24 +305,23 @@ export default class RoomSublist2 extends React.Component { }; private toggleCollapsed = () => { - this.layout.isCollapsed = !this.layout.isCollapsed; - this.forceUpdate(); // because the layout doesn't trigger an update + this.layout.isCollapsed = this.state.isExpanded; + this.setState({isExpanded: !this.layout.isCollapsed}); setImmediate(() => this.props.onResize()); // needs to happen when the DOM is updated }; private onHeaderKeyDown = (ev: React.KeyboardEvent) => { - const isCollapsed = this.layout && this.layout.isCollapsed; switch (ev.key) { case Key.ARROW_LEFT: ev.stopPropagation(); - if (!isCollapsed) { + if (this.state.isExpanded) { // On ARROW_LEFT collapse the room sublist if it isn't already this.toggleCollapsed(); } break; case Key.ARROW_RIGHT: { ev.stopPropagation(); - if (isCollapsed) { + if (!this.state.isExpanded) { // On ARROW_RIGHT expand the room sublist if it isn't already this.toggleCollapsed(); } else if (this.sublistRef.current) { @@ -341,7 +350,7 @@ export default class RoomSublist2 extends React.Component { }; private renderVisibleTiles(): React.ReactElement[] { - if (this.layout && this.layout.isCollapsed) { + if (!this.state.isExpanded) { // don't waste time on rendering return []; } @@ -498,7 +507,7 @@ export default class RoomSublist2 extends React.Component { const collapseClasses = classNames({ 'mx_RoomSublist2_collapseBtn': true, - 'mx_RoomSublist2_collapseBtn_collapsed': this.layout && this.layout.isCollapsed, + 'mx_RoomSublist2_collapseBtn_collapsed': !this.state.isExpanded, }); const classes = classNames({ @@ -526,7 +535,7 @@ export default class RoomSublist2 extends React.Component { tabIndex={tabIndex} className="mx_RoomSublist2_headerText" role="treeitem" - aria-expanded={!this.layout.isCollapsed} + aria-expanded={this.state.isExpanded} aria-level={1} onClick={this.onHeaderClick} onContextMenu={this.onContextMenu} diff --git a/src/stores/room-list/ListLayout.ts b/src/stores/room-list/ListLayout.ts index f87181ccd1..5169c5e4e5 100644 --- a/src/stores/room-list/ListLayout.ts +++ b/src/stores/room-list/ListLayout.ts @@ -26,14 +26,12 @@ interface ISerializedListLayout { numTiles: number; showPreviews: boolean; collapsed: boolean; - savedCollapsed: boolean; } export class ListLayout { private _n = 0; private _previews = false; private _collapsed = false; - private _savedCollapsed = false; constructor(public readonly tagId: TagID) { const serialized = localStorage.getItem(this.key); @@ -43,7 +41,6 @@ export class ListLayout { this._n = parsed.numTiles; this._previews = parsed.showPreviews; this._collapsed = parsed.collapsed; - this._savedCollapsed = parsed.savedCollapsed; } } @@ -136,20 +133,11 @@ export class ListLayout { localStorage.setItem(this.key, JSON.stringify(this.serialize())); } - public saveCollapsedState() { - this._savedCollapsed = this.isCollapsed; - } - - public restoreCollapsedState() { - this.isCollapsed = this._savedCollapsed; - } - private serialize(): ISerializedListLayout { return { numTiles: this.visibleTiles, showPreviews: this.showPreviews, collapsed: this.isCollapsed, - savedCollapsed: this._savedCollapsed, }; } } From 8a7bebc6bf446e58f47e4c163d62dcdcce47bd6f Mon Sep 17 00:00:00 2001 From: Jorik Schellekens Date: Thu, 9 Jul 2020 18:37:18 +0100 Subject: [PATCH 4/6] lint --- src/components/views/rooms/RoomList2.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index 79f6ed0d10..ba0464a0a4 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -191,7 +191,7 @@ export default class RoomList2 extends React.Component { show_room_tile: true, // to make sure the room gets scrolled into view }); } - } + } }; private getRoomDelta = (roomId: string, delta: number, unread = false) => { From 1983591cbf4e4b63c145570bd1be09525958314d Mon Sep 17 00:00:00 2001 From: Jorik Schellekens Date: Fri, 10 Jul 2020 02:22:34 +0100 Subject: [PATCH 5/6] Remove unused actions --- src/components/views/rooms/RoomSublist2.tsx | 1 - src/dispatcher/actions.ts | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx index e7deca2543..67a84e9292 100644 --- a/src/components/views/rooms/RoomSublist2.tsx +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -47,7 +47,6 @@ import { Direction } from "re-resizable/lib/resizer"; import { polyfillTouchEvent } from "../../../@types/polyfill"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore"; -import { Action } from "../../../dispatcher/actions"; // 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 diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 89b2216db1..9be674b59e 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -84,14 +84,4 @@ export enum Action { * Changes room based on room list order and payload parameters. Should be used with ViewRoomDeltaPayload. */ ViewRoomDelta = "view_room_delta", - - /** - * Informs the room list when room filtering has begun. No additional payload information required. - */ - StartRoomFilter = "start_room_filter", - - /** - * Informs the room list when room filtering has ended. No additional payload information required. - */ - StopRoomFilter = "stop_room_filter", } From ceff68476dcf92e49b18a730b7e2c3ecd7e9ddc1 Mon Sep 17 00:00:00 2001 From: Jorik Schellekens Date: Fri, 10 Jul 2020 02:25:15 +0100 Subject: [PATCH 6/6] Remove useless dispatches --- src/components/structures/RoomSearch.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx index 7c5799dcbb..8655db2e8c 100644 --- a/src/components/structures/RoomSearch.tsx +++ b/src/components/structures/RoomSearch.tsx @@ -76,7 +76,6 @@ export default class RoomSearch extends React.PureComponent { private clearInput = () => { if (!this.inputRef.current) return; this.inputRef.current.value = ""; - defaultDispatcher.dispatch({action: Action.StopRoomFilter}); this.onChange(); }; @@ -104,15 +103,9 @@ export default class RoomSearch extends React.PureComponent { private onFocus = (ev: React.FocusEvent) => { this.setState({focused: true}); ev.target.select(); - if (ev.target.value === "") { - defaultDispatcher.dispatch({action: Action.StartRoomFilter}); - } }; private onBlur = (ev: React.FocusEvent) => { - if (ev.target.value === "") { - defaultDispatcher.dispatch({action: Action.StopRoomFilter}); - } this.setState({focused: false}); };