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 21 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 @@ -303,7 +303,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 @@ -312,4 +311,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';
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
2 changes: 1 addition & 1 deletion src/components/views/elements/AppTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ 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
appTileBody = <div className="mx_AppTile_persistedWrapper">
<PersistedElement zIndex={this.props.miniMode ? 10 : 9}persistKey={this.persistKey}>
<PersistedElement zIndex={this.props.miniMode ? 101 : 9}persistKey={this.persistKey}>
toger5 marked this conversation as resolved.
Show resolved Hide resolved
{ appTileBody }
</PersistedElement>
</div>;
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
94 changes: 31 additions & 63 deletions src/components/views/elements/PersistentApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,110 +16,78 @@ 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";

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

interface IState {
roomId: string;
persistentWidgetId: string;
}

@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(),
};
}

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

public componentWillUnmount(): void {
if (this.roomStoreToken) {
this.roomStoreToken.remove();
}
ActiveWidgetStore.instance.removeListener(ActiveWidgetStoreEvent.Update, this.onActiveWidgetStoreUpdate);
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 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 {
if (this.state.persistentWidgetId) {
const persistentWidgetInRoomId = ActiveWidgetStore.instance.getRoomId(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 myMembership = persistentWidgetInRoom.getMyMembership();
if (this.state.roomId !== persistentWidgetInRoomId && myMembership === "join") {
// 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
15 changes: 10 additions & 5 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 @@ -134,19 +135,20 @@ 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);

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 @@ -196,22 +198,25 @@ 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();
break;
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
Loading