From 791f39abcc3c72841fc5dc3ac385ea71764f65a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 5 May 2021 08:31:07 +0200 Subject: [PATCH 1/6] Initial support for persistent collapsed states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/spaces/SpaceTreeLevel.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index 6825d84013..6e00eac725 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -48,6 +48,8 @@ import {EventType} from "matrix-js-sdk/src/@types/event"; import {StaticNotificationState} from "../../../stores/notifications/StaticNotificationState"; import {NotificationColor} from "../../../stores/notifications/NotificationColor"; +const getSpaceCollapsedKey = (space: Room) => `mx_space_collapsed_${space.roomId}`; + interface IItemProps { space?: Room; activeSpaces: Room[]; @@ -68,8 +70,12 @@ export class SpaceItem extends React.PureComponent { constructor(props) { super(props); + // XXX: localStorage doesn't allow booleans + // default to collapsed for root items + const collapsed = localStorage.getItem(getSpaceCollapsedKey(props.space)) === "true" || !props.isNested; + this.state = { - collapsed: !props.isNested, // default to collapsed for root items + collapsed: collapsed, contextMenuPosition: null, }; } @@ -78,7 +84,10 @@ export class SpaceItem extends React.PureComponent { if (this.props.onExpand && this.state.collapsed) { this.props.onExpand(); } - this.setState({collapsed: !this.state.collapsed}); + const newCollapsedState = !this.state.collapsed; + // XXX: localStorage doesn't allow booleans + localStorage.setItem(getSpaceCollapsedKey(this.props.space), newCollapsedState.toString()); + this.setState({collapsed: newCollapsedState}); // don't bubble up so encapsulating button for space // doesn't get triggered evt.stopPropagation(); From 2044ff01493d3bf9944d596aae5d6066936e4a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 5 May 2021 11:48:55 +0200 Subject: [PATCH 2/6] Correctly handle defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/spaces/SpaceTreeLevel.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index 6e00eac725..47ed0cd6ca 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -70,9 +70,10 @@ export class SpaceItem extends React.PureComponent { constructor(props) { super(props); + const collapsedLocalStorage = localStorage.getItem(getSpaceCollapsedKey(props.space)); // XXX: localStorage doesn't allow booleans // default to collapsed for root items - const collapsed = localStorage.getItem(getSpaceCollapsedKey(props.space)) === "true" || !props.isNested; + const collapsed = collapsedLocalStorage ? collapsedLocalStorage === "true" : !props.isNested; this.state = { collapsed: collapsed, From 965af1a6422f32b3f6bc8e5fc1e6e53c5deaa890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 11 May 2021 08:08:02 +0200 Subject: [PATCH 3/6] Initial SpaceTreeLevelLayoutStore implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../views/spaces/SpaceTreeLevel.tsx | 15 +++------ src/stores/SpaceTreeLevelLayoutStore.ts | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 src/stores/SpaceTreeLevelLayoutStore.ts diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index 5614271398..df9ea5533b 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -20,6 +20,7 @@ import {Room} from "matrix-js-sdk/src/models/room"; import RoomAvatar from "../avatars/RoomAvatar"; import SpaceStore from "../../../stores/SpaceStore"; +import SpaceTreeLevelLayoutStore from "../../../stores/SpaceTreeLevelLayoutStore"; import NotificationBadge from "../rooms/NotificationBadge"; import {RovingAccessibleButton} from "../../../accessibility/roving/RovingAccessibleButton"; import {RovingAccessibleTooltipButton} from "../../../accessibility/roving/RovingAccessibleTooltipButton"; @@ -48,8 +49,6 @@ import {EventType} from "matrix-js-sdk/src/@types/event"; import {StaticNotificationState} from "../../../stores/notifications/StaticNotificationState"; import {NotificationColor} from "../../../stores/notifications/NotificationColor"; -const getSpaceCollapsedKey = (space: Room) => `mx_space_collapsed_${space.roomId}`; - interface IItemProps { space?: Room; activeSpaces: Room[]; @@ -70,13 +69,9 @@ export class SpaceItem extends React.PureComponent { constructor(props) { super(props); - const collapsedLocalStorage = localStorage.getItem(getSpaceCollapsedKey(props.space)); - // XXX: localStorage doesn't allow booleans - // default to collapsed for root items - const collapsed = collapsedLocalStorage ? collapsedLocalStorage === "true" : !props.isNested; - this.state = { - collapsed: collapsed, + // default to collapsed for root items + collapsed: SpaceTreeLevelLayoutStore.getSpaceCollapsedState(props.space, !props.isNested), contextMenuPosition: null, }; } @@ -86,8 +81,8 @@ export class SpaceItem extends React.PureComponent { this.props.onExpand(); } const newCollapsedState = !this.state.collapsed; - // XXX: localStorage doesn't allow booleans - localStorage.setItem(getSpaceCollapsedKey(this.props.space), newCollapsedState.toString()); + + SpaceTreeLevelLayoutStore.setSpaceCollapsedState(this.props.space, newCollapsedState); this.setState({collapsed: newCollapsedState}); // don't bubble up so encapsulating button for space // doesn't get triggered diff --git a/src/stores/SpaceTreeLevelLayoutStore.ts b/src/stores/SpaceTreeLevelLayoutStore.ts new file mode 100644 index 0000000000..2ba8a73fcb --- /dev/null +++ b/src/stores/SpaceTreeLevelLayoutStore.ts @@ -0,0 +1,32 @@ +/* +Copyright 2021 Šimon Brandner + +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 {Room} from "matrix-js-sdk/src/models/room"; + +const getSpaceCollapsedKey = (space: Room) => `mx_space_collapsed_${space.roomId}`; + +export default class SpaceTreeLevelLayoutStore { + public static setSpaceCollapsedState(space: Room, collapsed: boolean) { + // XXX: localStorage doesn't allow booleans + localStorage.setItem(getSpaceCollapsedKey(space), collapsed.toString()); + } + + public static getSpaceCollapsedState(space: Room, fallback: boolean): boolean { + const collapsedLocalStorage = localStorage.getItem(getSpaceCollapsedKey(space)); + // XXX: localStorage doesn't allow booleans + return collapsedLocalStorage ? collapsedLocalStorage === "true" : fallback; + } +} From 4115fd869512d4a9f585b9e78f207889449549da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 11 May 2021 11:13:13 +0200 Subject: [PATCH 4/6] Rewrite SpaceTreeLevelLayoutStore to save paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- .../views/spaces/SpaceTreeLevel.tsx | 14 +++++++++++-- src/stores/SpaceTreeLevelLayoutStore.ts | 21 ++++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index df9ea5533b..52508e6320 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -69,9 +69,15 @@ export class SpaceItem extends React.PureComponent { constructor(props) { super(props); + const collapsed = SpaceTreeLevelLayoutStore.getSpaceCollapsedState( + props.space.roomId, + this.props.parents, + !props.isNested, + ); + this.state = { // default to collapsed for root items - collapsed: SpaceTreeLevelLayoutStore.getSpaceCollapsedState(props.space, !props.isNested), + collapsed: collapsed, contextMenuPosition: null, }; } @@ -82,7 +88,11 @@ export class SpaceItem extends React.PureComponent { } const newCollapsedState = !this.state.collapsed; - SpaceTreeLevelLayoutStore.setSpaceCollapsedState(this.props.space, newCollapsedState); + SpaceTreeLevelLayoutStore.setSpaceCollapsedState( + this.props.space.roomId, + this.props.parents, + newCollapsedState, + ); this.setState({collapsed: newCollapsedState}); // don't bubble up so encapsulating button for space // doesn't get triggered diff --git a/src/stores/SpaceTreeLevelLayoutStore.ts b/src/stores/SpaceTreeLevelLayoutStore.ts index 2ba8a73fcb..1250fee0b7 100644 --- a/src/stores/SpaceTreeLevelLayoutStore.ts +++ b/src/stores/SpaceTreeLevelLayoutStore.ts @@ -14,18 +14,25 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {Room} from "matrix-js-sdk/src/models/room"; - -const getSpaceCollapsedKey = (space: Room) => `mx_space_collapsed_${space.roomId}`; +const getSpaceCollapsedKey = (roomId: string, parents: Set): string => { + const separator = "/"; + let path = ""; + if (parents) { + for (const entry of parents.entries()) { + path += entry + separator; + } + } + return `mx_space_collapsed_${path + roomId}`; +}; export default class SpaceTreeLevelLayoutStore { - public static setSpaceCollapsedState(space: Room, collapsed: boolean) { + public static setSpaceCollapsedState(roomId: string, parents: Set, collapsed: boolean) { // XXX: localStorage doesn't allow booleans - localStorage.setItem(getSpaceCollapsedKey(space), collapsed.toString()); + localStorage.setItem(getSpaceCollapsedKey(roomId, parents), collapsed.toString()); } - public static getSpaceCollapsedState(space: Room, fallback: boolean): boolean { - const collapsedLocalStorage = localStorage.getItem(getSpaceCollapsedKey(space)); + public static getSpaceCollapsedState(roomId: string, parents: Set, fallback: boolean): boolean { + const collapsedLocalStorage = localStorage.getItem(getSpaceCollapsedKey(roomId, parents)); // XXX: localStorage doesn't allow booleans return collapsedLocalStorage ? collapsedLocalStorage === "true" : fallback; } From 1b877f2b7c08322e9cfda1de7d29456ec6764fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Tue, 11 May 2021 11:16:14 +0200 Subject: [PATCH 5/6] Make SpaceTreeLevelLayoutStore into a singleton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/spaces/SpaceTreeLevel.tsx | 4 ++-- src/stores/SpaceTreeLevelLayoutStore.ts | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index 52508e6320..f799cb02ba 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -69,7 +69,7 @@ export class SpaceItem extends React.PureComponent { constructor(props) { super(props); - const collapsed = SpaceTreeLevelLayoutStore.getSpaceCollapsedState( + const collapsed = SpaceTreeLevelLayoutStore.instance.getSpaceCollapsedState( props.space.roomId, this.props.parents, !props.isNested, @@ -88,7 +88,7 @@ export class SpaceItem extends React.PureComponent { } const newCollapsedState = !this.state.collapsed; - SpaceTreeLevelLayoutStore.setSpaceCollapsedState( + SpaceTreeLevelLayoutStore.instance.setSpaceCollapsedState( this.props.space.roomId, this.props.parents, newCollapsedState, diff --git a/src/stores/SpaceTreeLevelLayoutStore.ts b/src/stores/SpaceTreeLevelLayoutStore.ts index 1250fee0b7..424e9f4012 100644 --- a/src/stores/SpaceTreeLevelLayoutStore.ts +++ b/src/stores/SpaceTreeLevelLayoutStore.ts @@ -26,12 +26,21 @@ const getSpaceCollapsedKey = (roomId: string, parents: Set): string => { }; export default class SpaceTreeLevelLayoutStore { - public static setSpaceCollapsedState(roomId: string, parents: Set, collapsed: boolean) { + private static internalInstance: SpaceTreeLevelLayoutStore; + + public static get instance(): SpaceTreeLevelLayoutStore { + if (!SpaceTreeLevelLayoutStore.internalInstance) { + SpaceTreeLevelLayoutStore.internalInstance = new SpaceTreeLevelLayoutStore(); + } + return SpaceTreeLevelLayoutStore.internalInstance; + } + + public setSpaceCollapsedState(roomId: string, parents: Set, collapsed: boolean) { // XXX: localStorage doesn't allow booleans localStorage.setItem(getSpaceCollapsedKey(roomId, parents), collapsed.toString()); } - public static getSpaceCollapsedState(roomId: string, parents: Set, fallback: boolean): boolean { + public getSpaceCollapsedState(roomId: string, parents: Set, fallback: boolean): boolean { const collapsedLocalStorage = localStorage.getItem(getSpaceCollapsedKey(roomId, parents)); // XXX: localStorage doesn't allow booleans return collapsedLocalStorage ? collapsedLocalStorage === "true" : fallback; From 262fc40afb2867004a60dd4043794fb5f0cdac24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Wed, 12 May 2021 07:12:00 +0200 Subject: [PATCH 6/6] Move comment to the correct place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/components/views/spaces/SpaceTreeLevel.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index f799cb02ba..f0a0605584 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -72,11 +72,10 @@ export class SpaceItem extends React.PureComponent { const collapsed = SpaceTreeLevelLayoutStore.instance.getSpaceCollapsedState( props.space.roomId, this.props.parents, - !props.isNested, + !props.isNested, // default to collapsed for root items ); this.state = { - // default to collapsed for root items collapsed: collapsed, contextMenuPosition: null, };