mirror of
https://github.com/vector-im/element-call.git
synced 2026-03-07 05:47:03 +00:00
Show 'reconnecting' message when sync loop is disconnected
With this change I'm also taking care to not show the standard "Connection to the server has been lost" banner in the call view, since that is now covered by the 'reconnecting' message.
This commit is contained in:
@@ -24,7 +24,6 @@ import { RegisterPage } from "./auth/RegisterPage";
|
||||
import { RoomPage } from "./room/RoomPage";
|
||||
import { ClientProvider } from "./ClientContext";
|
||||
import { ErrorPage, LoadingPage } from "./FullScreenView";
|
||||
import { DisconnectedBanner } from "./DisconnectedBanner";
|
||||
import { Initializer } from "./initializer";
|
||||
import { widget } from "./widget";
|
||||
import { useTheme } from "./useTheme";
|
||||
@@ -86,7 +85,6 @@ export const App: FC<Props> = ({ vm }) => {
|
||||
<Sentry.ErrorBoundary
|
||||
fallback={(error) => <ErrorPage error={error} widget={widget} />}
|
||||
>
|
||||
<DisconnectedBanner />
|
||||
<Routes>
|
||||
<SentryRoute path="/" element={<HomePage />} />
|
||||
<SentryRoute path="/login" element={<LoginPage />} />
|
||||
|
||||
@@ -61,7 +61,11 @@ export const AppBar: FC<Props> = ({ children }) => {
|
||||
style={{ display: hidden ? "none" : "block" }}
|
||||
className={styles.bar}
|
||||
>
|
||||
<Header>
|
||||
<Header
|
||||
// App bar is mainly seen in the call view, which has its own
|
||||
// 'reconnecting' toast
|
||||
disconnectedBanner={false}
|
||||
>
|
||||
<LeftNav>
|
||||
<Tooltip label={t("common.back")}>
|
||||
<IconButton onClick={onBackClick}>
|
||||
|
||||
@@ -17,27 +17,38 @@ import Logo from "./icons/Logo.svg?react";
|
||||
import { Avatar, Size } from "./Avatar";
|
||||
import { EncryptionLock } from "./room/EncryptionLock";
|
||||
import { useMediaQuery } from "./useMediaQuery";
|
||||
import { DisconnectedBanner } from "./DisconnectedBanner";
|
||||
|
||||
interface HeaderProps extends HTMLAttributes<HTMLElement> {
|
||||
ref?: Ref<HTMLElement>;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
/**
|
||||
* Whether the header should display an informational banner whenever the
|
||||
* client is disconnected from the homeserver.
|
||||
* @default true
|
||||
*/
|
||||
disconnectedBanner?: boolean;
|
||||
}
|
||||
|
||||
export const Header: FC<HeaderProps> = ({
|
||||
ref,
|
||||
children,
|
||||
className,
|
||||
disconnectedBanner = true,
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<header
|
||||
ref={ref}
|
||||
className={classNames(styles.header, className)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</header>
|
||||
<>
|
||||
<header
|
||||
ref={ref}
|
||||
className={classNames(styles.header, className)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</header>
|
||||
{disconnectedBanner && <DisconnectedBanner />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -508,7 +508,11 @@ export const InCallView: FC<InCallViewProps> = ({
|
||||
break;
|
||||
case "standard":
|
||||
header = (
|
||||
<Header className={styles.header} ref={headerRef}>
|
||||
<Header
|
||||
className={styles.header}
|
||||
ref={headerRef}
|
||||
disconnectedBanner={false} // This screen has its own 'reconnecting' toast
|
||||
>
|
||||
<LeftNav>
|
||||
<RoomHeaderInfo
|
||||
id={matrixInfo.roomId}
|
||||
|
||||
@@ -19,7 +19,9 @@ import {
|
||||
Track,
|
||||
} from "livekit-client";
|
||||
import {
|
||||
ClientEvent,
|
||||
RoomStateEvent,
|
||||
SyncState,
|
||||
type Room as MatrixRoom,
|
||||
type RoomMember,
|
||||
} from "matrix-js-sdk";
|
||||
@@ -69,7 +71,7 @@ import {
|
||||
ScreenShareViewModel,
|
||||
type UserMediaViewModel,
|
||||
} from "./MediaViewModel";
|
||||
import { accumulate, finalizeValue } from "../utils/observable";
|
||||
import { accumulate, and$, finalizeValue } from "../utils/observable";
|
||||
import { ObservableScope } from "./ObservableScope";
|
||||
import {
|
||||
duplicateTiles,
|
||||
@@ -494,18 +496,37 @@ export class CallViewModel extends ViewModel {
|
||||
map(() => this.matrixRTCSession.memberships),
|
||||
);
|
||||
|
||||
private readonly matrixRTCConnected$ = this.scope.behavior(
|
||||
this.memberships$.pipe(
|
||||
map((ms) =>
|
||||
ms.some(
|
||||
(m) => m.sender === this.userId && m.deviceId === this.deviceId,
|
||||
private readonly matrixConnected$ = this.scope.behavior(
|
||||
// To consider ourselves connected to MatrixRTC, we check the following:
|
||||
and$(
|
||||
// The client is connected to the sync loop
|
||||
(
|
||||
fromEvent(this.matrixRoom.client, ClientEvent.Sync) as Observable<
|
||||
[SyncState]
|
||||
>
|
||||
).pipe(
|
||||
startWith([this.matrixRoom.client.getSyncState()]),
|
||||
map(([state]) => state === SyncState.Syncing),
|
||||
),
|
||||
// We can see our own call membership
|
||||
this.memberships$.pipe(
|
||||
map((ms) =>
|
||||
ms.some(
|
||||
(m) => m.sender === this.userId && m.deviceId === this.deviceId,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// TODO: Account for LiveKit connection state too
|
||||
private readonly connected$ = this.matrixConnected$;
|
||||
|
||||
/**
|
||||
* Whether we should tell the user that we're reconnecting to the call.
|
||||
*/
|
||||
public readonly reconnecting$ = this.scope.behavior(
|
||||
this.matrixRTCConnected$.pipe(
|
||||
this.connected$.pipe(
|
||||
// We are reconnecting if we previously had some successful initial
|
||||
// connection but are now disconnected
|
||||
scan(
|
||||
@@ -1533,7 +1554,7 @@ export class CallViewModel extends ViewModel {
|
||||
// Pause all media tracks when we're disconnected from MatrixRTC, because it
|
||||
// can be an unpleasant surprise for the app to say 'reconnecting' and yet
|
||||
// still be transmitting your media to others.
|
||||
this.matrixRTCConnected$.pipe(this.scope.bind()).subscribe((connected) => {
|
||||
this.matrixConnected$.pipe(this.scope.bind()).subscribe((connected) => {
|
||||
const publications =
|
||||
this.livekitRoom.localParticipant.trackPublications.values();
|
||||
if (connected) {
|
||||
|
||||
@@ -7,6 +7,7 @@ Please see LICENSE in the repository root for full details.
|
||||
|
||||
import {
|
||||
type Observable,
|
||||
combineLatest,
|
||||
concat,
|
||||
defer,
|
||||
finalize,
|
||||
@@ -86,3 +87,11 @@ export function getValue<T>(state$: Observable<T>): T {
|
||||
if (value === nothing) throw new Error("Not a state Observable");
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Observable that has a value of true whenever all its inputs are
|
||||
* true.
|
||||
*/
|
||||
export function and$(...inputs: Observable<boolean>[]): Observable<boolean> {
|
||||
return combineLatest(inputs, (...flags) => flags.every((flag) => flag));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user