Implement small broadcast PiP (#9755)

This commit is contained in:
Michael Weimann 2022-12-15 12:43:01 +01:00 committed by GitHub
parent 9f795a4c5f
commit ab560bba40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 938 additions and 74 deletions

View file

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

View file

@ -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",

View file

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

View file

@ -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} />;
};

View file

@ -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} />

View file

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

View file

@ -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";