mirror of
https://github.com/element-hq/element-web
synced 2024-11-27 19:56:47 +03:00
Merge pull request #2515 from matrix-org/bwindels/roomlistjslayout-bisbis
Redesign: switch layout when filtering room sublists
This commit is contained in:
commit
012e358147
3 changed files with 80 additions and 27 deletions
|
@ -84,7 +84,7 @@ const RoomSubList = React.createClass({
|
||||||
// The dataset elements are added in the RoomList _initAndPositionStickyHeaders method
|
// The dataset elements are added in the RoomList _initAndPositionStickyHeaders method
|
||||||
isCollapsableOnClick: function() {
|
isCollapsableOnClick: function() {
|
||||||
const stuck = this.refs.header.dataset.stuck;
|
const stuck = this.refs.header.dataset.stuck;
|
||||||
if (this.state.hidden || stuck === undefined || stuck === "none") {
|
if (!this.props.forceExpand && (this.state.hidden || stuck === undefined || stuck === "none")) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -238,7 +238,7 @@ const RoomSubList = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_getHeaderJsx: function() {
|
_getHeaderJsx: function(isCollapsed) {
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
const subListNotifications = this.roomNotificationCount();
|
const subListNotifications = this.roomNotificationCount();
|
||||||
const subListNotifCount = subListNotifications[0];
|
const subListNotifCount = subListNotifications[0];
|
||||||
|
@ -287,8 +287,8 @@ const RoomSubList = React.createClass({
|
||||||
if (len) {
|
if (len) {
|
||||||
const chevronClasses = classNames({
|
const chevronClasses = classNames({
|
||||||
'mx_RoomSubList_chevron': true,
|
'mx_RoomSubList_chevron': true,
|
||||||
'mx_RoomSubList_chevronRight': this.state.hidden,
|
'mx_RoomSubList_chevronRight': isCollapsed,
|
||||||
'mx_RoomSubList_chevronDown': !this.state.hidden,
|
'mx_RoomSubList_chevronDown': !isCollapsed,
|
||||||
});
|
});
|
||||||
chevron = (<div className={chevronClasses}></div>);
|
chevron = (<div className={chevronClasses}></div>);
|
||||||
}
|
}
|
||||||
|
@ -321,21 +321,23 @@ const RoomSubList = React.createClass({
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
const len = this.props.list.length + this.props.extraTiles.length;
|
const len = this.props.list.length + this.props.extraTiles.length;
|
||||||
|
const isCollapsed = this.state.hidden && !this.props.forceExpand;
|
||||||
if (len) {
|
if (len) {
|
||||||
const subListClasses = classNames({
|
const subListClasses = classNames({
|
||||||
"mx_RoomSubList": true,
|
"mx_RoomSubList": true,
|
||||||
"mx_RoomSubList_hidden": this.state.hidden,
|
"mx_RoomSubList_hidden": isCollapsed,
|
||||||
"mx_RoomSubList_nonEmpty": len && !this.state.hidden,
|
"mx_RoomSubList_nonEmpty": len && !isCollapsed,
|
||||||
});
|
});
|
||||||
if (this.state.hidden) {
|
|
||||||
|
if (isCollapsed) {
|
||||||
return <div ref="subList" className={subListClasses}>
|
return <div ref="subList" className={subListClasses}>
|
||||||
{this._getHeaderJsx()}
|
{this._getHeaderJsx(isCollapsed)}
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
const tiles = this.makeRoomTiles();
|
const tiles = this.makeRoomTiles();
|
||||||
tiles.push(...this.props.extraTiles);
|
tiles.push(...this.props.extraTiles);
|
||||||
return <div ref="subList" className={subListClasses}>
|
return <div ref="subList" className={subListClasses}>
|
||||||
{this._getHeaderJsx()}
|
{this._getHeaderJsx(isCollapsed)}
|
||||||
<IndicatorScrollbar ref="scroller" className="mx_RoomSubList_scroll">
|
<IndicatorScrollbar ref="scroller" className="mx_RoomSubList_scroll">
|
||||||
{ tiles }
|
{ tiles }
|
||||||
</IndicatorScrollbar>
|
</IndicatorScrollbar>
|
||||||
|
@ -344,13 +346,13 @@ const RoomSubList = React.createClass({
|
||||||
} else {
|
} else {
|
||||||
const Loader = sdk.getComponent("elements.Spinner");
|
const Loader = sdk.getComponent("elements.Spinner");
|
||||||
let content;
|
let content;
|
||||||
if (this.props.showSpinner && !this.state.hidden) {
|
if (this.props.showSpinner && !isCollapsed) {
|
||||||
content = <Loader />;
|
content = <Loader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref="subList" className="mx_RoomSubList">
|
<div ref="subList" className="mx_RoomSubList">
|
||||||
{ this._getHeaderJsx() }
|
{ this._getHeaderJsx(isCollapsed) }
|
||||||
{ content }
|
{ content }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -82,7 +82,11 @@ module.exports = React.createClass({
|
||||||
this.collapsedState = collapsedJson ? JSON.parse(collapsedJson) : {};
|
this.collapsedState = collapsedJson ? JSON.parse(collapsedJson) : {};
|
||||||
this._layoutSections = [];
|
this._layoutSections = [];
|
||||||
|
|
||||||
this._layout = new Layout((key, size) => {
|
const unfilteredOptions = {
|
||||||
|
allowWhitespace: true,
|
||||||
|
handleHeight: 1,
|
||||||
|
};
|
||||||
|
this._unfilteredlayout = new Layout((key, size) => {
|
||||||
const subList = this._subListRefs[key];
|
const subList = this._subListRefs[key];
|
||||||
if (subList) {
|
if (subList) {
|
||||||
subList.setHeight(size);
|
subList.setHeight(size);
|
||||||
|
@ -95,7 +99,19 @@ module.exports = React.createClass({
|
||||||
window.localStorage.setItem("mx_roomlist_sizes",
|
window.localStorage.setItem("mx_roomlist_sizes",
|
||||||
JSON.stringify(this.subListSizes));
|
JSON.stringify(this.subListSizes));
|
||||||
}
|
}
|
||||||
}, this.subListSizes, this.collapsedState);
|
}, this.subListSizes, this.collapsedState, unfilteredOptions);
|
||||||
|
|
||||||
|
this._filteredLayout = new Layout((key, size) => {
|
||||||
|
const subList = this._subListRefs[key];
|
||||||
|
if (subList) {
|
||||||
|
subList.setHeight(size);
|
||||||
|
}
|
||||||
|
}, null, null, {
|
||||||
|
allowWhitespace: false,
|
||||||
|
handleHeight: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
this._layout = this._unfilteredlayout;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isLoadingLeftRooms: false,
|
isLoadingLeftRooms: false,
|
||||||
|
@ -187,15 +203,21 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
componentDidUpdate: function(prevProps) {
|
componentDidUpdate: function(prevProps) {
|
||||||
|
let forceLayoutUpdate = false;
|
||||||
this._repositionIncomingCallBox(undefined, false);
|
this._repositionIncomingCallBox(undefined, false);
|
||||||
// if (this.props.searchFilter !== prevProps.searchFilter) {
|
if (!this.props.searchFilter && prevProps.searchFilter) {
|
||||||
// this._checkSubListsOverflow();
|
this._layout = this._unfilteredlayout;
|
||||||
// }
|
forceLayoutUpdate = true;
|
||||||
|
} else if (this.props.searchFilter && !prevProps.searchFilter) {
|
||||||
|
this._layout = this._filteredLayout;
|
||||||
|
forceLayoutUpdate = true;
|
||||||
|
}
|
||||||
this._layout.update(
|
this._layout.update(
|
||||||
this._layoutSections,
|
this._layoutSections,
|
||||||
this.resizeContainer && this.resizeContainer.clientHeight,
|
this.resizeContainer && this.resizeContainer.clientHeight,
|
||||||
|
forceLayoutUpdate,
|
||||||
);
|
);
|
||||||
// TODO: call layout.setAvailableHeight, window height was changed when bannerShown prop was changed
|
this._checkSubListsOverflow();
|
||||||
},
|
},
|
||||||
|
|
||||||
onAction: function(payload) {
|
onAction: function(payload) {
|
||||||
|
@ -617,7 +639,7 @@ module.exports = React.createClass({
|
||||||
onHeaderClick(collapsed);
|
onHeaderClick(collapsed);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const startAsHidden = props.startAsHidden || this.collapsedState[chosenKey];
|
let startAsHidden = props.startAsHidden || this.collapsedState[chosenKey];
|
||||||
this._layoutSections.push({
|
this._layoutSections.push({
|
||||||
id: chosenKey,
|
id: chosenKey,
|
||||||
count: len,
|
count: len,
|
||||||
|
@ -625,6 +647,7 @@ module.exports = React.createClass({
|
||||||
let subList = (<RoomSubList
|
let subList = (<RoomSubList
|
||||||
ref={this._subListRef.bind(this, chosenKey)}
|
ref={this._subListRef.bind(this, chosenKey)}
|
||||||
startAsHidden={startAsHidden}
|
startAsHidden={startAsHidden}
|
||||||
|
forceExpand={!!this.props.searchFilter}
|
||||||
onHeaderClick={onSubListHeaderClick}
|
onHeaderClick={onSubListHeaderClick}
|
||||||
key={chosenKey}
|
key={chosenKey}
|
||||||
label={label}
|
label={label}
|
||||||
|
|
|
@ -16,9 +16,6 @@ limitations under the License.
|
||||||
|
|
||||||
import FixedDistributor from "./fixed";
|
import FixedDistributor from "./fixed";
|
||||||
|
|
||||||
// const allowWhitespace = true;
|
|
||||||
const handleHeight = 1;
|
|
||||||
|
|
||||||
function clamp(height, min, max) {
|
function clamp(height, min, max) {
|
||||||
if (height > max) return max;
|
if (height > max) return max;
|
||||||
if (height < min) return min;
|
if (height < min) return min;
|
||||||
|
@ -26,7 +23,7 @@ function clamp(height, min, max) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Layout {
|
export class Layout {
|
||||||
constructor(applyHeight, initialSizes, collapsedState) {
|
constructor(applyHeight, initialSizes, collapsedState, options) {
|
||||||
// callback to set height of section
|
// callback to set height of section
|
||||||
this._applyHeight = applyHeight;
|
this._applyHeight = applyHeight;
|
||||||
// list of {id, count} objects,
|
// list of {id, count} objects,
|
||||||
|
@ -41,6 +38,17 @@ export class Layout {
|
||||||
this._sectionHeights = Object.assign({}, initialSizes);
|
this._sectionHeights = Object.assign({}, initialSizes);
|
||||||
// in-progress heights, while dragging. Committed on mouse-up.
|
// in-progress heights, while dragging. Committed on mouse-up.
|
||||||
this._heights = [];
|
this._heights = [];
|
||||||
|
// use while manually resizing to cancel
|
||||||
|
// the resize for a given mouse position
|
||||||
|
// when the previous resize made the layout
|
||||||
|
// constrained
|
||||||
|
this._clampedOffset = 0;
|
||||||
|
// used while manually resizing, to clear
|
||||||
|
// _clampedOffset when the direction of resizing changes
|
||||||
|
this._lastOffset = 0;
|
||||||
|
|
||||||
|
this._allowWhitespace = options && options.allowWhitespace;
|
||||||
|
this._handleHeight = (options && options.handleHeight) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAvailableHeight(newSize) {
|
setAvailableHeight(newSize) {
|
||||||
|
@ -60,7 +68,7 @@ export class Layout {
|
||||||
this._applyNewSize();
|
this._applyNewSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
update(sections, availableHeight) {
|
update(sections, availableHeight, force = false) {
|
||||||
let heightChanged = false;
|
let heightChanged = false;
|
||||||
|
|
||||||
if (Number.isFinite(availableHeight) && availableHeight !== this._availableHeight) {
|
if (Number.isFinite(availableHeight) && availableHeight !== this._availableHeight) {
|
||||||
|
@ -75,7 +83,7 @@ export class Layout {
|
||||||
return a.id !== b.id || a.count !== b.count;
|
return a.id !== b.id || a.count !== b.count;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!heightChanged && !sectionsChanged) {
|
if (!heightChanged && !sectionsChanged && !force) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +112,7 @@ export class Layout {
|
||||||
const collapsed = this._collapsedState[section.id];
|
const collapsed = this._collapsedState[section.id];
|
||||||
return count + (collapsed ? 0 : 1);
|
return count + (collapsed ? 0 : 1);
|
||||||
}, 0);
|
}, 0);
|
||||||
return this._availableHeight - ((nonCollapsedSectionCount - 1) * handleHeight);
|
return this._availableHeight - ((nonCollapsedSectionCount - 1) * this._handleHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyNewSize() {
|
_applyNewSize() {
|
||||||
|
@ -130,9 +138,10 @@ export class Layout {
|
||||||
|
|
||||||
if (collapsed) {
|
if (collapsed) {
|
||||||
return this._sectionHeight(0);
|
return this._sectionHeight(0);
|
||||||
|
} else if (!this._allowWhitespace) {
|
||||||
|
return this._sectionHeight(section.count);
|
||||||
} else {
|
} else {
|
||||||
return 100000;
|
return 100000;
|
||||||
// return this._sectionHeight(section.count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,6 +277,22 @@ export class Layout {
|
||||||
this._sectionHeights[section.id] = this._heights[i];
|
this._sectionHeights[section.id] = this._heights[i];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setUncommittedSectionHeight(sectionIndex, offset) {
|
||||||
|
if (Math.sign(offset) != Math.sign(this._lastOffset)) {
|
||||||
|
this._clampedOffset = undefined;
|
||||||
|
}
|
||||||
|
if (this._clampedOffset !== undefined) {
|
||||||
|
if (offset < 0 && offset < this._clampedOffset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (offset > 0 && offset > this._clampedOffset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._clampedOffset = this._relayout(sectionIndex, offset);
|
||||||
|
this._lastOffset = offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Handle {
|
class Handle {
|
||||||
|
@ -278,7 +303,10 @@ class Handle {
|
||||||
}
|
}
|
||||||
|
|
||||||
setHeight(height) {
|
setHeight(height) {
|
||||||
this._layout._relayout(this._sectionIndex, height - this._initialHeight);
|
this._layout._setUncommittedSectionHeight(
|
||||||
|
this._sectionIndex,
|
||||||
|
height - this._initialHeight,
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue