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

Render Jitsi (and other sticky widgets) in PiP container, so it can be dragged and the "jump to room functionality" is provided #7450

Merged
merged 29 commits into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
48224bb
Always show jitsi
toger5 Dec 21, 2021
17e3776
make active widgets (jitsi call) use the same container pip container…
toger5 Dec 27, 2021
68e30d5
Rename files and fix missing update
toger5 Dec 27, 2021
4553b9f
remove comments
toger5 Dec 28, 2021
47f0906
extend callType enum with Widget (jitsi Call)
toger5 Dec 28, 2021
a24ba78
onWidgetAction->onAction
toger5 Dec 28, 2021
c975cbc
clean up onAction switch
toger5 Dec 28, 2021
d90e2c5
add translation
toger5 Dec 28, 2021
4fb3d9f
rename call-> pip in missing places
toger5 Dec 28, 2021
01c34a6
CallContainer -> PiPcontainer
toger5 Dec 28, 2021
d648c3f
fix pointer events beeing captured by IFrame on drag
toger5 Dec 28, 2021
f489316
the linter.. the linter ..
toger5 Dec 28, 2021
5c5abc3
revert CallType.Widget enum case
toger5 Dec 28, 2021
34f5b4c
fix i18n
toger5 Dec 28, 2021
b9afcac
review fixes
toger5 Dec 29, 2021
7e7bae2
Merge branch 'toger5/maximised_widgets_jitsy_flaoting' into toger5/ji…
toger5 Dec 29, 2021
c590a07
fix go to room on double click on pip widget
toger5 Dec 29, 2021
346eb6e
Merge branch 'develop' into toger5/maximised_widgets_jitsy_flaoting
toger5 Jan 5, 2022
b62c868
refactor for new right panel
toger5 Jan 5, 2022
c3698f0
Merge branch 'toger5/maximised_widgets_jitsy_flaoting' into toger5/ji…
toger5 Jan 5, 2022
5bcf608
fix for react not updating state
toger5 Jan 5, 2022
9e4aeca
Update src/components/views/elements/PersistentApp.tsx
toger5 Jan 11, 2022
b033398
Merge branch 'toger5/maximised_widgets_jitsy_flaoting' into toger5/ji…
toger5 Jan 11, 2022
e0d5216
review
toger5 Jan 11, 2022
2eb3af2
"PiP" -> "Pip"
toger5 Jan 11, 2022
8acf163
Merge branch 'develop' into toger5/jitsi_pip_container
toger5 Jan 11, 2022
c49b72b
lint
toger5 Jan 11, 2022
55d8cab
improove weird styling
toger5 Jan 12, 2022
d24195d
Merge branch 'develop' into toger5/jitsi_pip_container
toger5 Jan 12, 2022
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
2 changes: 1 addition & 1 deletion res/css/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@
@import "./views/typography/_Heading.scss";
@import "./views/verification/_VerificationShowSas.scss";
@import "./views/voip/CallView/_CallViewButtons.scss";
@import "./views/voip/_CallContainer.scss";
@import "./views/voip/_CallPreview.scss";
@import "./views/voip/_CallView.scss";
@import "./views/voip/_CallViewForRoom.scss";
Expand All @@ -313,4 +312,5 @@
@import "./views/voip/_DialPad.scss";
@import "./views/voip/_DialPadContextMenu.scss";
@import "./views/voip/_DialPadModal.scss";
@import "./views/voip/_PiPContainer.scss";
@import "./views/voip/_VideoFeed.scss";
13 changes: 7 additions & 6 deletions res/css/views/voip/_CallView.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ limitations under the License.
background-color: $dark-panel-bg-color;
padding-left: 8px;
padding-right: 8px;
// XXX: CallContainer sets pointer-events: none - should probably be set back in a better place
// XXX: PiPContainer sets pointer-events: none - should probably be set back in a better place
pointer-events: initial;
}

.mx_CallView_large {
padding-bottom: 10px;
margin: $container-gap-width;
margin-right: calc($container-gap-width / 2); // The left side gap is fully handled by this margin. To prohibit bleeding on webkit browser.
// The left side gap is fully handled by this margin. To prohibit bleeding on webkit browser.
margin-right: calc($container-gap-width / 2);
margin-bottom: 10px;
display: flex;
flex-direction: column;
Expand All @@ -46,7 +47,7 @@ limitations under the License.
width: 320px;
padding-bottom: 8px;
background-color: $system;
box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.20);
box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.2);
border-radius: 8px;

.mx_CallView_video_hold,
Expand Down Expand Up @@ -170,7 +171,7 @@ limitations under the License.
background-position: center;
filter: blur(20px);
&::after {
content: '';
content: "";
display: block;
position: absolute;
width: 100%;
Expand All @@ -194,10 +195,10 @@ limitations under the License.
display: block;
margin-left: auto;
margin-right: auto;
content: '';
content: "";
toger5 marked this conversation as resolved.
Show resolved Hide resolved
width: 40px;
height: 40px;
background-image: url('$(res)/img/voip/paused.svg');
background-image: url("$(res)/img/voip/paused.svg");
background-position: center;
background-size: cover;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

.mx_CallContainer {
.mx_PiPContainer {
position: absolute;
right: 20px;
bottom: 72px;
Expand All @@ -25,8 +25,4 @@ limitations under the License.
// sure the cursor hits the iframe for Jitsi which will be at a
// different level.
pointer-events: none;

.mx_AppTile_persistedWrapper div {
min-width: 350px;
}
}
4 changes: 2 additions & 2 deletions src/components/structures/LoggedInView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import { DefaultTagID } from "../../stores/room-list/models";
import { hideToast as hideServerLimitToast, showToast as showServerLimitToast } from "../../toasts/ServerLimitToast";
import { Action } from "../../dispatcher/actions";
import LeftPanel from "./LeftPanel";
import CallContainer from '../views/voip/CallContainer';
import PiPContainer from '../views/voip/PipContainer';
toger5 marked this conversation as resolved.
Show resolved Hide resolved
import { ViewRoomDeltaPayload } from "../../dispatcher/payloads/ViewRoomDeltaPayload";
import RoomListStore from "../../stores/room-list/RoomListStore";
import NonUrgentToastContainer from "./NonUrgentToastContainer";
Expand Down Expand Up @@ -674,7 +674,7 @@ class LoggedInView extends React.Component<IProps, IState> {
</div>
</div>
</div>
<CallContainer />
<PiPContainer />
<NonUrgentToastContainer />
<HostSignupContainer />
{ audioFeedArraysForCalls }
Expand Down
15 changes: 10 additions & 5 deletions src/components/views/elements/AppTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,13 @@ export default class AppTile extends React.Component<IProps, IState> {

// Also wrap the PersistedElement in a div to fix the height, otherwise
// AppTile's border is in the wrong place

// For persistent apps in PiP we want the zIndex to be higher then for other persistent apps (100)
// otherwise there are issues that the PiP view is drawn UNDER another widget (Persistent app) when dragged around.
const zIndexAboveOtherPersistentElements = 101;

appTileBody = <div className="mx_AppTile_persistedWrapper">
<PersistedElement zIndex={this.props.miniMode ? 10 : 9}persistKey={this.persistKey}>
<PersistedElement zIndex={this.props.miniMode ? zIndexAboveOtherPersistentElements : 9} persistKey={this.persistKey}>
{ appTileBody }
</PersistedElement>
</div>;
Expand Down Expand Up @@ -548,12 +553,12 @@ export default class AppTile extends React.Component<IProps, IState> {
maxMinButton = <AccessibleButton
className={
"mx_AppTileMenuBar_iconButton"
+ (widgetIsMaximised
? " mx_AppTileMenuBar_iconButton_minWidget"
: " mx_AppTileMenuBar_iconButton_maxWidget")
+ (widgetIsMaximised
? " mx_AppTileMenuBar_iconButton_minWidget"
: " mx_AppTileMenuBar_iconButton_maxWidget")
toger5 marked this conversation as resolved.
Show resolved Hide resolved
}
title={
widgetIsMaximised ? _t('Close'): _t('Maximise widget')
widgetIsMaximised ? _t('Close') : _t('Maximise widget')
}
onClick={this.onMaxMinWidgetClick}
/>;
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/elements/PersistedElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export default class PersistedElement extends React.Component<IProps> {
width: parentRect.width + 'px',
height: parentRect.height + 'px',
});
}, 100, { trailing: true, leading: true });
}, 16, { trailing: true, leading: true });
toger5 marked this conversation as resolved.
Show resolved Hide resolved

public render(): JSX.Element {
return <div ref={this.collectChildContainer} />;
Expand Down
120 changes: 29 additions & 91 deletions src/components/views/elements/PersistentApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,141 +16,79 @@ limitations under the License.
*/

import React from 'react';
import { EventSubscription } from 'fbemitter';
import { Room } from "matrix-js-sdk/src/models/room";

import RoomViewStore from '../../../stores/RoomViewStore';
import ActiveWidgetStore, { ActiveWidgetStoreEvent } from '../../../stores/ActiveWidgetStore';
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
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';

interface IProps {
// none
persistentWidgetId: string;
pointerEvents?: string;
}

interface IState {
roomId: string;
persistentWidgetId: string;
rightPanelPhase?: RightPanelPhases;
}

@replaceableComponent("views.elements.PersistentApp")
export default class PersistentApp extends React.Component<IProps, IState> {
private roomStoreToken: EventSubscription;

constructor(props: IProps) {
super(props);

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);
}

public componentWillUnmount(): void {
if (this.roomStoreToken) {
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);
}
MatrixClientPeg.get().off("Room.myMembership", this.onMyMembership);
}

private onRoomViewStoreUpdate = (): void => {
if (RoomViewStore.getRoomId() === this.state.roomId) return;
this.setState({
roomId: RoomViewStore.getRoomId(),
});
};

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

private onActiveWidgetStoreUpdate = (): void => {
this.setState({
persistentWidgetId: ActiveWidgetStore.instance.getPersistentWidgetId(),
});
};

private onMyMembership = async (room: Room, membership: string): Promise<void> => {
const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(this.state.persistentWidgetId);
const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(this.props.persistentWidgetId);
if (membership !== "join") {
// we're not in the room anymore - delete
if (room .roomId === persistentWidgetInRoomId) {
ActiveWidgetStore.instance.destroyPersistentWidget(this.state.persistentWidgetId);
if (room.roomId === persistentWidgetInRoomId) {
ActiveWidgetStore.instance.destroyPersistentWidget(this.props.persistentWidgetId);
}
}
};

public render(): JSX.Element {
const wId = this.state.persistentWidgetId;
const wId = this.props.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 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();
});
const app = WidgetUtils.makeAppConfig(
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(),
persistentWidgetInRoomId, appEvent.getId(),
);
return <AppTile
key={app.id}
app={app}
fullWidth={true}
room={persistentWidgetInRoom}
userId={MatrixClientPeg.get().credentials.userId}
creatorUserId={app.creatorUserId}
widgetPageTitle={WidgetUtils.getWidgetDataTitle(app)}
waitForIframeLoad={app.waitForIframeLoad}
miniMode={true}
showMenubar={false}
/>;
}
// get the widget data
const appEvent = WidgetUtils.getRoomWidgets(persistentWidgetInRoom).find((ev) => {
return ev.getStateKey() === ActiveWidgetStore.instance.getPersistentWidgetId();
});
const app = WidgetUtils.makeAppConfig(
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(),
persistentWidgetInRoomId, appEvent.getId(),
);
return <AppTile
key={app.id}
app={app}
fullWidth={true}
room={persistentWidgetInRoom}
userId={MatrixClientPeg.get().credentials.userId}
creatorUserId={app.creatorUserId}
widgetPageTitle={WidgetUtils.getWidgetDataTitle(app)}
waitForIframeLoad={app.waitForIframeLoad}
miniMode={true}
showMenubar={false}
pointerEvents={this.props.pointerEvents}
/>;
}
return null;
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/rooms/Stickerpicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
// Close the sticker picker when the window resizes
window.addEventListener('resize', this.onResize);

this.dispatcherRef = dis.register(this.onWidgetAction);
this.dispatcherRef = dis.register(this.onAction);

// Track updates to widget state in account data
MatrixClientPeg.get().on('accountData', this.updateWidget);
Expand Down Expand Up @@ -198,7 +198,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
});
};

private onWidgetAction = (payload: ActionPayload): void => {
private onAction = (payload: ActionPayload): void => {
switch (payload.action) {
case "user_widget_updated":
this.forceUpdate();
Expand Down
Loading