Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Fix active Jitsi calls (and other active widgets) not being visible on screen, by showing them in PiP if they are not visible in any other container #7435

Merged
merged 5 commits into from
Jan 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions src/components/views/elements/PersistentApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ import WidgetUtils from '../../../utils/WidgetUtils';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { replaceableComponent } from "../../../utils/replaceableComponent";
import AppTile from "./AppTile";
import { Container, WidgetLayoutStore } from '../../../stores/widgets/WidgetLayoutStore';
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
import { UPDATE_EVENT } from '../../../stores/AsyncStore';
toger5 marked this conversation as resolved.
Show resolved Hide resolved

interface IProps {
// none
Expand All @@ -33,6 +37,7 @@ interface IProps {
interface IState {
roomId: string;
persistentWidgetId: string;
rightPanelPhase?: RightPanelPhases;
}

@replaceableComponent("views.elements.PersistentApp")
Expand All @@ -45,12 +50,14 @@ export default class PersistentApp extends React.Component<IProps, IState> {
this.state = {
roomId: RoomViewStore.getRoomId(),
persistentWidgetId: ActiveWidgetStore.instance.getPersistentWidgetId(),
rightPanelPhase: RightPanelStore.instance.currentCard.phase,
};
}

public componentDidMount(): void {
this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
ActiveWidgetStore.instance.on(ActiveWidgetStoreEvent.Update, this.onActiveWidgetStoreUpdate);
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership);
}

Expand All @@ -59,6 +66,7 @@ export default class PersistentApp extends React.Component<IProps, IState> {
this.roomStoreToken.remove();
}
ActiveWidgetStore.instance.removeListener(ActiveWidgetStoreEvent.Update, this.onActiveWidgetStoreUpdate);
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("Room.myMembership", this.onMyMembership);
}
Expand All @@ -71,6 +79,12 @@ export default class PersistentApp extends React.Component<IProps, IState> {
});
};

private onRightPanelStoreUpdate = () => {
this.setState({
rightPanelPhase: RightPanelStore.instance.currentCard.phase,
});
};

private onActiveWidgetStoreUpdate = (): void => {
this.setState({
persistentWidgetId: ActiveWidgetStore.instance.getPersistentWidgetId(),
Expand All @@ -88,17 +102,34 @@ export default class PersistentApp extends React.Component<IProps, IState> {
};

public render(): JSX.Element {
if (this.state.persistentWidgetId) {
const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(this.state.persistentWidgetId);
const wId = this.state.persistentWidgetId;
if (wId) {
const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(wId);

const persistentWidgetInRoom = MatrixClientPeg.get().getRoom(persistentWidgetInRoomId);

// Sanity check the room - the widget may have been destroyed between render cycles, and
// thus no room is associated anymore.
if (!persistentWidgetInRoom) return null;

const myMembership = persistentWidgetInRoom.getMyMembership();
if (this.state.roomId !== persistentWidgetInRoomId && myMembership === "join") {
const wls = WidgetLayoutStore.instance;

const userIsPartOfTheRoom = persistentWidgetInRoom.getMyMembership() == "join";
const fromAnotherRoom = this.state.roomId !== persistentWidgetInRoomId;

const notInRightPanel =
!(this.state.rightPanelPhase == RightPanelPhases.Widget &&
wId == RightPanelStore.instance.currentCard.state?.widgetId);
const notInCenterContainer =
!wls.getContainerWidgets(persistentWidgetInRoom, Container.Center).some((app) => app.id == wId);
const notInTopContainer =
!wls.getContainerWidgets(persistentWidgetInRoom, Container.Top).some(app => app.id == wId);
if (
// the widget should only be shown as a persistent app (in a floating pip container) if it is not visible on screen
// either, because we are viewing a different room OR because it is in none of the possible containers of the room view.
(fromAnotherRoom && userIsPartOfTheRoom) ||
(notInRightPanel && notInCenterContainer && notInTopContainer && userIsPartOfTheRoom)
) {
// get the widget data
const appEvent = WidgetUtils.getRoomWidgets(persistentWidgetInRoom).find((ev) => {
return ev.getStateKey() === ActiveWidgetStore.instance.getPersistentWidgetId();
Expand Down
11 changes: 8 additions & 3 deletions src/components/views/rooms/Stickerpicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,14 @@ import { IntegrationManagers } from "../../../integrations/IntegrationManagers";
import SettingsStore from "../../../settings/SettingsStore";
import ContextMenu, { ChevronFace } from "../../structures/ContextMenu";
import { WidgetType } from "../../../widgets/WidgetType";
import { Action } from "../../../dispatcher/actions";
import { WidgetMessagingStore } from "../../../stores/widgets/WidgetMessagingStore";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { ActionPayload } from '../../../dispatcher/payloads';
import ScalarAuthClient from '../../../ScalarAuthClient';
import GenericElementContextMenu from "../context_menus/GenericElementContextMenu";
import { IApp } from "../../../stores/WidgetStore";
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
import { UPDATE_EVENT } from '../../../stores/AsyncStore';

// This should be below the dialog level (4000), but above the rest of the UI (1000-2000).
// We sit in a context menu, so this should be given to the context menu.
Expand Down Expand Up @@ -139,14 +140,15 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
// Track updates to widget state in account data
MatrixClientPeg.get().on('accountData', this.updateWidget);

RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
// Initialise widget state from current account data
this.updateWidget();
}

public componentWillUnmount(): void {
const client = MatrixClientPeg.get();
if (client) client.removeListener('accountData', this.updateWidget);

RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
window.removeEventListener('resize', this.onResize);
if (this.dispatcherRef) {
dis.unregister(this.dispatcherRef);
Expand Down Expand Up @@ -204,14 +206,17 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
case "stickerpicker_close":
this.props.setShowStickers(false);
break;
case Action.AfterRightPanelPhaseChange:
case "show_left_panel":
case "hide_left_panel":
this.props.setShowStickers(false);
break;
}
};

private onRightPanelStoreUpdate = () => {
this.props.setShowStickers(false);
};

private defaultStickerpickerContent(): JSX.Element {
return (
<AccessibleButton onClick={this.launchManageIntegrations}
Expand Down
17 changes: 10 additions & 7 deletions src/components/views/voip/CallPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,16 @@ export default class CallPreview extends React.Component<IProps, IState> {
draggable={pipMode}
onDoubleClick={this.onDoubleClick}
>
{ ({ onStartMoving, onResize }) => <CallView
onMouseDownOnHeader={onStartMoving}
call={this.state.primaryCall}
secondaryCall={this.state.secondaryCall}
pipMode={pipMode}
onResize={onResize}
/> }
{
({ onStartMoving, onResize }) =>
<CallView
onMouseDownOnHeader={onStartMoving}
call={this.state.primaryCall}
secondaryCall={this.state.secondaryCall}
pipMode={pipMode}
onResize={onResize}
/>
}
</PictureInPictureDragger>

);
Expand Down
5 changes: 0 additions & 5 deletions src/dispatcher/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,6 @@ export enum Action {
*/
ViewRoomDelta = "view_room_delta",

/**
* Trigged after the phase of the right panel is set. Should be used with AfterRightPanelPhaseChangePayload.
*/
AfterRightPanelPhaseChange = "after_right_panel_phase_change",

/**
* Opens the modal dial pad
*/
Expand Down