Skip to content

Commit

Permalink
fix: webinar speaker mode update (#136)
Browse files Browse the repository at this point in the history
* refactor: rename component and style names

* fix: hidden participants are still rendered as audio tag

* refactor: wrap the calculation logic into 1 usememo
  • Loading branch information
faiq-naufal authored Feb 1, 2024
1 parent 7440c06 commit be12e7b
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 121 deletions.
74 changes: 0 additions & 74 deletions app/_features/room/components/conference-speaker-layout.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion app/_features/room/components/conference.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { usePeerContext } from '@/_features/room/contexts/peer-context';
import MeetingOneOnOneLayout from './meeting-one-on-one-layout';
import MeetingGalleryLayout from './meeting-gallery-layout';
import MeetingPresentationLayout from './meeting-presentation-layout';
import WebinarSpeakerLayout from './conference-speaker-layout';
import WebinarSpeakerLayout from './webinar-speaker-layout';
import WebinarPresentationLayout from './webinar-presentation-layout';
import PlugConnectedFillIcon from '@/_shared/components/icons/plug-connected-fill-icon';
import PlugDisconnectedFillIcon from '@/_shared/components/icons/plug-disconnected-fill-icon';
Expand Down
20 changes: 13 additions & 7 deletions app/_features/room/components/meeting-gallery-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

import { useMemo } from 'react';
import { type ParticipantStream } from '@/_features/room/contexts/participant-context';
import '../styles/meeting-gallery-layout.css';
import ConferenceScreen from './conference-screen';
Expand All @@ -12,13 +13,18 @@ export default function MeetingGalleryLayout({
}) {
const MAX_VISIBLE_PARTICIPANTS = 49;
const moreThanMax = streams.length > MAX_VISIBLE_PARTICIPANTS;
const visibleParticipants = streams.slice(
0,
moreThanMax ? MAX_VISIBLE_PARTICIPANTS - 1 : MAX_VISIBLE_PARTICIPANTS
);
const hiddenParticipants = streams.slice(
moreThanMax ? MAX_VISIBLE_PARTICIPANTS - 1 : MAX_VISIBLE_PARTICIPANTS
);

const { visibleParticipants, hiddenParticipants } = useMemo(() => {
const visibleParticipants = streams.slice(
0,
moreThanMax ? MAX_VISIBLE_PARTICIPANTS - 1 : MAX_VISIBLE_PARTICIPANTS
);
const hiddenParticipants = streams.slice(
moreThanMax ? MAX_VISIBLE_PARTICIPANTS - 1 : MAX_VISIBLE_PARTICIPANTS
);

return { visibleParticipants, hiddenParticipants };
}, [streams, moreThanMax]);

const maxColumns = Math.ceil(Math.sqrt(visibleParticipants.length));

Expand Down
28 changes: 15 additions & 13 deletions app/_features/room/components/meeting-presentation-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export default function MeetingPresentationLayout({
}) {
const MAX_VISIBLE_PARTICIPANTS = 6;

const { screens, medias } = useMemo(() => {
return streams.reduce(
const { spotlightScreen, visibleStreams, hiddenStreams } = useMemo(() => {
const { screens, medias } = streams.reduce(
(accumulator, currentValue) => {
if (currentValue.source === 'screen') {
return {
Expand All @@ -30,20 +30,22 @@ export default function MeetingPresentationLayout({
},
{ screens: [] as ParticipantStream[], medias: [] as ParticipantStream[] }
);
}, [streams]);

const spotlightScreen = screens.pop();
const visibleScreens = screens.slice(0, MAX_VISIBLE_PARTICIPANTS);
const inVisibleScreens = screens.slice(MAX_VISIBLE_PARTICIPANTS);
const spotlightScreen = screens.pop();
const visibleScreens = screens.slice(0, MAX_VISIBLE_PARTICIPANTS);
const inVisibleScreens = screens.slice(MAX_VISIBLE_PARTICIPANTS);

const visibleParticipants =
visibleScreens.length < MAX_VISIBLE_PARTICIPANTS
? medias.slice(0, MAX_VISIBLE_PARTICIPANTS - visibleScreens.length)
: [];
const invisibleParticipants = medias.slice(visibleParticipants.length);

const visibleParticipants =
visibleScreens.length < MAX_VISIBLE_PARTICIPANTS
? medias.slice(0, MAX_VISIBLE_PARTICIPANTS - visibleScreens.length)
: [];
const invisibleParticipants = medias.slice(visibleParticipants.length);
const visibleStreams = [...visibleScreens, ...visibleParticipants];
const hiddenStreams = [...inVisibleScreens, ...invisibleParticipants];

const visibleStreams = [...visibleScreens, ...visibleParticipants];
const hiddenStreams = [...inVisibleScreens, ...invisibleParticipants];
return { spotlightScreen, visibleStreams, hiddenStreams };
}, [streams]);

const maxColumns = Math.ceil(Math.sqrt(visibleStreams.length));

Expand Down
52 changes: 26 additions & 26 deletions app/_features/room/components/webinar-presentation-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ export default function WebinarPresentationLayout({
const { moderatorClientIDs, speakerClientIDs } = useMetadataContext();
const MAX_VISIBLE_PARTICIPANTS = 6;

const { speakers, participants } = useMemo(() => {
return streams.reduce(
const { spotlightScreen, visibleStreams, hiddenStreams } = useMemo(() => {
const { speakers, participants } = streams.reduce(
(accumulator, currentStream) => {
if (
moderatorClientIDs.includes(currentStream.clientId) ||
Expand All @@ -38,10 +38,8 @@ export default function WebinarPresentationLayout({
participants: [] as ParticipantStream[],
}
);
}, [streams, moderatorClientIDs, speakerClientIDs]);

const { speakerMedias, speakerScreens } = useMemo(() => {
return speakers.reduce(
const { speakerMedias, speakerScreens } = speakers.reduce(
(accumulator, currentValue) => {
if (currentValue.source === 'screen') {
return {
Expand All @@ -60,31 +58,33 @@ export default function WebinarPresentationLayout({
speakerMedias: [] as ParticipantStream[],
}
);
}, [speakers]);

const spotlightScreen = speakerScreens.pop();
const visibleSpeakerScreens = speakerScreens.slice(
0,
MAX_VISIBLE_PARTICIPANTS
);
const hiddenSpeakerScreens = speakerScreens.slice(MAX_VISIBLE_PARTICIPANTS);
const spotlightScreen = speakerScreens.pop();
const visibleSpeakerScreens = speakerScreens.slice(
0,
MAX_VISIBLE_PARTICIPANTS
);
const hiddenSpeakerScreens = speakerScreens.slice(MAX_VISIBLE_PARTICIPANTS);

const visibleSpeakers =
visibleSpeakerScreens.length < MAX_VISIBLE_PARTICIPANTS
? speakerMedias.slice(
0,
MAX_VISIBLE_PARTICIPANTS - visibleSpeakerScreens.length
)
: [];
const visibleSpeakers =
visibleSpeakerScreens.length < MAX_VISIBLE_PARTICIPANTS
? speakerMedias.slice(
0,
MAX_VISIBLE_PARTICIPANTS - visibleSpeakerScreens.length
)
: [];

const hiddenSpeakers = speakerMedias.slice(visibleSpeakers.length);
const hiddenSpeakers = speakerMedias.slice(visibleSpeakers.length);

const visibleStreams = [...visibleSpeakerScreens, ...visibleSpeakers];
const hiddenStreams = [
...hiddenSpeakerScreens,
...hiddenSpeakers,
...participants,
];
const visibleStreams = [...visibleSpeakerScreens, ...visibleSpeakers];
const hiddenStreams = [
...hiddenSpeakerScreens,
...hiddenSpeakers,
...participants,
];

return { spotlightScreen, visibleStreams, hiddenStreams };
}, [streams, moderatorClientIDs, speakerClientIDs]);

const maxColumns = Math.ceil(Math.sqrt(visibleStreams.length));

Expand Down
113 changes: 113 additions & 0 deletions app/_features/room/components/webinar-speaker-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
'use client';

import { useMemo } from 'react';
import { type ParticipantStream } from '@/_features/room/contexts/participant-context';
import { useMetadataContext } from '@/_features/room/contexts/metadata-context';
import ConferenceScreen from '@/_features/room/components/conference-screen';
import ConferenceScreenHidden from '@/_features/room/components/conference-screen-hidden';
import '../styles/webinar-speaker-layout.css';

export default function WebinarSpeakerLayout({
streams,
}: {
streams: ParticipantStream[];
}) {
const MAX_VISIBLE_PARTICIPANTS = 20;
const { moderatorClientIDs, speakerClientIDs } = useMetadataContext();

const {
speakers,
visibleParticipants,
hiddenParticipants,
participantsMoreThanMax,
} = useMemo(() => {
const { speakers, participants } = streams.reduce(
(accumulator, currentStream) => {
if (
moderatorClientIDs.includes(currentStream.clientId) ||
speakerClientIDs.includes(currentStream.clientId)
) {
return {
...accumulator,
speakers: [...accumulator.speakers, currentStream],
};
} else {
return {
...accumulator,
participants: [...accumulator.participants, currentStream],
};
}
},
{
speakers: [] as ParticipantStream[],
participants: [] as ParticipantStream[],
}
);

const participantsMoreThanMax =
participants.length > MAX_VISIBLE_PARTICIPANTS;

const visibleParticipants = participants.slice(
0,
participantsMoreThanMax
? MAX_VISIBLE_PARTICIPANTS - 1
: MAX_VISIBLE_PARTICIPANTS
);

const hiddenParticipants = participants.slice(
participantsMoreThanMax
? MAX_VISIBLE_PARTICIPANTS - 1
: MAX_VISIBLE_PARTICIPANTS
);

return {
speakers,
visibleParticipants,
hiddenParticipants,
participantsMoreThanMax,
};
}, [streams, moderatorClientIDs, speakerClientIDs]);

return (
<div className="conference-layout speaker">
<div className="speaker-container">
{speakers.map((speaker) => {
return (
<div key={`speaker-${speaker.id}`} className="relative">
<ConferenceScreen stream={speaker} />
</div>
);
})}
</div>
<div className="participant-container">
<div className="participant-grid">
{visibleParticipants.map((stream) => {
return (
<div
key={`visible-stream-${stream.id}`}
className="participant-item relative"
>
<ConferenceScreen stream={stream} />
</div>
);
})}
{participantsMoreThanMax && (
<div className="participant-item relative">
<div className="flex h-full w-full items-center justify-center rounded-lg bg-zinc-700/70 p-2 text-sm font-medium shadow-lg">
More+
</div>
{hiddenParticipants.map((stream) => {
return (
<ConferenceScreenHidden
key={`hidden-stream-${stream.id}`}
stream={stream}
/>
);
})}
</div>
)}
</div>
</div>
</div>
);
}

0 comments on commit be12e7b

Please sign in to comment.