Make AppsDrawer resizable by dragging its bottom border

Signed-off-by: Pauli Virtanen <pav@iki.fi>
pull/21833/head
Pauli Virtanen 2020-04-23 22:52:28 +03:00
parent 11438aeee6
commit e897e97fd6
2 changed files with 83 additions and 6 deletions

View File

@ -16,9 +16,10 @@ limitations under the License.
*/ */
/* /*
Minimum size for usual AppTiles and fixed size for mini-tiles. Size settings
*/ */
$AppTileMinHeight: 300px; $AppsDrawerMinHeight: 50px;
$AppsDrawerDefaultHeight: 300px;
$MiniAppTileHeight: 114px; $MiniAppTileHeight: 114px;
.mx_AppsDrawer { .mx_AppsDrawer {
@ -35,6 +36,13 @@ $MiniAppTileHeight: 114px;
flex-direction: row; flex-direction: row;
align-items: stretch; align-items: stretch;
justify-content: center; justify-content: center;
min-height: $AppsDrawerMinHeight;
height: $AppsDrawerDefaultHeight;
}
.mx_AppsDrawer_minimised .mx_AppsContainer {
min-height: inherit;
height: inherit;
} }
.mx_AddWidget_button { .mx_AddWidget_button {
@ -67,7 +75,6 @@ $MiniAppTileHeight: 114px;
border-radius: 4px; border-radius: 4px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: $AppTileMinHeight;
} }
.mx_AppTile:last-child { .mx_AppTile:last-child {
@ -83,7 +90,6 @@ $MiniAppTileHeight: 114px;
border-radius: 4px; border-radius: 4px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: $AppTileMinHeight;
} }
.mx_AppTile_mini { .mx_AppTile_mini {
@ -378,3 +384,27 @@ form.mx_Custom_Widget_Form div {
.mx_AppLoading iframe { .mx_AppLoading iframe {
display: none; display: none;
} }
/* Hidden resize handle (Apptile bottom serves as indicator) */
.mx_AppsDrawer .mx_ResizeHandle > div {
background: inherit;
}
.mx_AppsDrawer_fullWidth .mx_ResizeHandle {
max-width: 960px;
margin-left: auto;
margin-right: auto;
}
.mx_AppsDrawer_minimised .mx_ResizeHandle {
display: none;
}
/* Avoid apptile iframes capturing mouse event focus when resizing */
.mx_AppsDrawer_resizing iframe {
pointer-events: none;
}
.mx_AppsDrawer_resizing .mx_AppTile_persistedWrapper {
z-index: 1;
}

View File

@ -30,6 +30,9 @@ import WidgetEchoStore from "../../../stores/WidgetEchoStore";
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import classNames from 'classnames';
import ResizeHandle from '../elements/ResizeHandle';
import {Resizer, FixedDistributor} from '../../../resizer';
// The maximum number of widgets that can be added in a room // The maximum number of widgets that can be added in a room
const MAX_WIDGETS = 2; const MAX_WIDGETS = 2;
@ -60,6 +63,7 @@ export default createReactClass({
MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents); MatrixClientPeg.get().on('RoomState.events', this.onRoomStateEvents);
WidgetEchoStore.on('update', this._updateApps); WidgetEchoStore.on('update', this._updateApps);
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
this._createResizer();
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
@ -69,6 +73,10 @@ export default createReactClass({
} }
WidgetEchoStore.removeListener('update', this._updateApps); WidgetEchoStore.removeListener('update', this._updateApps);
if (this.dispatcherRef) dis.unregister(this.dispatcherRef); if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
if (this.resizer) {
this.resizer.detach();
this.resizer = null;
}
}, },
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
@ -154,6 +162,30 @@ export default createReactClass({
this._launchManageIntegrations(); this._launchManageIntegrations();
}, },
_createResizer: function() {
if (!this.resizeContainer) {
return;
}
const classNames = {
handle: "mx_ResizeHandle",
vertical: "mx_ResizeHandle_vertical",
resizing: "mx_AppsDrawer_resizing",
};
const resizer = new Resizer(
this.resizeContainer,
FixedDistributor,
{},
);
resizer.setClassNames(classNames);
resizer.attach();
this.resizer = resizer;
},
_setResizeContainerRef: function(div) {
this.resizeContainer = div;
},
render: function() { render: function() {
const apps = this.state.apps.map((app, index, arr) => { const apps = this.state.apps.map((app, index, arr) => {
const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, this.props.room.roomId); const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, this.props.room.roomId);
@ -191,6 +223,13 @@ export default createReactClass({
</AccessibleButton>; </AccessibleButton>;
} }
const containerStyle = {
maxHeight: Math.max(this.props.maxHeight - 50, 300),
};
if (!this.props.showApps && this.resizer) {
this.resizer.forHandleAt(0).item.clearSize();
}
let spinner; let spinner;
if ( if (
apps.length === 0 && WidgetEchoStore.roomHasPendingWidgets( apps.length === 0 && WidgetEchoStore.roomHasPendingWidgets(
@ -202,12 +241,20 @@ export default createReactClass({
spinner = <Loader />; spinner = <Loader />;
} }
const classes = classNames({
"mx_AppsDrawer": true,
"mx_AppsDrawer_hidden": this.props.hide,
"mx_AppsDrawer_fullWidth": apps.length < 2,
"mx_AppsDrawer_minimised": !this.props.showApps,
});
return ( return (
<div className={'mx_AppsDrawer' + (this.props.hide ? ' mx_AppsDrawer_hidden' : '')}> <div className={classes} ref={this._setResizeContainerRef}>
<div id='apps' className='mx_AppsContainer'> <div id='apps' className='mx_AppsContainer' style={containerStyle}>
{ apps } { apps }
{ spinner } { spinner }
</div> </div>
<ResizeHandle vertical={true} />
{ this._canUserModify() && addWidget } { this._canUserModify() && addWidget }
</div> </div>
); );