Implement small broadcast PiP (#9755)
This commit is contained in:
parent
9f795a4c5f
commit
ab560bba40
21 changed files with 938 additions and 74 deletions
|
@ -45,6 +45,7 @@ import {
|
|||
VoiceBroadcastPreRecordingPip,
|
||||
VoiceBroadcastRecording,
|
||||
VoiceBroadcastRecordingPip,
|
||||
VoiceBroadcastSmallPlaybackBody,
|
||||
} from "../../../voice-broadcast";
|
||||
import { useCurrentVoiceBroadcastPlayback } from "../../../voice-broadcast/hooks/useCurrentVoiceBroadcastPlayback";
|
||||
|
||||
|
@ -335,9 +336,17 @@ class PipView extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
private createVoiceBroadcastPlaybackPipContent(voiceBroadcastPlayback: VoiceBroadcastPlayback): CreatePipChildren {
|
||||
if (this.state.viewedRoomId === voiceBroadcastPlayback.infoEvent.getRoomId()) {
|
||||
return ({ onStartMoving }) => (
|
||||
<div onMouseDown={onStartMoving}>
|
||||
<VoiceBroadcastPlaybackBody playback={voiceBroadcastPlayback} pip={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return ({ onStartMoving }) => (
|
||||
<div onMouseDown={onStartMoving}>
|
||||
<VoiceBroadcastPlaybackBody playback={voiceBroadcastPlayback} pip={true} />
|
||||
<VoiceBroadcastSmallPlaybackBody playback={voiceBroadcastPlayback} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -653,16 +653,16 @@
|
|||
"Stop live broadcasting?": "Stop live broadcasting?",
|
||||
"Are you sure you want to stop your live broadcast?This will end the broadcast and the full recording will be available in the room.": "Are you sure you want to stop your live broadcast?This will end the broadcast and the full recording will be available in the room.",
|
||||
"Yes, stop broadcast": "Yes, stop broadcast",
|
||||
"play voice broadcast": "play voice broadcast",
|
||||
"resume voice broadcast": "resume voice broadcast",
|
||||
"pause voice broadcast": "pause voice broadcast",
|
||||
"30s backward": "30s backward",
|
||||
"30s forward": "30s forward",
|
||||
"Go live": "Go live",
|
||||
"resume voice broadcast": "resume voice broadcast",
|
||||
"pause voice broadcast": "pause voice broadcast",
|
||||
"Change input device": "Change input device",
|
||||
"Live": "Live",
|
||||
"Voice broadcast": "Voice broadcast",
|
||||
"Buffering…": "Buffering…",
|
||||
"play voice broadcast": "play voice broadcast",
|
||||
"Cannot reach homeserver": "Cannot reach homeserver",
|
||||
"Ensure you have a stable internet connection, or get in touch with the server admin": "Ensure you have a stable internet connection, or get in touch with the server admin",
|
||||
"Your %(brand)s is misconfigured": "Your %(brand)s is misconfigured",
|
||||
|
|
|
@ -34,12 +34,14 @@ import AccessibleTooltipButton from "../../../components/views/elements/Accessib
|
|||
interface VoiceBroadcastHeaderProps {
|
||||
linkToRoom?: boolean;
|
||||
live?: VoiceBroadcastLiveness;
|
||||
liveBadgePosition?: "middle" | "right";
|
||||
onCloseClick?: () => void;
|
||||
onMicrophoneLineClick?: ((e: ButtonEvent) => void | Promise<void>) | null;
|
||||
room: Room;
|
||||
microphoneLabel?: string;
|
||||
showBroadcast?: boolean;
|
||||
showBuffering?: boolean;
|
||||
bufferingPosition?: "line" | "title";
|
||||
timeLeft?: number;
|
||||
showClose?: boolean;
|
||||
}
|
||||
|
@ -47,12 +49,14 @@ interface VoiceBroadcastHeaderProps {
|
|||
export const VoiceBroadcastHeader: React.FC<VoiceBroadcastHeaderProps> = ({
|
||||
linkToRoom = false,
|
||||
live = "not-live",
|
||||
liveBadgePosition = "right",
|
||||
onCloseClick = () => {},
|
||||
onMicrophoneLineClick = null,
|
||||
room,
|
||||
microphoneLabel,
|
||||
showBroadcast = false,
|
||||
showBuffering = false,
|
||||
bufferingPosition = "line",
|
||||
showClose = false,
|
||||
timeLeft,
|
||||
}) => {
|
||||
|
@ -78,7 +82,7 @@ export const VoiceBroadcastHeader: React.FC<VoiceBroadcastHeaderProps> = ({
|
|||
</div>
|
||||
);
|
||||
|
||||
const buffering = showBuffering && (
|
||||
const bufferingLine = showBuffering && bufferingPosition === "line" && (
|
||||
<div className="mx_VoiceBroadcastHeader_line">
|
||||
<Spinner w={14} h={14} />
|
||||
{_t("Buffering…")}
|
||||
|
@ -110,7 +114,12 @@ export const VoiceBroadcastHeader: React.FC<VoiceBroadcastHeaderProps> = ({
|
|||
};
|
||||
|
||||
let roomAvatar = <RoomAvatar room={room} width={32} height={32} />;
|
||||
let roomName = <div className="mx_VoiceBroadcastHeader_room">{room.name}</div>;
|
||||
let roomName = (
|
||||
<div className="mx_VoiceBroadcastHeader_room_wrapper">
|
||||
<div className="mx_VoiceBroadcastHeader_room">{room.name}</div>
|
||||
{showBuffering && bufferingPosition === "title" && <Spinner w={12} h={12} />}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (linkToRoom) {
|
||||
roomAvatar = <AccessibleButton onClick={onRoomAvatarOrNameClick}>{roomAvatar}</AccessibleButton>;
|
||||
|
@ -126,9 +135,10 @@ export const VoiceBroadcastHeader: React.FC<VoiceBroadcastHeaderProps> = ({
|
|||
{microphoneLine}
|
||||
{timeLeftLine}
|
||||
{broadcast}
|
||||
{buffering}
|
||||
{bufferingLine}
|
||||
{liveBadgePosition === "middle" && liveBadge}
|
||||
</div>
|
||||
{liveBadge}
|
||||
{liveBadgePosition === "right" && liveBadge}
|
||||
{closeButton}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { Icon as PlayIcon } from "../../../../res/img/element-icons/play.svg";
|
||||
import { Icon as PauseIcon } from "../../../../res/img/element-icons/pause.svg";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { VoiceBroadcastControl, VoiceBroadcastPlaybackState } from "../..";
|
||||
|
||||
interface Props {
|
||||
onClick: () => void;
|
||||
state: VoiceBroadcastPlaybackState;
|
||||
}
|
||||
|
||||
export const VoiceBroadcastPlaybackControl: React.FC<Props> = ({ onClick, state }) => {
|
||||
let controlIcon: React.FC<React.SVGProps<SVGSVGElement>>;
|
||||
let controlLabel: string;
|
||||
let className = "";
|
||||
|
||||
switch (state) {
|
||||
case VoiceBroadcastPlaybackState.Stopped:
|
||||
controlIcon = PlayIcon;
|
||||
className = "mx_VoiceBroadcastControl-play";
|
||||
controlLabel = _t("play voice broadcast");
|
||||
break;
|
||||
case VoiceBroadcastPlaybackState.Paused:
|
||||
controlIcon = PlayIcon;
|
||||
className = "mx_VoiceBroadcastControl-play";
|
||||
controlLabel = _t("resume voice broadcast");
|
||||
break;
|
||||
case VoiceBroadcastPlaybackState.Buffering:
|
||||
case VoiceBroadcastPlaybackState.Playing:
|
||||
controlIcon = PauseIcon;
|
||||
controlLabel = _t("pause voice broadcast");
|
||||
break;
|
||||
}
|
||||
|
||||
return <VoiceBroadcastControl className={className} label={controlLabel} icon={controlIcon} onClick={onClick} />;
|
||||
};
|
|
@ -18,14 +18,12 @@ import React, { ReactElement } from "react";
|
|||
import classNames from "classnames";
|
||||
|
||||
import {
|
||||
VoiceBroadcastControl,
|
||||
VoiceBroadcastHeader,
|
||||
VoiceBroadcastPlayback,
|
||||
VoiceBroadcastPlaybackControl,
|
||||
VoiceBroadcastPlaybackState,
|
||||
} from "../..";
|
||||
import { useVoiceBroadcastPlayback } from "../../hooks/useVoiceBroadcastPlayback";
|
||||
import { Icon as PlayIcon } from "../../../../res/img/element-icons/play.svg";
|
||||
import { Icon as PauseIcon } from "../../../../res/img/element-icons/pause.svg";
|
||||
import { Icon as Back30sIcon } from "../../../../res/img/element-icons/Back30s.svg";
|
||||
import { Icon as Forward30sIcon } from "../../../../res/img/element-icons/Forward30s.svg";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
@ -43,32 +41,6 @@ interface VoiceBroadcastPlaybackBodyProps {
|
|||
export const VoiceBroadcastPlaybackBody: React.FC<VoiceBroadcastPlaybackBodyProps> = ({ pip = false, playback }) => {
|
||||
const { times, liveness, playbackState, room, sender, toggle } = useVoiceBroadcastPlayback(playback);
|
||||
|
||||
let controlIcon: React.FC<React.SVGProps<SVGSVGElement>>;
|
||||
let controlLabel: string;
|
||||
let className = "";
|
||||
|
||||
switch (playbackState) {
|
||||
case VoiceBroadcastPlaybackState.Stopped:
|
||||
controlIcon = PlayIcon;
|
||||
className = "mx_VoiceBroadcastControl-play";
|
||||
controlLabel = _t("play voice broadcast");
|
||||
break;
|
||||
case VoiceBroadcastPlaybackState.Paused:
|
||||
controlIcon = PlayIcon;
|
||||
className = "mx_VoiceBroadcastControl-play";
|
||||
controlLabel = _t("resume voice broadcast");
|
||||
break;
|
||||
case VoiceBroadcastPlaybackState.Buffering:
|
||||
case VoiceBroadcastPlaybackState.Playing:
|
||||
controlIcon = PauseIcon;
|
||||
controlLabel = _t("pause voice broadcast");
|
||||
break;
|
||||
}
|
||||
|
||||
const control = (
|
||||
<VoiceBroadcastControl className={className} label={controlLabel} icon={controlIcon} onClick={toggle} />
|
||||
);
|
||||
|
||||
let seekBackwardButton: ReactElement | null = null;
|
||||
let seekForwardButton: ReactElement | null = null;
|
||||
|
||||
|
@ -107,7 +79,7 @@ export const VoiceBroadcastPlaybackBody: React.FC<VoiceBroadcastPlaybackBodyProp
|
|||
/>
|
||||
<div className="mx_VoiceBroadcastBody_controls">
|
||||
{seekBackwardButton}
|
||||
{control}
|
||||
<VoiceBroadcastPlaybackControl state={playbackState} onClick={toggle} />
|
||||
{seekForwardButton}
|
||||
</div>
|
||||
<SeekBar playback={playback} />
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
VoiceBroadcastHeader,
|
||||
VoiceBroadcastPlayback,
|
||||
VoiceBroadcastPlaybackControl,
|
||||
VoiceBroadcastPlaybackState,
|
||||
} from "../..";
|
||||
import AccessibleButton from "../../../components/views/elements/AccessibleButton";
|
||||
import { useVoiceBroadcastPlayback } from "../../hooks/useVoiceBroadcastPlayback";
|
||||
import { Icon as XIcon } from "../../../../res/img/element-icons/cancel-rounded.svg";
|
||||
|
||||
interface VoiceBroadcastSmallPlaybackBodyProps {
|
||||
playback: VoiceBroadcastPlayback;
|
||||
}
|
||||
|
||||
export const VoiceBroadcastSmallPlaybackBody: React.FC<VoiceBroadcastSmallPlaybackBodyProps> = ({ playback }) => {
|
||||
const { liveness, playbackState, room, sender, toggle } = useVoiceBroadcastPlayback(playback);
|
||||
return (
|
||||
<div className="mx_VoiceBroadcastBody mx_VoiceBroadcastBody--pip mx_VoiceBroadcastBody--small">
|
||||
<VoiceBroadcastHeader
|
||||
linkToRoom={true}
|
||||
live={liveness}
|
||||
liveBadgePosition="middle"
|
||||
microphoneLabel={sender?.name}
|
||||
room={room}
|
||||
showBuffering={playbackState === VoiceBroadcastPlaybackState.Buffering}
|
||||
bufferingPosition="title"
|
||||
/>
|
||||
<VoiceBroadcastPlaybackControl state={playbackState} onClick={toggle} />
|
||||
<AccessibleButton onClick={() => playback.stop()}>
|
||||
<XIcon className="mx_Icon mx_Icon_8 mx_VoiceBroadcastBody__small-close" />
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -29,8 +29,10 @@ export * from "./components/VoiceBroadcastBody";
|
|||
export * from "./components/atoms/LiveBadge";
|
||||
export * from "./components/atoms/VoiceBroadcastControl";
|
||||
export * from "./components/atoms/VoiceBroadcastHeader";
|
||||
export * from "./components/atoms/VoiceBroadcastPlaybackControl";
|
||||
export * from "./components/atoms/VoiceBroadcastRoomSubtitle";
|
||||
export * from "./components/molecules/VoiceBroadcastPlaybackBody";
|
||||
export * from "./components/molecules/VoiceBroadcastSmallPlaybackBody";
|
||||
export * from "./components/molecules/VoiceBroadcastPreRecordingPip";
|
||||
export * from "./components/molecules/VoiceBroadcastRecordingBody";
|
||||
export * from "./components/molecules/VoiceBroadcastRecordingPip";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue