mirror of
https://github.com/balzack/databag.git
synced 2025-04-28 12:35:34 +00:00
adding video call screen
This commit is contained in:
parent
67ea8c9925
commit
dda3eb23ed
20
app/client/mobile/src/call/Call.styled.ts
Normal file
20
app/client/mobile/src/call/Call.styled.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {StyleSheet} from 'react-native';
|
||||||
|
import { Colors } from '../constants/Colors';
|
||||||
|
|
||||||
|
export const styles = StyleSheet.create({
|
||||||
|
active: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
position: 'absolute',
|
||||||
|
},
|
||||||
|
inactive: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
call: {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
});
|
85
app/client/mobile/src/call/Call.tsx
Normal file
85
app/client/mobile/src/call/Call.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
import { useCall } from './useCall.hook';
|
||||||
|
import { styles } from './Call.styled'
|
||||||
|
import { Card as Contact } from '../card/Card';
|
||||||
|
import { Text, Surface, IconButton, ActivityIndicator } from 'react-native-paper';
|
||||||
|
import { Confirm } from '../confirm/Confirm';
|
||||||
|
import { Colors } from '../constants/Colors';
|
||||||
|
|
||||||
|
export function Call() {
|
||||||
|
const { state, actions } = useCall();
|
||||||
|
const [alert, setAlert] = useState(false);
|
||||||
|
const [ending, setEnding] = useState(false);
|
||||||
|
const [applyingAudio, setApplyingAudio] = useState(false);
|
||||||
|
const [accepting, setAccepting] = useState(null as null|string);
|
||||||
|
const [ignoring, setIgnoring] = useState(null as null|string);
|
||||||
|
const [declining, setDeclining] = useState(null as null|string);
|
||||||
|
|
||||||
|
const toggleAudio = async () => {
|
||||||
|
if (!applyingAudio) {
|
||||||
|
setApplyingAudio(true);
|
||||||
|
try {
|
||||||
|
if (state.audioEnabled) {
|
||||||
|
await actions.disableAudio();
|
||||||
|
} else if (!state.audioEnabled) {
|
||||||
|
await actions.enableAudio();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
setAlert(true);
|
||||||
|
}
|
||||||
|
setApplyingAudio(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleVideo = async () => {
|
||||||
|
if (!applyingVideo) {
|
||||||
|
setApplyingVideo(true);
|
||||||
|
try {
|
||||||
|
if (state.videoEnabled) {
|
||||||
|
await actions.disableVideo();
|
||||||
|
} else if (!state.videoEnabled) {
|
||||||
|
await actions.enableVideo();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
setAlert(true);
|
||||||
|
}
|
||||||
|
setApplyingVideo(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = async () => {
|
||||||
|
if (!ending) {
|
||||||
|
setEnding(true);
|
||||||
|
try {
|
||||||
|
await actions.end();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
setAlert(true);
|
||||||
|
}
|
||||||
|
setEnding(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const alertParams = {
|
||||||
|
title: state.strings.operationFailed,
|
||||||
|
prompt: state.strings.tryAgain,
|
||||||
|
cancel: {
|
||||||
|
label: state.strings.close,
|
||||||
|
action: () => {
|
||||||
|
setAlert(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={(state.calling && state.fullscreen) ? styles.active : styles.inactive}>
|
||||||
|
<Surface elevation={4} mode="flat" style={styles.call}>
|
||||||
|
</Surface>
|
||||||
|
<Confirm show={alert} params={alertParams} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
54
app/client/mobile/src/call/useCall.hook.ts
Normal file
54
app/client/mobile/src/call/useCall.hook.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { useState, useContext, useEffect, useRef } from 'react'
|
||||||
|
import { RingContext } from '../context/RingContext'
|
||||||
|
import { DisplayContext } from '../context/DisplayContext'
|
||||||
|
import { ContextType } from '../context/ContextType'
|
||||||
|
import { Card } from 'databag-client-sdk';
|
||||||
|
|
||||||
|
export function useCall() {
|
||||||
|
const ring = useContext(RingContext) as ContextType;
|
||||||
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
|
const offsetTime = useRef(0);
|
||||||
|
const offset = useRef(false);
|
||||||
|
|
||||||
|
const [state, setState] = useState({
|
||||||
|
strings: display.state.strings,
|
||||||
|
calls: [] as { callId: string, card: Card }[],
|
||||||
|
calling: null as null | Card,
|
||||||
|
remoteVideo: false,
|
||||||
|
localVideo: false,
|
||||||
|
audioEnabled: false,
|
||||||
|
videoEnabled: false,
|
||||||
|
connected: false,
|
||||||
|
duration: 0,
|
||||||
|
failed: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const updateState = (value: any) => {
|
||||||
|
setState((s) => ({ ...s, ...value }))
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
if (offset.current) {
|
||||||
|
const now = new Date();
|
||||||
|
const duration = Math.floor((now.getTime() / 1000) - offsetTime.current);
|
||||||
|
updateState({ duration });
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { calls, calling, fullscreen, remoteVideo, localVideo, audioEnabled, videoEnabled, connected, connectedTime, failed } = ring.state;
|
||||||
|
offsetTime.current = connectedTime;
|
||||||
|
offset.current = connected;
|
||||||
|
const duration = connected ? Math.floor(((new Date()).getTime() / 1000) - connectedTime) : 0;
|
||||||
|
updateState({ calls, calling, fullscreen, duration, remoteVideo, localVideo, audioEnabled, videoEnabled, connected, failed });
|
||||||
|
}, [ring.state]);
|
||||||
|
|
||||||
|
const actions = ring.actions;
|
||||||
|
return { state, actions };
|
||||||
|
}
|
@ -49,6 +49,7 @@ export function useRingContext() {
|
|||||||
connected: false,
|
connected: false,
|
||||||
connectedTime: 0,
|
connectedTime: 0,
|
||||||
failed: false,
|
failed: false,
|
||||||
|
fullscreen: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -121,11 +121,11 @@ export function Ring() {
|
|||||||
)}
|
)}
|
||||||
{ state.calling && (
|
{ state.calling && (
|
||||||
<Surface elevation={4} mode="flat" style={styles.ring}>
|
<Surface elevation={4} mode="flat" style={styles.ring}>
|
||||||
<IconButton style={styles.circleIcon} iconColor="white" containerColor={Colors.primary} icon={state.audioEnabled ? 'microphone' : 'microphone-off'} compact="true" mode="contained" size={24} onPress={toggleAudio} />
|
<IconButton style={styles.circleIcon} iconColor="white" disabled={!state.connected} containerColor={Colors.primary} icon={state.audioEnabled ? 'microphone' : 'microphone-off'} compact="true" mode="contained" size={24} onPress={toggleAudio} />
|
||||||
<IconButton style={styles.circleIcon} iconColor="white" containerColor={Colors.confirmed} icon="arrow-expand-all" compact="true" mode="contained" size={24} onPress={toggleAudio} />
|
<IconButton style={styles.circleIcon} iconColor="white" disabled={!state.connected} containerColor={Colors.confirmed} icon={(state.remoteVideo || state.localVideo) ? 'video-switch-outline' : 'arrow-expand-all'} compact="true" mode="contained" size={24} onPress={()=>actions.setFullscreen(true)} />
|
||||||
<View style={styles.name}>
|
<View style={styles.name}>
|
||||||
{ state.calling.name && (
|
{ state.calling.name && (
|
||||||
<Text style={styles.nameSet} numberOfLines={1}>asuperlongnamehere asuperlongnamehere</Text>
|
<Text style={styles.nameSet} numberOfLines={1}>{ state.calling.name }</Text>
|
||||||
)}
|
)}
|
||||||
{ !state.calling.name && (
|
{ !state.calling.name && (
|
||||||
<Text style={styles.nameUnset} adjustsFontSizeToFit={true} numberOfLines={1}>{ state.strings.name }</Text>
|
<Text style={styles.nameUnset} adjustsFontSizeToFit={true} numberOfLines={1}>{ state.strings.name }</Text>
|
||||||
|
@ -15,6 +15,7 @@ export function useRing() {
|
|||||||
calls: [] as { callId: string, card: Card }[],
|
calls: [] as { callId: string, card: Card }[],
|
||||||
calling: null as null | Card,
|
calling: null as null | Card,
|
||||||
remoteVideo: false,
|
remoteVideo: false,
|
||||||
|
localVideo: false,
|
||||||
audioEnabled: false,
|
audioEnabled: false,
|
||||||
connected: false,
|
connected: false,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
@ -40,11 +41,11 @@ export function useRing() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { calls, calling, remoteVideo, audioEnabled, connected, connectedTime, failed } = ring.state;
|
const { calls, calling, localVideo, remoteVideo, audioEnabled, connected, connectedTime, failed } = ring.state;
|
||||||
offsetTime.current = connectedTime;
|
offsetTime.current = connectedTime;
|
||||||
offset.current = connected;
|
offset.current = connected;
|
||||||
const duration = connected ? Math.floor(((new Date()).getTime() / 1000) - connectedTime) : 0;
|
const duration = connected ? Math.floor(((new Date()).getTime() / 1000) - connectedTime) : 0;
|
||||||
updateState({ calls, calling, duration, remoteVideo, audioEnabled, connected, failed });
|
updateState({ calls, calling, duration, localVideo, remoteVideo, audioEnabled, connected, failed });
|
||||||
}, [ring.state]);
|
}, [ring.state]);
|
||||||
|
|
||||||
const actions = ring.actions;
|
const actions = ring.actions;
|
||||||
|
@ -19,6 +19,7 @@ import {createDrawerNavigator} from '@react-navigation/drawer';
|
|||||||
import {createNativeStackNavigator} from '@react-navigation/native-stack';
|
import {createNativeStackNavigator} from '@react-navigation/native-stack';
|
||||||
import {Colors} from '../constants/Colors';
|
import {Colors} from '../constants/Colors';
|
||||||
import {Ring} from '../ring/Ring';
|
import {Ring} from '../ring/Ring';
|
||||||
|
import {Call} from '../call/Call';
|
||||||
|
|
||||||
const SettingsDrawer = createDrawerNavigator();
|
const SettingsDrawer = createDrawerNavigator();
|
||||||
const ContactsDrawer = createDrawerNavigator();
|
const ContactsDrawer = createDrawerNavigator();
|
||||||
@ -198,6 +199,7 @@ export function Session() {
|
|||||||
</Surface>
|
</Surface>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
<Call />
|
||||||
</View>
|
</View>
|
||||||
</RingContextProvider>
|
</RingContextProvider>
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user