use new components

This commit is contained in:
jmoguilevsky 2023-08-08 17:17:12 -03:00
parent 203687bc72
commit e4f5ee7a8f
No known key found for this signature in database
GPG Key ID: D097BD46EA6103FA
6 changed files with 292 additions and 19 deletions

View File

@ -1,6 +1,7 @@
import React from "react"
import { Props } from "./Conference.types"
import { LiveKitRoom, VideoConference } from "@livekit/components-react"
import { LiveKitRoom } from "@livekit/components-react"
import { VideoConference } from "../../VideoConference/Videoconference"
import "@livekit/components-styles"
import "./Conference.css"

View File

@ -0,0 +1,156 @@
import * as React from "react"
import type { Participant, TrackPublication } from "livekit-client"
import { Track } from "livekit-client"
import type { ParticipantClickEvent, TrackReferenceOrPlaceholder } from "@livekit/components-core"
import { isParticipantSourcePinned } from "@livekit/components-core"
import {
AudioTrack,
ConnectionQualityIndicator,
FocusToggle,
ParticipantContext,
ParticipantName,
TrackMutedIndicator,
VideoTrack,
useEnsureParticipant,
useMaybeLayoutContext,
useMaybeParticipantContext,
useMaybeTrackContext,
useParticipantTile,
} from "@livekit/components-react"
import Profile from "decentraland-dapps/dist/containers/Profile"
/** @public */
export function ParticipantContextIfNeeded(
props: React.PropsWithChildren<{
participant?: Participant
}>
) {
const hasContext = !!useMaybeParticipantContext()
return props.participant && !hasContext ? (
<ParticipantContext.Provider value={props.participant}>{props.children}</ParticipantContext.Provider>
) : (
<>{props.children}</>
)
}
/** @public */
export interface ParticipantTileProps extends React.HTMLAttributes<HTMLDivElement> {
disableSpeakingIndicator?: boolean
participant?: Participant
source?: Track.Source
publication?: TrackPublication
onParticipantClick?: (event: ParticipantClickEvent) => void
imageSize?: "normal" | "large" | "huge" | "massive"
}
/**
* The ParticipantTile component is the base utility wrapper for displaying a visual representation of a participant.
* This component can be used as a child of the `TrackLoop` component or by spreading a track reference as properties.
*
* @example
* ```tsx
* <ParticipantTile source={Track.Source.Camera} />
*
* <ParticipantTile {...trackReference} />
* ```
* @public
*/
export function ParticipantTile({
participant,
children,
source = Track.Source.Camera,
onParticipantClick,
publication,
disableSpeakingIndicator,
imageSize,
...htmlProps
}: ParticipantTileProps) {
const p = useEnsureParticipant(participant)
const trackRef: TrackReferenceOrPlaceholder = useMaybeTrackContext() ?? {
participant: p,
source,
publication,
}
const { elementProps } = useParticipantTile<HTMLDivElement>({
participant: trackRef.participant,
htmlProps,
source: trackRef.source,
publication: trackRef.publication,
disableSpeakingIndicator,
onParticipantClick,
})
const layoutContext = useMaybeLayoutContext()
const handleSubscribe = React.useCallback(
(subscribed: boolean) => {
if (
trackRef.source &&
!subscribed &&
layoutContext &&
layoutContext.pin.dispatch &&
isParticipantSourcePinned(trackRef.participant, trackRef.source, layoutContext.pin.state)
) {
layoutContext.pin.dispatch({ msg: "clear_pin" })
}
},
[trackRef.participant, layoutContext, trackRef.source]
)
const participantWithProfile: Participant = React.useMemo(
() => ({
...trackRef.participant,
name: "Edita me",
}),
[trackRef.participant]
) as Participant
return (
<div style={{ position: "relative" }} {...elementProps}>
<ParticipantContextIfNeeded participant={trackRef.participant}>
{children ?? (
<>
{trackRef.publication?.kind === "video" ||
trackRef.source === Track.Source.Camera ||
trackRef.source === Track.Source.ScreenShare ? (
<VideoTrack
participant={trackRef.participant}
source={trackRef.source}
publication={trackRef.publication}
onSubscriptionStatusChanged={handleSubscribe}
/>
) : (
<AudioTrack
participant={trackRef.participant}
source={trackRef.source}
publication={trackRef.publication}
onSubscriptionStatusChanged={handleSubscribe}
/>
)}
<div className="lk-participant-placeholder">
<Profile address={trackRef.participant.identity} imageOnly size={imageSize} />
</div>
<div className="lk-participant-metadata">
<div className="lk-participant-metadata-item">
{trackRef.source === Track.Source.Camera ? (
<>
<TrackMutedIndicator source={Track.Source.Microphone} show={"muted"}></TrackMutedIndicator>
<ParticipantName participant={participantWithProfile} />
</>
) : (
<>
{/* <ScreenShareIcon style={{ marginRight: "0.25rem" }} /> */}
<ParticipantName participant={participantWithProfile}>&apos;s screen</ParticipantName>
</>
)}
</div>
<ConnectionQualityIndicator className="lk-participant-metadata-item" />
</div>
</>
)}
<FocusToggle trackSource={trackRef.source} />
</ParticipantContextIfNeeded>
</div>
)
}

View File

@ -0,0 +1,129 @@
import * as React from "react"
import type { WidgetState } from "@livekit/components-core"
import { isEqualTrackRef, isTrackReference, log, isWeb } from "@livekit/components-core"
import { RoomEvent, Track } from "livekit-client"
import type { TrackReferenceOrPlaceholder } from "@livekit/components-core"
import {
CarouselView,
Chat,
ConnectionStateToast,
ControlBar,
FocusLayout,
FocusLayoutContainer,
GridLayout,
LayoutContextProvider,
MessageFormatter,
RoomAudioRenderer,
useCreateLayoutContext,
useParticipants,
usePinnedTracks,
useTracks,
} from "@livekit/components-react"
import { ParticipantTile } from "./ParticipantTile"
/**
* @public
*/
export interface VideoConferenceProps extends React.HTMLAttributes<HTMLDivElement> {
chatMessageFormatter?: MessageFormatter
}
/**
* This component is the default setup of a classic LiveKit video conferencing app.
* It provides functionality like switching between participant grid view and focus view.
*
* @remarks
* The component is implemented with other LiveKit components like `FocusContextProvider`,
* `GridLayout`, `ControlBar`, `FocusLayoutContainer` and `FocusLayout`.
*
* @example
* ```tsx
* <LiveKitRoom>
* <VideoConference />
* <LiveKitRoom>
* ```
* @public
*/
export function VideoConference({ chatMessageFormatter, ...props }: VideoConferenceProps) {
const [widgetState, setWidgetState] = React.useState<WidgetState>({ showChat: false })
const lastAutoFocusedScreenShareTrack = React.useRef<TrackReferenceOrPlaceholder | null>(null)
const tracks = useTracks(
[
{ source: Track.Source.Camera, withPlaceholder: true },
{ source: Track.Source.ScreenShare, withPlaceholder: false },
],
{ updateOnlyOn: [RoomEvent.ActiveSpeakersChanged] }
)
const participants = useParticipants({
updateOnlyOn: [RoomEvent.ParticipantConnected, RoomEvent.ParticipantDisconnected],
})
const widgetUpdate = (state: WidgetState) => {
log.debug("updating widget state", state)
setWidgetState(state)
}
const layoutContext = useCreateLayoutContext()
const screenShareTracks = tracks
.filter(isTrackReference)
.filter((track) => track.publication.source === Track.Source.ScreenShare)
const focusTrack = usePinnedTracks(layoutContext)?.[0]
const carouselTracks = tracks.filter((track) => !isEqualTrackRef(track, focusTrack))
React.useEffect(() => {
// If screen share tracks are published, and no pin is set explicitly, auto set the screen share.
if (screenShareTracks.length > 0 && lastAutoFocusedScreenShareTrack.current === null) {
log.debug("Auto set screen share focus:", { newScreenShareTrack: screenShareTracks[0] })
layoutContext.pin.dispatch?.({ msg: "set_pin", trackReference: screenShareTracks[0] })
lastAutoFocusedScreenShareTrack.current = screenShareTracks[0]
} else if (
lastAutoFocusedScreenShareTrack.current &&
!screenShareTracks.some(
(track) => track.publication.trackSid === lastAutoFocusedScreenShareTrack.current?.publication?.trackSid
)
) {
log.debug("Auto clearing screen share focus.")
layoutContext.pin.dispatch?.({ msg: "clear_pin" })
lastAutoFocusedScreenShareTrack.current = null
}
}, [screenShareTracks.map((ref) => ref.publication.trackSid).join(), focusTrack?.publication?.trackSid])
return (
<div className="lk-video-conference" {...props}>
{isWeb() && (
<LayoutContextProvider
value={layoutContext}
// onPinChange={handleFocusStateChange}
onWidgetChange={widgetUpdate}
>
<div className="lk-video-conference-inner">
{!focusTrack ? (
<div className="lk-grid-layout-wrapper">
<GridLayout tracks={tracks}>
<ParticipantTile imageSize="massive" />
</GridLayout>
</div>
) : (
<div className="lk-focus-layout-wrapper">
<FocusLayoutContainer>
<CarouselView tracks={carouselTracks}>
<ParticipantTile imageSize="huge" />
</CarouselView>
{focusTrack && <FocusLayout track={focusTrack} />}
</FocusLayoutContainer>
</div>
)}
<ControlBar controls={{ chat: true }} />
</div>
<Chat style={{ display: widgetState.showChat ? "flex" : "none" }} messageFormatter={chatMessageFormatter} />
</LayoutContextProvider>
)}
<RoomAudioRenderer />
<ConnectionStateToast />
</div>
)
}

View File

@ -1,8 +1,6 @@
{
"NETWORK": "sepolia",
"CHAIN_ID": "11155111",
"EXPLORER_URL": "https://play.decentraland.zone",
"PEER_URL": "https://peer-ap1.decentraland.zone",
"MARKETPLACE_GRAPH_URL": "https://api.studio.thegraph.com/query/49472/marketplace-sepolia/version/latest",
"NETWORK": "mainnet",
"CHAIN_ID": "1",
"PEER_URL": "https://peer.decentraland.org",
"WORLDS_CONTENT_SERVER_URL": "https://worlds-content-server.decentraland.zone"
}

View File

@ -3,10 +3,5 @@
"CHAIN_ID": "1",
"EXPLORER_URL": "https://play.decentraland.org",
"PEER_URL": "https://peer.decentraland.org",
"MARKETPLACE_GRAPH_URL": "https://api.thegraph.com/subgraphs/name/decentraland/marketplace-goerli",
"WORLDS_CONTENT_SERVER_URL": "https://worlds-content-server.decentraland.org",
"BUILDER_URL": "https://builder.decentraland.org",
"SYNAPSE_URL": "https://social.decentraland.org",
"SOCIAL_RPC_URL": "wss://rpc-social-service.decentraland.org",
"PROFILE_URL": "https://profile.decentraland.org"
"WORLDS_CONTENT_SERVER_URL": "https://worlds-content-server.decentraland.org"
}

View File

@ -1,12 +1,6 @@
{
"NETWORK": "mainnet",
"CHAIN_ID": "1",
"EXPLORER_URL": "https://play.decentraland.today",
"PEER_URL": "https://peer.decentraland.org",
"MARKETPLACE_GRAPH_URL": "https://api.thegraph.com/subgraphs/name/decentraland/marketplace",
"WORLDS_CONTENT_SERVER_URL": "https://worlds-content-server.decentraland.org",
"SOCIAL_RPC_URL": "wss://rpc-social-service.decentraland.today",
"BUILDER_URL": "https://builder.decentraland.today",
"SYNAPSE_URL": "https://social.decentraland.today",
"PROFILE_URL": "https://profile.decentraland.today"
"WORLDS_CONTENT_SERVER_URL": "https://worlds-content-server.decentraland.org"
}