mirror of
https://github.com/balzack/databag.git
synced 2025-05-05 07:55:15 +00:00
rendering call video on webapp
This commit is contained in:
parent
cda9f6078a
commit
35f2c7d58d
@ -2,65 +2,64 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
.inactive {
|
.inactive {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.titleView {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding-top: 32px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.titleName {
|
||||||
|
font-size: 32px;
|
||||||
|
padding-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
height: 50%;
|
||||||
|
width: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
width: fit-content;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleStatus {
|
||||||
|
font-size: 24;
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
background-color: var(--mantine-color-surface-2);
|
||||||
|
position: absolute;
|
||||||
|
bottom: 92px;
|
||||||
|
opacity: 0.8;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
gap: 16px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
.call {
|
.call {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
background-color: var(--mantine-color-surface-4);
|
||||||
.controls {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 10%;
|
|
||||||
padding: 8;
|
|
||||||
gap: 12;
|
|
||||||
border-radius: 8;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
.full {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.box {
|
|
||||||
position: absolute;
|
|
||||||
top: 10%;
|
|
||||||
right: 10%;
|
|
||||||
width: 20%;
|
|
||||||
height: 20%;
|
|
||||||
}
|
|
||||||
.titleView {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
paddingTop: 92;
|
|
||||||
}
|
|
||||||
.titleName {
|
|
||||||
font-size: 24;
|
|
||||||
padding-bottom: 32;
|
|
||||||
}
|
|
||||||
.titleImage {
|
|
||||||
width: 80%;
|
|
||||||
height: auto;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
border-radius: 8;
|
|
||||||
}
|
|
||||||
.duration {
|
|
||||||
padding-top: 16;
|
|
||||||
font-size: 20;
|
|
||||||
}
|
|
||||||
.logoView {
|
|
||||||
height: 100%;
|
|
||||||
width: auto;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import classes from './Call.module.css'
|
|||||||
import { Card as Contact } from '../card/Card';
|
import { Card as Contact } from '../card/Card';
|
||||||
import { Colors } from '../constants/Colors';
|
import { Colors } from '../constants/Colors';
|
||||||
import { modals } from '@mantine/modals'
|
import { modals } from '@mantine/modals'
|
||||||
|
import { Image, Text, ActionIcon } from '@mantine/core'
|
||||||
|
import { IconPhone, IconMicrophone, IconMicrophoneOff, IconVideo, IconVideoOff } from '@tabler/icons-react'
|
||||||
|
|
||||||
export function Call() {
|
export function Call() {
|
||||||
const { state, actions } = useCall();
|
const { state, actions } = useCall();
|
||||||
@ -76,7 +78,47 @@ export function Call() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div />
|
<div className={(state.calling && state.fullscreen) ? classes.active : classes.inactive}>
|
||||||
|
{ state.calling && (
|
||||||
|
<div className={classes.call}>
|
||||||
|
|
||||||
|
<div className={classes.titleView}>
|
||||||
|
{ state.calling.name && (
|
||||||
|
<Text className={classes.titleName}>{ state.calling.name }</Text>
|
||||||
|
)}
|
||||||
|
{ !state.calling.name && (
|
||||||
|
<Text className={classes.titleName}>{ `${state.calling.handle}/${state.calling.node}` }</Text>
|
||||||
|
)}
|
||||||
|
<div className={classes.image}>
|
||||||
|
<div className={classes.frame}>
|
||||||
|
<Image radius="lg" fit="contain" className={classes.logo} src={state.calling.imageUrl} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Text className={classes.titleStatus}>{ `${Math.floor(state.duration/60)}:${(state.duration % 60).toString().padStart(2, '0')}` }</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes.buttons}>
|
||||||
|
<ActionIcon onClick={toggleAudio} disabled={!state.connected} loading={applyingAudio} color={Colors.primary} size="xl">
|
||||||
|
{ state.audioEnabled && (
|
||||||
|
<IconMicrophone />
|
||||||
|
)}
|
||||||
|
{ !state.audioEnabled && (
|
||||||
|
<IconMicrophoneOff />
|
||||||
|
)}
|
||||||
|
</ActionIcon>
|
||||||
|
<ActionIcon onClick={toggleVideo} disabled={!state.connected} loading={applyingVideo} color={Colors.primary} size="xl">
|
||||||
|
{ state.videoEnabled && (
|
||||||
|
<IconVideo />
|
||||||
|
)}
|
||||||
|
{ !state.videoEnabled && (
|
||||||
|
<IconVideoOff />
|
||||||
|
)}
|
||||||
|
</ActionIcon>
|
||||||
|
<ActionIcon onClick={end} color={Colors.offsync} size="xl"><IconPhone className={classes.off} /></ActionIcon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ export function useRingContext() {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
} else if (status === 'closed') {
|
} else if (status === 'closed') {
|
||||||
await cleanup;
|
await cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,6 +190,7 @@ export function useRingContext() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cleanup = async () => {
|
const cleanup = async () => {
|
||||||
|
console.log("CLEANUP!");
|
||||||
closing.current = true;
|
closing.current = true;
|
||||||
while (updatingPeer.current || connecting.current) {
|
while (updatingPeer.current || connecting.current) {
|
||||||
await new Promise((r) => setTimeout(r, CLOSE_POLL_MS));
|
await new Promise((r) => setTimeout(r, CLOSE_POLL_MS));
|
||||||
@ -213,6 +214,7 @@ export function useRingContext() {
|
|||||||
peerUpdate.current = [];
|
peerUpdate.current = [];
|
||||||
updateState({ calling: null, connected: false, connectedTime: 0, failed: false, localStream: null, remoteStream: null, localVideo: false, remoteVideo: false });
|
updateState({ calling: null, connected: false, connectedTime: 0, failed: false, localStream: null, remoteStream: null, localVideo: false, remoteVideo: false });
|
||||||
closing.current = false;
|
closing.current = false;
|
||||||
|
console.log("!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
const transmit = (ice: { urls: string; username: string; credential: string }[]) => {
|
const transmit = (ice: { urls: string; username: string; credential: string }[]) => {
|
||||||
|
@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { useRing } from './useRing.hook';
|
import { useRing } from './useRing.hook';
|
||||||
import classes from './Ring.module.css';
|
import classes from './Ring.module.css';
|
||||||
import { Card as Contact } from '../card/Card';
|
import { Card as Contact } from '../card/Card';
|
||||||
|
import { Card } from 'databag-client-sdk';
|
||||||
import { Colors } from '../constants/Colors';
|
import { Colors } from '../constants/Colors';
|
||||||
import { modals } from '@mantine/modals'
|
import { modals } from '@mantine/modals'
|
||||||
import { Loader, Image, Text, ActionIcon } from '@mantine/core'
|
import { Loader, Image, Text, ActionIcon } from '@mantine/core'
|
||||||
@ -59,7 +60,7 @@ export function Ring() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const accept = async (callId, card) => {
|
const accept = async (callId: string, card: Card) => {
|
||||||
if (!accepting) {
|
if (!accepting) {
|
||||||
setAccepting(callId);
|
setAccepting(callId);
|
||||||
try {
|
try {
|
||||||
@ -72,7 +73,7 @@ export function Ring() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ignore = async (callId, card) => {
|
const ignore = async (callId: string, card: Card) => {
|
||||||
if (!ignoring) {
|
if (!ignoring) {
|
||||||
setIgnoring(callId);
|
setIgnoring(callId);
|
||||||
try {
|
try {
|
||||||
@ -85,7 +86,7 @@ export function Ring() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const decline = async (callId, card) => {
|
const decline = async (callId: string, card: Card) => {
|
||||||
if (!declining) {
|
if (!declining) {
|
||||||
setDeclining(callId);
|
setDeclining(callId);
|
||||||
try {
|
try {
|
||||||
@ -124,7 +125,7 @@ export function Ring() {
|
|||||||
)}
|
)}
|
||||||
{ state.calling && (
|
{ state.calling && (
|
||||||
<div className={classes.ring}>
|
<div className={classes.ring}>
|
||||||
<ActionIcon variant="subtle" loading={applyingAudio} disabled={!state.connected} className={classes.circleIcon} color={Colors.primary}>
|
<ActionIcon variant="subtle" loading={applyingAudio} disabled={!state.connected} className={classes.circleIcon} color={Colors.primary} onClick={toggleAudio}>
|
||||||
{ state.audioEnabled && (
|
{ state.audioEnabled && (
|
||||||
<IconMicrophone />
|
<IconMicrophone />
|
||||||
)}
|
)}
|
||||||
@ -132,7 +133,7 @@ export function Ring() {
|
|||||||
<IconMicrophoneOff />
|
<IconMicrophoneOff />
|
||||||
)}
|
)}
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<ActionIcon variant="subtle" disabled={!state.connected} className={classes.circleIcon} color={Colors.confirmed}>
|
<ActionIcon variant="subtle" disabled={!state.connected} className={classes.circleIcon} color={Colors.confirmed} onClick={()=>actions.setFullscreen(true)}>
|
||||||
<IconArrowsMaximize />
|
<IconArrowsMaximize />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
<div className={classes.name}>
|
<div className={classes.name}>
|
||||||
@ -140,7 +141,7 @@ export function Ring() {
|
|||||||
<Text className={classes.nameSet}>{ state.calling.name }</Text>
|
<Text className={classes.nameSet}>{ state.calling.name }</Text>
|
||||||
)}
|
)}
|
||||||
{ !state.calling.name && (
|
{ !state.calling.name && (
|
||||||
<Text className={classs.nameUnset}>{ state.strings.name }</Text>
|
<Text className={classes.nameUnset}>{ state.strings.name }</Text>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.status}>
|
<div className={classes.status}>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user