mirror of
https://github.com/vector-im/element-call.git
synced 2024-11-24 00:38:31 +08:00
Always deal with MediaItem at the LayoutMedia layer
That way we only convert to the view model when we do LayoutMedia => Layout
This commit is contained in:
parent
84e172a2ba
commit
cfea4bd50c
@ -91,37 +91,37 @@ const showFooterMs = 4000;
|
|||||||
|
|
||||||
export interface GridLayoutMedia {
|
export interface GridLayoutMedia {
|
||||||
type: "grid";
|
type: "grid";
|
||||||
spotlight?: MediaViewModel[];
|
spotlight?: MediaItem[];
|
||||||
grid: UserMediaViewModel[];
|
grid: UserMedia[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SpotlightLandscapeLayoutMedia {
|
export interface SpotlightLandscapeLayoutMedia {
|
||||||
type: "spotlight-landscape";
|
type: "spotlight-landscape";
|
||||||
spotlight: MediaViewModel[];
|
spotlight: MediaItem[];
|
||||||
grid: UserMediaViewModel[];
|
grid: UserMedia[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SpotlightPortraitLayoutMedia {
|
export interface SpotlightPortraitLayoutMedia {
|
||||||
type: "spotlight-portrait";
|
type: "spotlight-portrait";
|
||||||
spotlight: MediaViewModel[];
|
spotlight: MediaItem[];
|
||||||
grid: UserMediaViewModel[];
|
grid: UserMedia[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SpotlightExpandedLayoutMedia {
|
export interface SpotlightExpandedLayoutMedia {
|
||||||
type: "spotlight-expanded";
|
type: "spotlight-expanded";
|
||||||
spotlight: MediaViewModel[];
|
spotlight: MediaItem[];
|
||||||
pip?: UserMediaViewModel;
|
pip?: UserMedia;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OneOnOneLayoutMedia {
|
export interface OneOnOneLayoutMedia {
|
||||||
type: "one-on-one";
|
type: "one-on-one";
|
||||||
local: UserMediaViewModel;
|
local: UserMedia;
|
||||||
remote: UserMediaViewModel;
|
remote: UserMedia;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PipLayoutMedia {
|
export interface PipLayoutMedia {
|
||||||
type: "pip";
|
type: "pip";
|
||||||
spotlight: MediaViewModel[];
|
spotlight: MediaItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LayoutMedia =
|
export type LayoutMedia =
|
||||||
@ -478,9 +478,8 @@ export class CallViewModel extends ViewModel {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly localUserMedia: Observable<LocalUserMediaViewModel> =
|
private readonly localUserMedia: Observable<UserMedia> = this.userMedia.pipe(
|
||||||
this.mediaItems.pipe(
|
map((ms) => ms.find((m) => m.vm.local) as UserMedia),
|
||||||
map((ms) => ms.find((m) => m.vm.local)!.vm as LocalUserMediaViewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly screenShares: Observable<ScreenShare[]> =
|
private readonly screenShares: Observable<ScreenShare[]> =
|
||||||
@ -491,7 +490,7 @@ export class CallViewModel extends ViewModel {
|
|||||||
this.scope.state(),
|
this.scope.state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly spotlightSpeaker: Observable<UserMediaViewModel> =
|
private readonly spotlightSpeaker: Observable<UserMedia> =
|
||||||
this.userMedia.pipe(
|
this.userMedia.pipe(
|
||||||
switchMap((mediaItems) =>
|
switchMap((mediaItems) =>
|
||||||
mediaItems.length === 0
|
mediaItems.length === 0
|
||||||
@ -523,11 +522,10 @@ export class CallViewModel extends ViewModel {
|
|||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
),
|
),
|
||||||
map((speaker) => speaker.vm),
|
|
||||||
this.scope.state(),
|
this.scope.state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly grid: Observable<UserMediaViewModel[]> = this.userMedia.pipe(
|
private readonly grid: Observable<UserMedia[]> = this.userMedia.pipe(
|
||||||
switchMap((mediaItems) => {
|
switchMap((mediaItems) => {
|
||||||
const bins = mediaItems.map((m) =>
|
const bins = mediaItems.map((m) =>
|
||||||
combineLatest(
|
combineLatest(
|
||||||
@ -558,27 +556,27 @@ export class CallViewModel extends ViewModel {
|
|||||||
return bins.length === 0
|
return bins.length === 0
|
||||||
? of([])
|
? of([])
|
||||||
: combineLatest(bins, (...bins) =>
|
: combineLatest(bins, (...bins) =>
|
||||||
bins.sort(([, bin1], [, bin2]) => bin1 - bin2).map(([m]) => m.vm),
|
bins.sort(([, bin1], [, bin2]) => bin1 - bin2).map(([m]) => m),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly spotlightAndPip: Observable<
|
private readonly spotlightAndPip: Observable<
|
||||||
[Observable<MediaViewModel[]>, Observable<UserMediaViewModel | null>]
|
[Observable<MediaItem[]>, Observable<UserMedia | null>]
|
||||||
> = this.screenShares.pipe(
|
> = this.screenShares.pipe(
|
||||||
map((screenShares) =>
|
map((screenShares) =>
|
||||||
screenShares.length > 0
|
screenShares.length > 0
|
||||||
? ([of(screenShares.map((m) => m.vm)), this.spotlightSpeaker] as const)
|
? ([of(screenShares.map((m) => m)), this.spotlightSpeaker] as const)
|
||||||
: ([
|
: ([
|
||||||
this.spotlightSpeaker.pipe(map((speaker) => [speaker!])),
|
this.spotlightSpeaker.pipe(map((speaker) => [speaker!])),
|
||||||
this.spotlightSpeaker.pipe(
|
this.spotlightSpeaker.pipe(
|
||||||
switchMap((speaker) =>
|
switchMap((speaker) =>
|
||||||
speaker.local
|
speaker.vm.local
|
||||||
? of(null)
|
? of(null)
|
||||||
: this.localUserMedia.pipe(
|
: this.localUserMedia.pipe(
|
||||||
switchMap((vm) =>
|
switchMap((lm) =>
|
||||||
vm.alwaysShow.pipe(
|
(lm.vm as LocalUserMediaViewModel).alwaysShow.pipe(
|
||||||
map((alwaysShow) => (alwaysShow ? vm : null)),
|
map((alwaysShow) => (alwaysShow ? lm : null)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -588,7 +586,7 @@ export class CallViewModel extends ViewModel {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly spotlight: Observable<MediaViewModel[]> =
|
private readonly spotlight: Observable<MediaItem[]> =
|
||||||
this.spotlightAndPip.pipe(
|
this.spotlightAndPip.pipe(
|
||||||
switchMap(([spotlight]) => spotlight),
|
switchMap(([spotlight]) => spotlight),
|
||||||
this.scope.state(),
|
this.scope.state(),
|
||||||
@ -597,12 +595,14 @@ export class CallViewModel extends ViewModel {
|
|||||||
private readonly hasRemoteScreenShares: Observable<boolean> =
|
private readonly hasRemoteScreenShares: Observable<boolean> =
|
||||||
this.spotlight.pipe(
|
this.spotlight.pipe(
|
||||||
map((spotlight) =>
|
map((spotlight) =>
|
||||||
spotlight.some((vm) => !vm.local && vm instanceof ScreenShareViewModel),
|
spotlight.some(
|
||||||
|
(m) => !m.vm.local && m.vm instanceof ScreenShareViewModel,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
distinctUntilChanged(),
|
distinctUntilChanged(),
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly pip: Observable<UserMediaViewModel | null> =
|
private readonly pip: Observable<UserMedia | null> =
|
||||||
this.spotlightAndPip.pipe(switchMap(([, pip]) => pip));
|
this.spotlightAndPip.pipe(switchMap(([, pip]) => pip));
|
||||||
|
|
||||||
private readonly pipEnabled: Observable<boolean> = setPipEnabled.pipe(
|
private readonly pipEnabled: Observable<boolean> = setPipEnabled.pipe(
|
||||||
@ -676,7 +676,7 @@ export class CallViewModel extends ViewModel {
|
|||||||
[this.grid, this.spotlight],
|
[this.grid, this.spotlight],
|
||||||
(grid, spotlight) => ({
|
(grid, spotlight) => ({
|
||||||
type: "grid",
|
type: "grid",
|
||||||
spotlight: spotlight.some((vm) => vm instanceof ScreenShareViewModel)
|
spotlight: spotlight.some((m) => m.vm instanceof ScreenShareViewModel)
|
||||||
? spotlight
|
? spotlight
|
||||||
: undefined,
|
: undefined,
|
||||||
grid,
|
grid,
|
||||||
@ -708,15 +708,16 @@ export class CallViewModel extends ViewModel {
|
|||||||
this.mediaItems.pipe(
|
this.mediaItems.pipe(
|
||||||
map((mediaItems) => {
|
map((mediaItems) => {
|
||||||
if (mediaItems.length !== 2) return null;
|
if (mediaItems.length !== 2) return null;
|
||||||
const local = mediaItems.find((vm) => vm.vm.local)!
|
const local = mediaItems.find(
|
||||||
.vm as LocalUserMediaViewModel;
|
(m) => m instanceof UserMedia && m.vm.local,
|
||||||
const remote = mediaItems.find((vm) => !vm.vm.local)?.vm as
|
) as UserMedia | undefined;
|
||||||
| RemoteUserMediaViewModel
|
const remote = mediaItems.find(
|
||||||
| undefined;
|
(m) => m instanceof UserMedia && !m.vm.local,
|
||||||
|
) as UserMedia | undefined;
|
||||||
// There might not be a remote tile if there are screen shares, or if
|
// There might not be a remote tile if there are screen shares, or if
|
||||||
// only the local user is in the call and they're using the duplicate
|
// only the local user is in the call and they're using the duplicate
|
||||||
// tiles option
|
// tiles option
|
||||||
if (remote === undefined) return null;
|
if (!local || !remote) return null;
|
||||||
|
|
||||||
return { type: "one-on-one", local, remote };
|
return { type: "one-on-one", local, remote };
|
||||||
}),
|
}),
|
||||||
|
@ -26,10 +26,10 @@ export function gridLikeLayout(
|
|||||||
const update = prevTiles.from(visibleTiles);
|
const update = prevTiles.from(visibleTiles);
|
||||||
if (media.spotlight !== undefined)
|
if (media.spotlight !== undefined)
|
||||||
update.registerSpotlight(
|
update.registerSpotlight(
|
||||||
media.spotlight,
|
media.spotlight.map((m) => m.vm),
|
||||||
media.type === "spotlight-portrait",
|
media.type === "spotlight-portrait",
|
||||||
);
|
);
|
||||||
for (const mediaVm of media.grid) update.registerGridTile(mediaVm);
|
for (const mediaVm of media.grid) update.registerGridTile(mediaVm.vm);
|
||||||
const tiles = update.build();
|
const tiles = update.build();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -18,14 +18,14 @@ export function oneOnOneLayout(
|
|||||||
prevTiles: TileStore,
|
prevTiles: TileStore,
|
||||||
): [OneOnOneLayout, TileStore] {
|
): [OneOnOneLayout, TileStore] {
|
||||||
const update = prevTiles.from(visibleTiles);
|
const update = prevTiles.from(visibleTiles);
|
||||||
update.registerGridTile(media.local);
|
update.registerGridTile(media.local.vm);
|
||||||
update.registerGridTile(media.remote);
|
update.registerGridTile(media.remote.vm);
|
||||||
const tiles = update.build();
|
const tiles = update.build();
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: media.type,
|
type: media.type,
|
||||||
local: tiles.gridTilesByMedia.get(media.local)!,
|
local: tiles.gridTilesByMedia.get(media.local.vm)!,
|
||||||
remote: tiles.gridTilesByMedia.get(media.remote)!,
|
remote: tiles.gridTilesByMedia.get(media.remote.vm)!,
|
||||||
},
|
},
|
||||||
tiles,
|
tiles,
|
||||||
];
|
];
|
||||||
|
@ -18,7 +18,10 @@ export function pipLayout(
|
|||||||
prevTiles: TileStore,
|
prevTiles: TileStore,
|
||||||
): [PipLayout, TileStore] {
|
): [PipLayout, TileStore] {
|
||||||
const update = prevTiles.from(visibleTiles);
|
const update = prevTiles.from(visibleTiles);
|
||||||
update.registerSpotlight(media.spotlight, true);
|
update.registerSpotlight(
|
||||||
|
media.spotlight.map((m) => m.vm),
|
||||||
|
true,
|
||||||
|
);
|
||||||
const tiles = update.build();
|
const tiles = update.build();
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -21,8 +21,11 @@ export function spotlightExpandedLayout(
|
|||||||
prevTiles: TileStore,
|
prevTiles: TileStore,
|
||||||
): [SpotlightExpandedLayout, TileStore] {
|
): [SpotlightExpandedLayout, TileStore] {
|
||||||
const update = prevTiles.from(visibleTiles);
|
const update = prevTiles.from(visibleTiles);
|
||||||
update.registerSpotlight(media.spotlight, true);
|
update.registerSpotlight(
|
||||||
if (media.pip !== undefined) update.registerGridTile(media.pip);
|
media.spotlight.map((m) => m.vm),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
if (media.pip !== undefined) update.registerGridTile(media.pip.vm);
|
||||||
const tiles = update.build();
|
const tiles = update.build();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
Loading…
Reference in New Issue
Block a user