From 09b7f39df8118a0c6979b7fc4091c4d583ee2782 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 30 Apr 2020 13:21:50 -0600 Subject: [PATCH] Simple rendering of the room list for visual aid This is largely meant to prove the algorithm works and nothing more. --- src/components/views/rooms/RoomList2.tsx | 130 +++++++++++++++++++- src/components/views/rooms/RoomSublist2.tsx | 61 +++++++++ 2 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 src/components/views/rooms/RoomSublist2.tsx diff --git a/src/components/views/rooms/RoomList2.tsx b/src/components/views/rooms/RoomList2.tsx index f97f599ae3..04cb8a4549 100644 --- a/src/components/views/rooms/RoomList2.tsx +++ b/src/components/views/rooms/RoomList2.tsx @@ -17,11 +17,18 @@ limitations under the License. */ import * as React from "react"; -import { _t } from "../../../languageHandler"; +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 { ITagMap } from "../../../stores/room-list/algorithms/models"; +import { DefaultTagID, TagID } from "../../../stores/room-list/models"; +import { Dispatcher } from "flux"; +import { ActionPayload } from "../../../dispatcher-types"; +import dis from "../../../dispatcher"; +import { RoomSublist2 } from "./RoomSublist2"; +import { isNullOrUndefined } from "matrix-js-sdk/lib/src/utils"; interface IProps { onKeyDown: (ev: React.KeyboardEvent) => void; @@ -33,14 +40,83 @@ interface IProps { } interface IState { + sublists: ITagMap; } -// TODO: Actually write stub -export class RoomSublist2 extends React.Component { - public setHeight(size: number) { - } +const TAG_ORDER: TagID[] = [ + // -- Community Invites Placeholder -- + + DefaultTagID.Invite, + DefaultTagID.Favourite, + DefaultTagID.DM, + DefaultTagID.Untagged, + + // -- Custom Tags Placeholder -- + + DefaultTagID.LowPriority, + DefaultTagID.ServerNotice, + DefaultTagID.Archived, +]; +const COMMUNITY_TAGS_BEFORE_TAG = DefaultTagID.Invite; +const CUSTOM_TAGS_BEFORE_TAG = DefaultTagID.LowPriority; +const ALWAYS_VISIBLE_TAGS: TagID[] = [ + DefaultTagID.DM, + DefaultTagID.Untagged, +]; + +interface ITagAesthetics { + sectionLabel: string; + addRoomLabel?: string; + onAddRoom?: (dispatcher: Dispatcher) => void; + isInvite: boolean; + defaultHidden: boolean; } +const TAG_AESTHETICS: { + // @ts-ignore - TS wants this to be a string but we know better + [tagId: TagID]: ITagAesthetics; +} = { + [DefaultTagID.Invite]: { + sectionLabel: _td("Invites"), + isInvite: true, + defaultHidden: false, + }, + [DefaultTagID.Favourite]: { + sectionLabel: _td("Favourites"), + isInvite: false, + defaultHidden: false, + }, + [DefaultTagID.DM]: { + sectionLabel: _td("Direct Messages"), + isInvite: false, + defaultHidden: false, + addRoomLabel: _td("Start chat"), + onAddRoom: (dispatcher: Dispatcher) => dispatcher.dispatch({action: 'view_create_chat'}), + }, + [DefaultTagID.Untagged]: { + sectionLabel: _td("Rooms"), + isInvite: false, + defaultHidden: false, + addRoomLabel: _td("Create room"), + onAddRoom: (dispatcher: Dispatcher) => dispatcher.dispatch({action: 'view_create_room'}), + }, + [DefaultTagID.LowPriority]: { + sectionLabel: _td("Low priority"), + isInvite: false, + defaultHidden: false, + }, + [DefaultTagID.ServerNotice]: { + sectionLabel: _td("System Alerts"), + isInvite: false, + defaultHidden: false, + }, + [DefaultTagID.Archived]: { + sectionLabel: _td("Historical"), + isInvite: false, + defaultHidden: true, + }, +}; + export default class RoomList2 extends React.Component { private sublistRefs: { [tagId: string]: React.RefObject } = {}; private sublistSizes: { [tagId: string]: number } = {}; @@ -51,6 +127,7 @@ export default class RoomList2 extends React.Component { constructor(props: IProps) { super(props); + this.state = {sublists: {}}; this.loadSublistSizes(); this.prepareLayouts(); } @@ -58,6 +135,7 @@ 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}); }); } @@ -108,7 +186,47 @@ export default class RoomList2 extends React.Component { } } + private renderSublists(): React.ReactElement[] { + const components: React.ReactElement[] = []; + + for (const orderedTagId of TAG_ORDER) { + if (COMMUNITY_TAGS_BEFORE_TAG === orderedTagId) { + // Populate community invites if we have the chance + // TODO + } + if (CUSTOM_TAGS_BEFORE_TAG === orderedTagId) { + // Populate custom tags if needed + // TODO + } + + const orderedRooms = this.state.sublists[orderedTagId] || []; + if (orderedRooms.length === 0 && !ALWAYS_VISIBLE_TAGS.includes(orderedTagId)) { + continue; // skip tag - not needed + } + + const aesthetics: ITagAesthetics = TAG_AESTHETICS[orderedTagId]; + if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`); + + const onAddRoomFn = () => { + if (!aesthetics.onAddRoom) return; + aesthetics.onAddRoom(dis); + }; + components.push(); + } + + return components; + } + public render() { + const sublists = this.renderSublists(); return ( {({onKeyDownHandler}) => ( @@ -122,7 +240,7 @@ export default class RoomList2 extends React.Component { // Firefox sometimes makes this element focusable due to // overflow:scroll;, so force it out of tab order. tabIndex={-1} - >{_t("TODO")} + >{sublists} )} ); diff --git a/src/components/views/rooms/RoomSublist2.tsx b/src/components/views/rooms/RoomSublist2.tsx new file mode 100644 index 0000000000..a3ca525b14 --- /dev/null +++ b/src/components/views/rooms/RoomSublist2.tsx @@ -0,0 +1,61 @@ +/* +Copyright 2015, 2016 OpenMarket Ltd +Copyright 2017, 2018 Vector Creations Ltd +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 * as React from "react"; +import { Room } from "matrix-js-sdk/src/models/room"; + +interface IProps { + forRooms: boolean; + rooms?: Room[]; + startAsHidden: boolean; + label: string; + onAddRoom?: () => void; + addRoomLabel: string; + isInvite: boolean; + + // TODO: Collapsed state + // TODO: Height + // TODO: Group invites + // TODO: Calls + // TODO: forceExpand? + // TODO: Header clicking + // TODO: Spinner support for historical +} + +interface IState { +} + +// TODO: Actually write stub +export class RoomSublist2 extends React.Component { + public setHeight(size: number) { + } + + public render() { + // TODO: Proper rendering + + const rooms = this.props.rooms.map(r => ( +
{r.name} ({r.roomId})
+ )); + return ( +
+

{this.props.label}

+ {rooms} +
+ ); + } +}