Merge pull request #4865 from matrix-org/travis/room-list/default-vis
Improve resizing interactions in the new room listpull/21833/head
commit
2cd6fae2ce
|
@ -91,6 +91,12 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
return (this.props.rooms || []).length;
|
return (this.props.rooms || []).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get numVisibleTiles(): number {
|
||||||
|
if (!this.props.layout) return 0;
|
||||||
|
const nVisible = Math.floor(this.props.layout.visibleTiles);
|
||||||
|
return Math.min(nVisible, this.numTiles);
|
||||||
|
}
|
||||||
|
|
||||||
public componentDidUpdate() {
|
public componentDidUpdate() {
|
||||||
this.state.notificationState.setRooms(this.props.rooms);
|
this.state.notificationState.setRooms(this.props.rooms);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +113,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
private onResize = (e: React.MouseEvent, data: ResizeCallbackData) => {
|
private onResize = (e: React.MouseEvent, data: ResizeCallbackData) => {
|
||||||
const direction = e.movementY < 0 ? -1 : +1;
|
const direction = e.movementY < 0 ? -1 : +1;
|
||||||
const tileDiff = this.props.layout.pixelsToTiles(Math.abs(e.movementY)) * direction;
|
const tileDiff = this.props.layout.pixelsToTiles(Math.abs(e.movementY)) * direction;
|
||||||
this.props.layout.visibleTiles += tileDiff;
|
this.props.layout.setVisibleTilesWithin(tileDiff, this.numTiles);
|
||||||
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -173,13 +179,17 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderTiles(): React.ReactElement[] {
|
private renderVisibleTiles(): React.ReactElement[] {
|
||||||
if (this.props.layout && this.props.layout.isCollapsed) return []; // don't waste time on rendering
|
if (this.props.layout && this.props.layout.isCollapsed) {
|
||||||
|
// don't waste time on rendering
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const tiles: React.ReactElement[] = [];
|
const tiles: React.ReactElement[] = [];
|
||||||
|
|
||||||
if (this.props.rooms) {
|
if (this.props.rooms) {
|
||||||
for (const room of this.props.rooms) {
|
const visibleRooms = this.props.rooms.slice(0, this.numVisibleTiles);
|
||||||
|
for (const room of visibleRooms) {
|
||||||
tiles.push(
|
tiles.push(
|
||||||
<RoomTile2
|
<RoomTile2
|
||||||
room={room}
|
room={room}
|
||||||
|
@ -343,7 +353,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
public render(): React.ReactElement {
|
public render(): React.ReactElement {
|
||||||
// TODO: Error boundary: https://github.com/vector-im/riot-web/issues/14185
|
// TODO: Error boundary: https://github.com/vector-im/riot-web/issues/14185
|
||||||
|
|
||||||
const tiles = this.renderTiles();
|
const visibleTiles = this.renderVisibleTiles();
|
||||||
|
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
'mx_RoomSublist2': true,
|
'mx_RoomSublist2': true,
|
||||||
|
@ -352,13 +362,10 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let content = null;
|
let content = null;
|
||||||
if (tiles.length > 0) {
|
if (visibleTiles.length > 0) {
|
||||||
const layout = this.props.layout; // to shorten calls
|
const layout = this.props.layout; // to shorten calls
|
||||||
|
|
||||||
const nVisible = Math.floor(layout.visibleTiles);
|
const maxTilesFactored = layout.tilesWithResizerBoxFactor(this.numTiles);
|
||||||
const visibleTiles = tiles.slice(0, nVisible);
|
|
||||||
|
|
||||||
const maxTilesFactored = layout.tilesWithResizerBoxFactor(tiles.length);
|
|
||||||
const showMoreBtnClasses = classNames({
|
const showMoreBtnClasses = classNames({
|
||||||
'mx_RoomSublist2_showNButton': true,
|
'mx_RoomSublist2_showNButton': true,
|
||||||
'mx_RoomSublist2_isCutting': this.state.isResizing && layout.visibleTiles < maxTilesFactored,
|
'mx_RoomSublist2_isCutting': this.state.isResizing && layout.visibleTiles < maxTilesFactored,
|
||||||
|
@ -368,9 +375,9 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
// floats above the resize handle, if we have one present. If the user has all
|
// floats above the resize handle, if we have one present. If the user has all
|
||||||
// tiles visible, it becomes 'show less'.
|
// tiles visible, it becomes 'show less'.
|
||||||
let showNButton = null;
|
let showNButton = null;
|
||||||
if (tiles.length > nVisible) {
|
if (this.numTiles > visibleTiles.length) {
|
||||||
// we have a cutoff condition - add the button to show all
|
// we have a cutoff condition - add the button to show all
|
||||||
const numMissing = tiles.length - visibleTiles.length;
|
const numMissing = this.numTiles - visibleTiles.length;
|
||||||
let showMoreText = (
|
let showMoreText = (
|
||||||
<span className='mx_RoomSublist2_showNButtonText'>
|
<span className='mx_RoomSublist2_showNButtonText'>
|
||||||
{_t("Show %(count)s more", {count: numMissing})}
|
{_t("Show %(count)s more", {count: numMissing})}
|
||||||
|
@ -385,7 +392,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
{showMoreText}
|
{showMoreText}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (tiles.length <= nVisible && tiles.length > this.props.layout.defaultVisibleTiles) {
|
} else if (this.numTiles <= visibleTiles.length && this.numTiles > this.props.layout.defaultVisibleTiles) {
|
||||||
// we have all tiles visible - add a button to show less
|
// we have all tiles visible - add a button to show less
|
||||||
let showLessText = (
|
let showLessText = (
|
||||||
<span className='mx_RoomSublist2_showNButtonText'>
|
<span className='mx_RoomSublist2_showNButtonText'>
|
||||||
|
@ -405,7 +412,7 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
// Figure out if we need a handle
|
// Figure out if we need a handle
|
||||||
let handles = ['s'];
|
let handles = ['s'];
|
||||||
if (layout.visibleTiles >= tiles.length && tiles.length <= layout.minVisibleTiles) {
|
if (layout.visibleTiles >= this.numTiles && this.numTiles <= layout.minVisibleTiles) {
|
||||||
handles = []; // no handles, we're at a minimum
|
handles = []; // no handles, we're at a minimum
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,9 +431,9 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
if (showNButton) padding += SHOW_N_BUTTON_HEIGHT;
|
if (showNButton) padding += SHOW_N_BUTTON_HEIGHT;
|
||||||
padding += RESIZE_HANDLE_HEIGHT; // always append the handle height
|
padding += RESIZE_HANDLE_HEIGHT; // always append the handle height
|
||||||
|
|
||||||
const relativeTiles = layout.tilesWithPadding(tiles.length, padding);
|
const relativeTiles = layout.tilesWithPadding(this.numTiles, padding);
|
||||||
const minTilesPx = layout.calculateTilesToPixelsMin(relativeTiles, layout.minVisibleTiles, padding);
|
const minTilesPx = layout.calculateTilesToPixelsMin(relativeTiles, layout.minVisibleTiles, padding);
|
||||||
const maxTilesPx = layout.tilesToPixelsWithPadding(tiles.length, padding);
|
const maxTilesPx = layout.tilesToPixelsWithPadding(this.numTiles, padding);
|
||||||
const tilesWithoutPadding = Math.min(relativeTiles, layout.visibleTiles);
|
const tilesWithoutPadding = Math.min(relativeTiles, layout.visibleTiles);
|
||||||
const tilesPx = layout.calculateTilesToPixelsMin(relativeTiles, tilesWithoutPadding, padding);
|
const tilesPx = layout.calculateTilesToPixelsMin(relativeTiles, tilesWithoutPadding, padding);
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,9 @@ import { TagID } from "./models";
|
||||||
|
|
||||||
const TILE_HEIGHT_PX = 44;
|
const TILE_HEIGHT_PX = 44;
|
||||||
|
|
||||||
// the .65 comes from the CSS where the show more button is
|
// this comes from the CSS where the show more button is
|
||||||
// mathematically 65% of a tile when floating.
|
// mathematically this percent of a tile when floating.
|
||||||
const RESIZER_BOX_FACTOR = 0.65;
|
const RESIZER_BOX_FACTOR = 0.78;
|
||||||
|
|
||||||
interface ISerializedListLayout {
|
interface ISerializedListLayout {
|
||||||
numTiles: number;
|
numTiles: number;
|
||||||
|
@ -85,10 +85,16 @@ export class ListLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
public get defaultVisibleTiles(): number {
|
public get defaultVisibleTiles(): number {
|
||||||
// TODO: Remove dogfood flag: https://github.com/vector-im/riot-web/issues/14231
|
// 10 is what "feels right", and mostly subject to design's opinion.
|
||||||
// TODO: Resolve dogfooding: https://github.com/vector-im/riot-web/issues/14137
|
return 10 + RESIZER_BOX_FACTOR;
|
||||||
const val = Number(localStorage.getItem("mx_dogfood_rl_defTiles") || 4);
|
}
|
||||||
return val + RESIZER_BOX_FACTOR;
|
|
||||||
|
public setVisibleTilesWithin(diff: number, maxPossible: number) {
|
||||||
|
if (this.visibleTiles > maxPossible) {
|
||||||
|
this.visibleTiles = maxPossible + diff;
|
||||||
|
} else {
|
||||||
|
this.visibleTiles += diff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public calculateTilesToPixelsMin(maxTiles: number, n: number, possiblePadding: number): number {
|
public calculateTilesToPixelsMin(maxTiles: number, n: number, possiblePadding: number): number {
|
||||||
|
@ -122,6 +128,10 @@ export class ListLayout {
|
||||||
return px / this.tileHeight;
|
return px / this.tileHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public reset() {
|
||||||
|
localStorage.removeItem(this.key);
|
||||||
|
}
|
||||||
|
|
||||||
private save() {
|
private save() {
|
||||||
localStorage.setItem(this.key, JSON.stringify(this.serialize()));
|
localStorage.setItem(this.key, JSON.stringify(this.serialize()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import { TagWatcher } from "./TagWatcher";
|
||||||
import RoomViewStore from "../RoomViewStore";
|
import RoomViewStore from "../RoomViewStore";
|
||||||
import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm";
|
import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm";
|
||||||
import { EffectiveMembership, getEffectiveMembership } from "./membership";
|
import { EffectiveMembership, getEffectiveMembership } from "./membership";
|
||||||
|
import { ListLayout } from "./ListLayout";
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
tagsEnabled?: boolean;
|
tagsEnabled?: boolean;
|
||||||
|
@ -396,6 +397,15 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
this.emit(LISTS_UPDATE_EVENT, this);
|
this.emit(LISTS_UPDATE_EVENT, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: this primarily exists for debugging, and isn't really intended to be used by anything.
|
||||||
|
public async resetLayouts() {
|
||||||
|
console.warn("Resetting layouts for room list");
|
||||||
|
for (const tagId of Object.keys(this.orderedLists)) {
|
||||||
|
new ListLayout(tagId).reset();
|
||||||
|
}
|
||||||
|
await this.regenerateAllLists();
|
||||||
|
}
|
||||||
|
|
||||||
public addFilter(filter: IFilterCondition): void {
|
public addFilter(filter: IFilterCondition): void {
|
||||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||||
console.log("Adding filter condition:", filter);
|
console.log("Adding filter condition:", filter);
|
||||||
|
|
Loading…
Reference in New Issue