Iterate with new buttons and resize locking

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2020-10-15 11:14:48 +01:00
parent d36fafd0c6
commit a6c81a903c
8 changed files with 173 additions and 89 deletions

View file

@ -26,6 +26,7 @@ interface ITooltipProps extends React.ComponentProps<typeof AccessibleButton> {
tooltip?: React.ReactNode;
tooltipClassName?: string;
forceHide?: boolean;
yOffset?: number;
}
interface IState {
@ -63,12 +64,13 @@ export default class AccessibleTooltipButton extends React.PureComponent<IToolti
render() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {title, tooltip, children, tooltipClassName, forceHide, ...props} = this.props;
const {title, tooltip, children, tooltipClassName, forceHide, yOffset, ...props} = this.props;
const tip = this.state.hover ? <Tooltip
className="mx_AccessibleTooltipButton_container"
tooltipClassName={classNames("mx_AccessibleTooltipButton_tooltip", tooltipClassName)}
label={tooltip || title}
yOffset={yOffset}
/> : <div />;
return (
<AccessibleButton

View file

@ -36,6 +36,7 @@ interface IProps {
// the react element to put into the tooltip
label: React.ReactNode;
forceOnRight?: boolean;
yOffset?: number;
}
export default class Tooltip extends React.Component<IProps> {
@ -46,6 +47,7 @@ export default class Tooltip extends React.Component<IProps> {
public static readonly defaultProps = {
visible: true,
yOffset: 0,
};
// Create a wrapper for the tooltip outside the parent and attach it to the body element
@ -82,9 +84,9 @@ export default class Tooltip extends React.Component<IProps> {
offset = Math.floor(parentBox.height - MIN_TOOLTIP_HEIGHT);
}
style.top = (parentBox.top - 2) + window.pageYOffset + offset;
style.top = (parentBox.top - 2 + this.props.yOffset) + window.pageYOffset + offset;
if (!this.props.forceOnRight && parentBox.right > window.innerWidth / 2) {
style.right = window.innerWidth - parentBox.right - window.pageXOffset - 8;
style.right = window.innerWidth - parentBox.right - window.pageXOffset - 16;
} else {
style.left = parentBox.right + window.pageXOffset + 6;
}

View file

@ -43,7 +43,7 @@ import { E2EStatus } from "../../../utils/ShieldUtils";
import RoomContext from "../../../contexts/RoomContext";
import {UIFeature} from "../../../settings/UIFeature";
import {ContextMenuButton} from "../../../accessibility/context_menu/ContextMenuButton";
import {ChevronFace, useContextMenu} from "../../structures/ContextMenu";
import {ChevronFace, ContextMenuTooltipButton, useContextMenu} from "../../structures/ContextMenu";
import WidgetContextMenu from "../context_menus/WidgetContextMenu";
interface IProps {
@ -70,11 +70,11 @@ const Button: React.FC<IButtonProps> = ({ children, className, onClick }) => {
};
export const useWidgets = (room: Room) => {
const [apps, setApps] = useState<IApp[]>(WidgetStore.instance.getApps(room));
const [apps, setApps] = useState<IApp[]>(WidgetStore.instance.getApps(room.roomId));
const updateApps = useCallback(() => {
// Copy the array so that we always trigger a re-render, as some updates mutate the array of apps/settings
setApps([...WidgetStore.instance.getApps(room)]);
setApps([...WidgetStore.instance.getApps(room.roomId)]);
}, [room]);
useEffect(updateApps, [room]);
@ -130,34 +130,39 @@ const AppRow: React.FC<IAppRowProps> = ({ app }) => {
pinTitle = isPinned ? _t("Unpin") : _t("Pin");
}
return <div className="mx_RoomSummaryCard_widgetRow" ref={handle}>
const classes = classNames("mx_BaseCard_Button mx_RoomSummaryCard_Button", {
mx_RoomSummaryCard_Button_pinned: isPinned,
});
return <div className={classes} ref={handle}>
<AccessibleTooltipButton
className="mx_BaseCard_Button mx_RoomSummaryCard_Button mx_RoomSummaryCard_icon_app"
className="mx_RoomSummaryCard_icon_app"
onClick={onOpenWidgetClick}
// only show a tooltip if the widget is pinned
title={isPinned ? _t("Unpin a widget to view it in this panel") : ""}
forceHide={!isPinned}
disabled={isPinned}
yOffset={-48}
>
<WidgetAvatar app={app} />
<span>{name}</span>
{ subtitle }
</AccessibleTooltipButton>
<AccessibleTooltipButton
className={classNames("mx_RoomSummaryCard_app_pinToggle", {
mx_RoomSummaryCard_app_pinned: isPinned,
})}
onClick={togglePin}
title={pinTitle}
disabled={cannotPin}
/>
<ContextMenuButton
<ContextMenuTooltipButton
className="mx_RoomSummaryCard_app_options"
isExpanded={menuDisplayed}
onClick={openMenu}
label={_t("Options")}
title={_t("Options")}
yOffset={-24}
/>
<AccessibleTooltipButton
className="mx_RoomSummaryCard_app_pinToggle"
onClick={togglePin}
title={pinTitle}
disabled={cannotPin}
yOffset={-24}
/>
{ contextMenu }

View file

@ -93,8 +93,9 @@ export default class AppsDrawer extends React.Component {
onResizeStop: () => {
this._resizeContainer.classList.remove("mx_AppsDrawer_resizing");
// persist to localStorage
console.log("@@ _saveResizerPreferences");
localStorage.setItem(this._getStorageKey(), JSON.stringify([
this._getIdString(),
this._getAppsHash(this.state.apps),
...this.state.apps.slice(1).map((_, i) => this.resizer.forHandleAt(i).size),
]));
},
@ -121,26 +122,39 @@ export default class AppsDrawer extends React.Component {
_getStorageKey = () => `mx_apps_drawer-${this.props.room.roomId}`;
_getIdString = () => this.state.apps.map(app => app.id).join("~");
_getAppsHash = (apps) => apps.map(app => app.id).join("~");
_loadResizerPreferences = () => { // TODO call this when changing pinned apps
componentDidUpdate(prevProps, prevState) {
if (this._getAppsHash(this.state.apps) !== this._getAppsHash(prevState.apps)) {
this._loadResizerPreferences();
}
}
_loadResizerPreferences = () => {
console.log("@@ _loadResizerPreferences");
try {
const [idString, ...sizes] = JSON.parse(localStorage.getItem(this._getStorageKey()));
// format: [idString: string, ...percentages: string];
if (this._getIdString() !== idString) return;
sizes.forEach((size, i) => {
const distributor = this.resizer.forHandleAt(i);
distributor.size = size;
distributor.finish();
});
// TODO determine the exact behaviour we want for layout changing when pinning/unpinning
if (this._getAppsHash() === idString || true) {
sizes.forEach((size, i) => {
const distributor = this.resizer.forHandleAt(i);
if (distributor) {
distributor.size = size;
distributor.finish();
}
});
return;
}
} catch (e) {
console.error(e);
this.state.apps.slice(1).forEach((_, i) => {
const distributor = this.resizer.forHandleAt(i);
distributor.item.clearSize();
distributor.finish();
});
// this is expected
}
if (this.state.apps) {
console.log("@@ full relaxation");
const distributors = this.resizer.getDistributors();
distributors.forEach(d => d.item.clearSize());
distributors.forEach(d => d.finish());
}
};
@ -162,12 +176,12 @@ export default class AppsDrawer extends React.Component {
}
};
_getApps = () => WidgetStore.instance.getApps(this.props.room, true);
_getApps = () => WidgetStore.instance.getPinnedApps(this.props.room.roomId);
_updateApps = () => {
this.setState({
apps: this._getApps(),
}, this._loadResizerPreferences);
});
};
_launchManageIntegrations() {