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

[Backport staging] Update Voice Broadcast buffering style #9660

Merged
merged 1 commit into from
Dec 1, 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
5 changes: 3 additions & 2 deletions res/css/voice-broadcast/atoms/_VoiceBroadcastHeader.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ limitations under the License.
display: flex;
gap: $spacing-4;

i {
flex-shrink: 0;
.mx_Spinner {
flex: 0 0 14px;
padding: 1px;
}

span {
Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@
"Change input device": "Change input device",
"Live": "Live",
"Voice broadcast": "Voice broadcast",
"Buffering…": "Buffering…",
"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",
Expand Down
41 changes: 26 additions & 15 deletions src/voice-broadcast/components/atoms/VoiceBroadcastHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import AccessibleButton from "../../../components/views/elements/AccessibleButto
import { Icon as XIcon } from "../../../../res/img/element-icons/cancel-rounded.svg";
import Clock from "../../../components/views/audio_messages/Clock";
import { formatTimeLeft } from "../../../DateUtils";
import Spinner from "../../../components/views/elements/Spinner";

interface VoiceBroadcastHeaderProps {
live?: VoiceBroadcastLiveness;
Expand All @@ -33,6 +34,7 @@ interface VoiceBroadcastHeaderProps {
room: Room;
microphoneLabel?: string;
showBroadcast?: boolean;
showBuffering?: boolean;
timeLeft?: number;
showClose?: boolean;
}
Expand All @@ -44,47 +46,55 @@ export const VoiceBroadcastHeader: React.FC<VoiceBroadcastHeaderProps> = ({
room,
microphoneLabel,
showBroadcast = false,
showBuffering = false,
showClose = false,
timeLeft,
}) => {
const broadcast = showBroadcast
? <div className="mx_VoiceBroadcastHeader_line">
const broadcast = showBroadcast && (
<div className="mx_VoiceBroadcastHeader_line">
<LiveIcon className="mx_Icon mx_Icon_16" />
{ _t("Voice broadcast") }
</div>
: null;
);

const liveBadge = live === "not-live"
? null
: <LiveBadge grey={live === "grey"} />;
const liveBadge = live !== "not-live" && (
<LiveBadge grey={live === "grey"} />
);

const closeButton = showClose
? <AccessibleButton onClick={onCloseClick}>
const closeButton = showClose && (
<AccessibleButton onClick={onCloseClick}>
<XIcon className="mx_Icon mx_Icon_16" />
</AccessibleButton>
: null;
);

const timeLeftLine = timeLeft
? <div className="mx_VoiceBroadcastHeader_line">
const timeLeftLine = timeLeft && (
<div className="mx_VoiceBroadcastHeader_line">
<TimerIcon className="mx_Icon mx_Icon_16" />
<Clock formatFn={formatTimeLeft} seconds={timeLeft} />
</div>
: null;
);

const buffering = showBuffering && (
<div className="mx_VoiceBroadcastHeader_line">
<Spinner w={14} h={14} />
{ _t("Buffering…") }
</div>
);

const microphoneLineClasses = classNames({
mx_VoiceBroadcastHeader_line: true,
["mx_VoiceBroadcastHeader_mic--clickable"]: onMicrophoneLineClick,
});

const microphoneLine = microphoneLabel
? <div
const microphoneLine = microphoneLabel && (
<div
className={microphoneLineClasses}
onClick={onMicrophoneLineClick}
>
<MicrophoneIcon className="mx_Icon mx_Icon_16" />
<span>{ microphoneLabel }</span>
</div>
: null;
);

return <div className="mx_VoiceBroadcastHeader">
<RoomAvatar room={room} width={32} height={32} />
Expand All @@ -95,6 +105,7 @@ export const VoiceBroadcastHeader: React.FC<VoiceBroadcastHeaderProps> = ({
{ microphoneLine }
{ timeLeftLine }
{ broadcast }
{ buffering }
</div>
{ liveBadge }
{ closeButton }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
VoiceBroadcastPlayback,
VoiceBroadcastPlaybackState,
} from "../..";
import Spinner from "../../../components/views/elements/Spinner";
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";
Expand Down Expand Up @@ -55,40 +54,35 @@ export const VoiceBroadcastPlaybackBody: React.FC<VoiceBroadcastPlaybackBodyProp
toggle,
} = useVoiceBroadcastPlayback(playback);

let control: React.ReactNode;

if (playbackState === VoiceBroadcastPlaybackState.Buffering) {
control = <Spinner />;
} else {
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.Playing:
controlIcon = PauseIcon;
controlLabel = _t("pause voice broadcast");
break;
}

control = <VoiceBroadcastControl
className={className}
label={controlLabel}
icon={controlIcon}
onClick={toggle}
/>;
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;

Expand Down Expand Up @@ -125,7 +119,8 @@ export const VoiceBroadcastPlaybackBody: React.FC<VoiceBroadcastPlaybackBodyProp
live={liveness}
microphoneLabel={sender?.name}
room={room}
showBroadcast={true}
showBroadcast={playbackState !== VoiceBroadcastPlaybackState.Buffering}
showBuffering={playbackState === VoiceBroadcastPlaybackState.Buffering}
/>
<div className="mx_VoiceBroadcastBody_controls">
{ seekBackwardButton }
Expand Down
7 changes: 7 additions & 0 deletions src/voice-broadcast/hooks/useVoiceBroadcastPlayback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ import {
export const useVoiceBroadcastPlayback = (playback: VoiceBroadcastPlayback) => {
const client = MatrixClientPeg.get();
const room = client.getRoom(playback.infoEvent.getRoomId());

if (!room) {
throw new Error(
`Voice Broadcast room not found (event ${playback.infoEvent.getId()})`,
);
}

const playbackToggle = () => {
playback.toggle();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ describe("VoiceBroadcastHeader", () => {
const sender = new RoomMember(roomId, userId);
let container: Container;

const renderHeader = (live: VoiceBroadcastLiveness, showBroadcast: boolean = undefined): RenderResult => {
const renderHeader = (
live: VoiceBroadcastLiveness,
showBroadcast?: boolean,
buffering?: boolean,
): RenderResult => {
return render(<VoiceBroadcastHeader
live={live}
microphoneLabel={sender.name}
room={room}
showBroadcast={showBroadcast}
showBuffering={buffering}
/>);
};

Expand All @@ -51,6 +56,16 @@ describe("VoiceBroadcastHeader", () => {
});

describe("when rendering a live broadcast header with broadcast info", () => {
beforeEach(() => {
container = renderHeader("live", true, true).container;
});

it("should render the header with a red live badge", () => {
expect(container).toMatchSnapshot();
});
});

describe("when rendering a buffering live broadcast header with broadcast info", () => {
beforeEach(() => {
container = renderHeader("live", true).container;
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`VoiceBroadcastHeader when rendering a buffering live broadcast header with broadcast info should render the header with a red live badge 1`] = `
<div>
<div
class="mx_VoiceBroadcastHeader"
>
<div
data-testid="room-avatar"
>
room avatar:
!room:example.com
</div>
<div
class="mx_VoiceBroadcastHeader_content"
>
<div
class="mx_VoiceBroadcastHeader_room"
>
!room:example.com
</div>
<div
class="mx_VoiceBroadcastHeader_line"
>
<div
class="mx_Icon mx_Icon_16"
/>
<span>
test user
</span>
</div>
<div
class="mx_VoiceBroadcastHeader_line"
>
<div
class="mx_Icon mx_Icon_16"
/>
Voice broadcast
</div>
</div>
<div
class="mx_LiveBadge"
>
<div
class="mx_Icon mx_Icon_16"
/>
Live
</div>
</div>
</div>
`;

exports[`VoiceBroadcastHeader when rendering a live (grey) broadcast header with broadcast info should render the header with a grey live badge 1`] = `
<div>
<div
Expand Down Expand Up @@ -87,6 +137,22 @@ exports[`VoiceBroadcastHeader when rendering a live broadcast header with broadc
/>
Voice broadcast
</div>
<div
class="mx_VoiceBroadcastHeader_line"
>
<div
class="mx_Spinner"
>
<div
aria-label="Loading..."
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 14px; height: 14px;"
/>
</div>
Buffering…
</div>
</div>
<div
class="mx_LiveBadge"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,17 @@ exports[`VoiceBroadcastPlaybackBody when rendering a buffering voice broadcast s
class="mx_VoiceBroadcastHeader_line"
>
<div
class="mx_Icon mx_Icon_16"
/>
Voice broadcast
class="mx_Spinner"
>
<div
aria-label="Loading..."
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 14px; height: 14px;"
/>
</div>
Buffering…
</div>
</div>
<div
Expand All @@ -270,14 +278,13 @@ exports[`VoiceBroadcastPlaybackBody when rendering a buffering voice broadcast s
/>
</div>
<div
class="mx_Spinner"
aria-label="pause voice broadcast"
class="mx_AccessibleButton mx_VoiceBroadcastControl"
role="button"
tabindex="0"
>
<div
aria-label="Loading..."
class="mx_Spinner_icon"
data-testid="spinner"
role="progressbar"
style="width: 32px; height: 32px;"
class="mx_Icon mx_Icon_16"
/>
</div>
<div
Expand Down