1
0
mirror of https://github.com/matrix-org/matrix-react-sdk.git synced 2025-11-13 08:02:38 +03:00

Merge branches 'develop' and 't3chguy/room-list/123' of github.com:matrix-org/matrix-react-sdk into t3chguy/room-list/123

 Conflicts:
	src/components/views/rooms/RoomSublist2.tsx
This commit is contained in:
Michael Telatynski
2020-07-07 14:10:58 +01:00
21 changed files with 363 additions and 122 deletions

View File

@@ -32,6 +32,7 @@ import ResizeNotifier from "../../utils/ResizeNotifier";
import SettingsStore from "../../settings/SettingsStore";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../stores/room-list/RoomListStore2";
import {Key} from "../../Keyboard";
import IndicatorScrollbar from "../structures/IndicatorScrollbar";
// 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
@@ -124,6 +125,7 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
const headerStickyWidth = rlRect.width - headerRightMargin;
let gotBottom = false;
let lastTopHeader;
for (const sublist of sublists) {
const slRect = sublist.getBoundingClientRect();
@@ -133,19 +135,25 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
header.classList.add("mx_RoomSublist2_headerContainer_sticky");
header.classList.add("mx_RoomSublist2_headerContainer_stickyBottom");
header.style.width = `${headerStickyWidth}px`;
header.style.top = `unset`;
header.style.removeProperty("top");
gotBottom = true;
} else if (slRect.top < top) {
} else if ((slRect.top - (headerHeight / 3)) < top) {
header.classList.add("mx_RoomSublist2_headerContainer_sticky");
header.classList.add("mx_RoomSublist2_headerContainer_stickyTop");
header.style.width = `${headerStickyWidth}px`;
header.style.top = `${rlRect.top}px`;
if (lastTopHeader) {
lastTopHeader.style.display = "none";
}
// first unset it, if set in last iteration
header.style.removeProperty("display");
lastTopHeader = header;
} else {
header.classList.remove("mx_RoomSublist2_headerContainer_sticky");
header.classList.remove("mx_RoomSublist2_headerContainer_stickyTop");
header.classList.remove("mx_RoomSublist2_headerContainer_stickyBottom");
header.style.width = `unset`;
header.style.top = `unset`;
header.style.removeProperty("width");
header.style.removeProperty("top");
}
}
}
@@ -223,11 +231,14 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
private renderHeader(): React.ReactNode {
let breadcrumbs;
if (this.state.showBreadcrumbs) {
if (this.state.showBreadcrumbs && !this.props.isMinimized) {
breadcrumbs = (
<div className="mx_LeftPanel2_headerRow mx_LeftPanel2_breadcrumbsContainer mx_AutoHideScrollbar">
{this.props.isMinimized ? null : <RoomBreadcrumbs2 />}
</div>
<IndicatorScrollbar
className="mx_LeftPanel2_headerRow mx_LeftPanel2_breadcrumbsContainer mx_AutoHideScrollbar"
verticalScrollsHorizontally={true}
>
<RoomBreadcrumbs2 />
</IndicatorScrollbar>
);
}
@@ -277,6 +288,7 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
onFocus={this.onFocus}
onBlur={this.onBlur}
isMinimized={this.props.isMinimized}
onResize={this.onResize}
/>;
// TODO: Conference handling / calls: https://github.com/vector-im/riot-web/issues/14177

View File

@@ -16,7 +16,7 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
import {_t} from '../../../languageHandler.js';
import {_t} from '../../../languageHandler';
import Field from "./Field";
import AccessibleButton from "./AccessibleButton";

View File

@@ -51,6 +51,7 @@ interface IProps {
onKeyDown: (ev: React.KeyboardEvent) => void;
onFocus: (ev: React.FocusEvent) => void;
onBlur: (ev: React.FocusEvent) => void;
onResize: () => void;
resizeNotifier: ResizeNotifier;
collapsed: boolean;
searchFilter: string;
@@ -63,8 +64,6 @@ interface IState {
}
const TAG_ORDER: TagID[] = [
// -- Community Invites Placeholder --
DefaultTagID.Invite,
DefaultTagID.Favourite,
DefaultTagID.DM,
@@ -76,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,
@@ -183,14 +181,16 @@ export default class RoomList2 extends React.Component<IProps, IState> {
layoutMap.set(tagId, new ListLayout(tagId));
}
this.setState({sublists: newLists, layouts: layoutMap});
this.setState({sublists: newLists, layouts: layoutMap}, () => {
this.props.onResize();
});
};
private renderCommunityInvites(): React.ReactElement[] {
// TODO: Put community invites in a more sensible place (not in the room list)
return MatrixClientPeg.get().getGroups().filter(g => {
if (g.myMembership !== 'invite') return false;
return !this.searchFilter || this.searchFilter.matches(g.name);
return !this.searchFilter || this.searchFilter.matches(g.name || "");
}).map(g => {
const avatar = (
<GroupAvatar
@@ -224,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
}
@@ -242,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}`}
@@ -256,6 +253,7 @@ export default class RoomList2 extends React.Component<IProps, IState> {
isInvite={aesthetics.isInvite}
layout={this.state.layouts.get(orderedTagId)}
isMinimized={this.props.isMinimized}
onResize={this.props.onResize}
extraBadTilesThatShouldntExist={extraTiles}
/>
);

View File

@@ -40,6 +40,7 @@ import NotificationBadge from "./NotificationBadge";
import { ListNotificationState } from "../../../stores/notifications/ListNotificationState";
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
@@ -68,6 +69,7 @@ interface IProps {
layout?: ListLayout;
isMinimized: boolean;
tagId: TagID;
onResize: () => void;
// 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.
@@ -233,6 +235,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
private toggleCollapsed = () => {
this.props.layout.isCollapsed = !this.props.layout.isCollapsed;
this.forceUpdate(); // because the layout doesn't trigger an update
setImmediate(() => this.props.onResize()); // needs to happen when the DOM is updated
};
private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
@@ -283,10 +286,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) {
@@ -302,6 +301,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
@@ -314,15 +317,42 @@ 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>
<StyledMenuItemCheckbox
onClose={this.onCloseMenu}
onChange={this.onUnreadFirstChanged}
checked={isUnreadFirst}
>
{_t("Always show first")}
</StyledMenuItemCheckbox>
</div>
<hr />
<div>
<div className='mx_RoomSublist2_contextMenu_title'>{_t("Show")}</div>
<StyledMenuItemCheckbox
onClose={this.onCloseMenu}
onChange={this.onMessagePreviewChanged}
checked={this.props.layout.showPreviews}
>
{_t("Message preview")}
</StyledMenuItemCheckbox>
</div>
</React.Fragment>
);
}
contextMenu = (
<ContextMenu
chevronFace="none"
@@ -350,28 +380,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
{_t("A-Z")}
</StyledMenuItemRadio>
</div>
<hr />
<div>
<div className='mx_RoomSublist2_contextMenu_title'>{_t("Unread rooms")}</div>
<StyledMenuItemCheckbox
onClose={this.onCloseMenu}
onChange={this.onUnreadFirstChanged}
checked={isUnreadFirst}
>
{_t("Always show first")}
</StyledMenuItemCheckbox>
</div>
<hr />
<div>
<div className='mx_RoomSublist2_contextMenu_title'>{_t("Show")}</div>
<StyledMenuItemCheckbox
onClose={this.onCloseMenu}
onChange={this.onMessagePreviewChanged}
checked={this.props.layout.showPreviews}
>
{_t("Message preview")}
</StyledMenuItemCheckbox>
</div>
{otherSections}
</div>
</ContextMenu>
);

View File

@@ -499,8 +499,8 @@ export default class RoomTile2 extends React.Component<IProps, IState> {
{roomAvatar}
{nameContainer}
{badge}
{this.renderNotificationsMenu(isActive)}
{this.renderGeneralMenu()}
{this.renderNotificationsMenu(isActive)}
</AccessibleButton>
}
</RovingTabIndexWrapper>

View File

@@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {ReactChild} from "react";
import React, {ReactNode} from "react";
import FormButton from "../elements/FormButton";
import {XOR} from "../../../@types/common";
export interface IProps {
description: ReactChild;
description: ReactNode;
acceptLabel: string;
onAccept();