Merge pull request from matrix-org/travis/room-list/invites-list

Fix a number of issues with the new room list's invites
pull/21833/head
Travis Ralston 2020-07-07 06:55:30 -06:00 committed by GitHub
commit b3b404f121
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 45 deletions
src
components/views/rooms
i18n/strings
stores/room-list/algorithms/tag-sorting

View File

@ -64,8 +64,6 @@ interface IState {
}
const TAG_ORDER: TagID[] = [
// -- Community Invites Placeholder --
DefaultTagID.Invite,
DefaultTagID.Favourite,
DefaultTagID.DM,
@ -77,7 +75,6 @@ const TAG_ORDER: TagID[] = [
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,
@ -227,17 +224,15 @@ export default class RoomList2 extends React.Component<IProps, IState> {
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: Community invites: https://github.com/vector-im/riot-web/issues/14179
}
if (CUSTOM_TAGS_BEFORE_TAG === orderedTagId) {
// Populate custom tags if needed
// TODO: Custom tags: https://github.com/vector-im/riot-web/issues/14091
}
const orderedRooms = this.state.sublists[orderedTagId] || [];
if (orderedRooms.length === 0 && !ALWAYS_VISIBLE_TAGS.includes(orderedTagId)) {
const extraTiles = orderedTagId === DefaultTagID.Invite ? this.renderCommunityInvites() : null;
const totalTiles = orderedRooms.length + (extraTiles ? extraTiles.length : 0);
if (totalTiles === 0 && !ALWAYS_VISIBLE_TAGS.includes(orderedTagId)) {
continue; // skip tag - not needed
}
@ -245,7 +240,6 @@ export default class RoomList2 extends React.Component<IProps, IState> {
if (!aesthetics) throw new Error(`Tag ${orderedTagId} does not have aesthetics`);
const onAddRoomFn = aesthetics.onAddRoom ? () => aesthetics.onAddRoom(dis) : null;
const extraTiles = orderedTagId === DefaultTagID.Invite ? this.renderCommunityInvites() : null;
components.push(
<RoomSublist2
key={`sublist-${orderedTagId}`}

View File

@ -27,7 +27,6 @@ import RoomTile2 from "./RoomTile2";
import { ResizableBox, ResizeCallbackData } from "react-resizable";
import { ListLayout } from "../../../stores/room-list/ListLayout";
import { ContextMenu, ContextMenuButton } from "../../structures/ContextMenu";
import StyledCheckbox from "../elements/StyledCheckbox";
import StyledRadioButton from "../elements/StyledRadioButton";
import RoomListStore from "../../../stores/room-list/RoomListStore2";
import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorithms/models";
@ -35,9 +34,9 @@ import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import dis from "../../../dispatcher/dispatcher";
import NotificationBadge from "./NotificationBadge";
import { ListNotificationState } from "../../../stores/notifications/ListNotificationState";
import Tooltip from "../elements/Tooltip";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { Key } from "../../../Keyboard";
import StyledCheckbox from "../elements/StyledCheckbox";
// 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
@ -280,10 +279,6 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
const tiles: React.ReactElement[] = [];
if (this.props.extraBadTilesThatShouldntExist) {
tiles.push(...this.props.extraBadTilesThatShouldntExist);
}
if (this.props.rooms) {
const visibleRooms = this.props.rooms.slice(0, this.numVisibleTiles);
for (const room of visibleRooms) {
@ -299,6 +294,10 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
}
}
if (this.props.extraBadTilesThatShouldntExist) {
tiles.push(...this.props.extraBadTilesThatShouldntExist);
}
// We only have to do this because of the extra tiles. We do it conditionally
// to avoid spending cycles on slicing. It's generally fine to do this though
// as users are unlikely to have more than a handful of tiles when the extra
@ -311,15 +310,40 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
}
private renderMenu(): React.ReactElement {
// TODO: Get a proper invite context menu, or take invites out of the room list.
if (this.props.tagId === DefaultTagID.Invite) {
return null;
}
let contextMenu = null;
if (this.state.contextMenuPosition) {
const isAlphabetical = RoomListStore.instance.getTagSorting(this.props.tagId) === SortAlgorithm.Alphabetic;
const isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance;
// Invites don't get some nonsense options, so only add them if we have to.
let otherSections = null;
if (this.props.tagId !== DefaultTagID.Invite) {
otherSections = (
<React.Fragment>
<hr />
<div>
<div className='mx_RoomSublist2_contextMenu_title'>{_t("Unread rooms")}</div>
<StyledCheckbox
onChange={this.onUnreadFirstChanged}
checked={isUnreadFirst}
>
{_t("Always show first")}
</StyledCheckbox>
</div>
<hr />
<div>
<div className='mx_RoomSublist2_contextMenu_title'>{_t("Show")}</div>
<StyledCheckbox
onChange={this.onMessagePreviewChanged}
checked={this.props.layout.showPreviews}
>
{_t("Message preview")}
</StyledCheckbox>
</div>
</React.Fragment>
);
}
contextMenu = (
<ContextMenu
chevronFace="none"
@ -345,26 +369,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
{_t("A-Z")}
</StyledRadioButton>
</div>
<hr />
<div>
<div className='mx_RoomSublist2_contextMenu_title'>{_t("Unread rooms")}</div>
<StyledCheckbox
onChange={this.onUnreadFirstChanged}
checked={isUnreadFirst}
>
{_t("Always show first")}
</StyledCheckbox>
</div>
<hr />
<div>
<div className='mx_RoomSublist2_contextMenu_title'>{_t("Show")}</div>
<StyledCheckbox
onChange={this.onMessagePreviewChanged}
checked={this.props.layout.showPreviews}
>
{_t("Message preview")}
</StyledCheckbox>
</div>
{otherSections}
</div>
</ContextMenu>
);

View File

@ -1200,13 +1200,13 @@
"Securely back up your keys to avoid losing them. <a>Learn more.</a>": "Securely back up your keys to avoid losing them. <a>Learn more.</a>",
"Not now": "Not now",
"Don't ask me again": "Don't ask me again",
"Sort by": "Sort by",
"Activity": "Activity",
"A-Z": "A-Z",
"Unread rooms": "Unread rooms",
"Always show first": "Always show first",
"Show": "Show",
"Message preview": "Message preview",
"Sort by": "Sort by",
"Activity": "Activity",
"A-Z": "A-Z",
"List options": "List options",
"Add room": "Add room",
"Show %(count)s more|other": "Show %(count)s more",

View File

@ -19,6 +19,7 @@ import { TagID } from "../../models";
import { IAlgorithm } from "./IAlgorithm";
import { MatrixClientPeg } from "../../../../MatrixClientPeg";
import * as Unread from "../../../../Unread";
import { EffectiveMembership, getEffectiveMembership } from "../../membership";
/**
* Sorts rooms according to the last event's timestamp in each room that seems
@ -37,6 +38,8 @@ export class RecentAlgorithm implements IAlgorithm {
// actually changed (probably needs to be done higher up?) then we could do an
// insertion sort or similar on the limited set of changes.
const myUserId = MatrixClientPeg.get().getUserId();
const tsCache: { [roomId: string]: number } = {};
const getLastTs = (r: Room) => {
if (tsCache[r.roomId]) {
@ -50,13 +53,23 @@ export class RecentAlgorithm implements IAlgorithm {
return Number.MAX_SAFE_INTEGER;
}
// If the room hasn't been joined yet, it probably won't have a timeline to
// parse. We'll still fall back to the timeline if this fails, but chances
// are we'll at least have our own membership event to go off of.
const effectiveMembership = getEffectiveMembership(r.getMyMembership());
if (effectiveMembership !== EffectiveMembership.Join) {
const membershipEvent = r.currentState.getStateEvents("m.room.member", myUserId);
if (membershipEvent && !Array.isArray(membershipEvent)) {
return membershipEvent.getTs();
}
}
for (let i = r.timeline.length - 1; i >= 0; --i) {
const ev = r.timeline[i];
if (!ev.getTs()) continue; // skip events that don't have timestamps (tests only?)
// TODO: Don't assume we're using the same client as the peg
if (ev.getSender() === MatrixClientPeg.get().getUserId()
|| Unread.eventTriggersUnreadCount(ev)) {
if (ev.getSender() === myUserId || Unread.eventTriggersUnreadCount(ev)) {
return ev.getTs();
}
}