diff --git a/net/web/src/constants/Strings.js b/net/web/src/constants/Strings.js index 20eef60e..cab22a12 100644 --- a/net/web/src/constants/Strings.js +++ b/net/web/src/constants/Strings.js @@ -117,7 +117,6 @@ export const en = { copied: 'Copied', accounts: 'Accounts', accessAccount: 'Access Account', - createAccount: 'Create Account', browserLink: 'Browser Link', mobileToken: 'Mobile Token', createLink: 'Create Account Link', @@ -126,7 +125,6 @@ export const en = { disableAccount: 'Disable Account', enableAccount: 'Enable Account', deleteAccount: 'Delete Account', - settings: 'Settings', hostHint: 'domain:port/app', federatedHost: 'Federated Host', storageLimit: 'Storage Limit (GB) / Account', @@ -153,7 +151,6 @@ export const en = { deleteMessage: 'Deleting Message', messageHint: 'Are you sure you want to delete the message?', - newMessage: 'New Message', attachImage: 'Attach Image', attachVideo: 'Attach Video', attachAudio: 'Attach Audio', @@ -301,7 +298,6 @@ export const fr = { copied: 'Copié', accounts: 'Comptes', accessAccount: 'Accéder au Compte', - createAccount: 'Créer un Compte', browserLink: 'Lien du Navigateur', mobileToken: 'Code Mobile', createLink: 'Lien pour Créer un Compte', @@ -310,7 +306,6 @@ export const fr = { disableAccount: 'Désactiver le Compte', enableAccount: 'Activer le Compte', deleteAccount: 'Supprimer le Compte', - settings: 'Paramètres', hostHint: 'domaine:port/app', federatedHost: 'Hôte Fédéré', storageLimit: 'Limite de Espace (Go) / Compte', @@ -337,7 +332,6 @@ export const fr = { deleteMessage: 'Suppression du Message', messageHint: 'Êtes-vous Sûr de Vouloir Supprimer le Message?', - newMessage: 'Nouveau Message', attachImage: 'Joindre une Image', attachVideo: 'Joindre une Vidéo', attachAudio: 'Joindre un Audio', diff --git a/net/web/src/context/useRingContext.hook.js b/net/web/src/context/useRingContext.hook.js index bb3430e6..4ceac9ea 100644 --- a/net/web/src/context/useRingContext.hook.js +++ b/net/web/src/context/useRingContext.hook.js @@ -134,8 +134,31 @@ export function useRingContext() { processing.current = false; } - const transmit = async (policy, ice) => { + const getAudioStream = async (audioId) => { + try { + if (audioId) { + return await navigator.mediaDevices.getUserMedia({ video: false, audio: { deviceId: audioId } }); + } + } + catch (err) { + console.log(err); + } + return await navigator.mediaDevices.getUserMedia({ video: false, audio: true }); + } + const getVideoStream = async (videoId) => { + try { + if (videoId) { + return await navigator.mediaDevices.getUserMedia({ video: { deviceId: videoId }, audio: false }); + } + } + catch (err) { + console.log(err); + } + return await navigator.mediaDevices.getUserMedia({ video: true, audio: false }); + } + + const transmit = async (policy, ice, audioId) => { pc.current = new RTCPeerConnection({ iceServers: ice }); pc.current.ontrack = (ev) => { if (!stream.current) { @@ -164,13 +187,7 @@ export function useRingContext() { }; try { - const devices = await navigator.mediaDevices.enumerateDevices(); - console.log('>> ', devices); - - const stream = await navigator.mediaDevices.getUserMedia({ - video: false, - audio: true, - }); + const stream = await getAudioStream(audioId); accessAudio.current = true; updateState({ localAudio: true }); for (const track of stream.getTracks()) { @@ -185,7 +202,7 @@ export function useRingContext() { } } - const connect = async (policy, node, token, clearRing, clearAlive, ice) => { + const connect = async (policy, audioId, node, token, clearRing, clearAlive, ice) => { // connect signal socket connected.current = false; @@ -209,7 +226,7 @@ export function useRingContext() { updateState({ callStatus: "connected" }); if (policy === 'polite') { connected.current = true; - transmit('polite', ice); + transmit('polite', ice, audioId); polite(); } } @@ -260,7 +277,7 @@ export function useRingContext() { ws.current.send(JSON.stringify({ AppToken: token })); if (policy === 'impolite') { connected.current = true; - transmit('impolite', ice); + transmit('impolite', ice, audioId); impolite(); } } @@ -317,7 +334,7 @@ export function useRingContext() { } } }, - accept: async (cardId, callId, contactNode, contactToken, calleeToken, iceUrl, iceUsername, icePassword) => { + accept: async (cardId, callId, contactNode, contactToken, calleeToken, iceUrl, iceUsername, icePassword, audioId) => { if (calling.current) { throw new Error("active session"); } @@ -332,7 +349,7 @@ export function useRingContext() { updateState({ ringing: ringing.current, callStatus: "connecting", cardId }); calling.current = { callId, contactNode, contactToken, host: false }; - await connect('impolite', contactNode, calleeToken, () => {}, () => {}, ice); + await connect('impolite', audioId, contactNode, calleeToken, () => {}, () => {}, ice); } }, end: async () => { @@ -362,7 +379,7 @@ export function useRingContext() { } } }, - call: async (cardId, contactNode, contactToken) => { + call: async (cardId, contactNode, contactToken, audioId) => { if (calling.current) { throw new Error("active session"); } @@ -416,17 +433,11 @@ export function useRingContext() { updateState({ callStatus: "ringing" }); calling.current = { callId: id, host: true }; const ice = [{ urls: iceUrl, username: iceUsername, credential: icePassword }]; - await connect('polite', window.location.host, callerToken, () => clearInterval(ringInterval), () => clearInterval(aliveInterval), ice); + await connect('polite', audioId, window.location.host, callerToken, () => clearInterval(ringInterval), () => clearInterval(aliveInterval), ice); }, - enableVideo: async () => { + enableVideo: async (videoId) => { if (!accessVideo.current) { - const devices = await navigator.mediaDevices.enumerateDevices(); - console.log('>> ', devices); - - const stream = await navigator.mediaDevices.getUserMedia({ - video: true, - audio: true, - }); + const stream = await getVideoStream(videoId); accessVideo.current = true; accessAudio.current = true; updateState({ localStream: stream }); diff --git a/net/web/src/context/useSettingsContext.hook.js b/net/web/src/context/useSettingsContext.hook.js index 0ffa9521..f4ee7169 100644 --- a/net/web/src/context/useSettingsContext.hook.js +++ b/net/web/src/context/useSettingsContext.hook.js @@ -18,9 +18,9 @@ export function useSettingsContext() { strings: en, dateFormat: 'mm/dd', timeFormat: '12h', - audioInput: null, + audioId: null, audioInputs: [], - videoInput: null, + videoId: null, videoInputs: [], }); @@ -75,6 +75,7 @@ export function useSettingsContext() { getDevices('video').then(video => { updateState({ videoInputs: video }); }); + // eslint-disable-next-line }, [state.strings]); useEffect(() => { @@ -134,9 +135,9 @@ export function useSettingsContext() { } } - const audioInput = localStorage.getItem('audio_input'); - const videoInput = localStorage.getItem('video_input'); - updateState({ audioInput, videoInput }); + const audioId = localStorage.getItem('audio_input'); + const videoId = localStorage.getItem('video_input'); + updateState({ audioId, videoId }); return () => { window.removeEventListener('resize', handleResize); @@ -193,13 +194,13 @@ export function useSettingsContext() { localStorage.setItem('time_format', timeFormat); updateState({ timeFormat }); }, - setAudioInput: (audioInput) => { - localStorage.setItem('audio_input', audioInput); - updateState({ audioInput }); + setAudioInput: (audioId) => { + localStorage.setItem('audio_input', audioId); + updateState({ audioId }); }, - setVideoInput: (videoInput) => { - localStorage.setItem('video_input', videoInput); - updateState({ videoInput }); + setVideoInput: (videoId) => { + localStorage.setItem('video_input', videoId); + updateState({ videoId }); }, } diff --git a/net/web/src/session/account/profile/Profile.jsx b/net/web/src/session/account/profile/Profile.jsx index 6343aae7..932c925e 100644 --- a/net/web/src/session/account/profile/Profile.jsx +++ b/net/web/src/session/account/profile/Profile.jsx @@ -1,6 +1,6 @@ import { useRef, useCallback } from 'react'; import { Modal, Input, Button, Switch } from 'antd'; -import { LogoutContent, ProfileWrapper, ProfileDetailsWrapper, ProfileImageWrapper } from './Profile.styled'; +import { ProfileWrapper, ProfileDetailsWrapper, ProfileImageWrapper } from './Profile.styled'; import { useProfile } from './useProfile.hook'; import { Logo } from 'logo/Logo'; import { AccountAccess } from './accountAccess/AccountAccess'; @@ -52,24 +52,6 @@ export function Profile({ closeProfile }) { } } - const logout = () => { - modal.confirm({ - title: {state.strings.confirmLogout}, - icon: , - content: e.stopPropagation()}> - { state.strings.allDevices } - all.current = e} size="small" /> - , - bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, - okText: state.strings.ok, - onOk() { - actions.logout(all.current); - }, - cancelText: state.strings.cancel, - onCancel() {}, - }); - } - const onCropComplete = useCallback((area, crop) => { actions.setEditImageCrop(crop.width, crop.height, crop.x, crop.y) // eslint-disable-next-line @@ -135,12 +117,6 @@ export function Profile({ closeProfile }) { { state.display !== 'xlarge' && state.displaySet && (
- { state.display === 'small' && ( -
- -
{ state.strings.logout }
-
- )}
diff --git a/net/web/src/session/account/profile/Profile.styled.js b/net/web/src/session/account/profile/Profile.styled.js index a48c2fcc..19fa6765 100644 --- a/net/web/src/session/account/profile/Profile.styled.js +++ b/net/web/src/session/account/profile/Profile.styled.js @@ -200,38 +200,6 @@ export const ProfileWrapper = styled.div` padding: 8px; width: 75%; } - - .logout { - display: flex; - flex-direction: row; - align-items: center; - background-color: ${props => props.theme.selectedArea}; - padding: 8px; - border-radius: 4px; - justify-content: center; - - .icon { - color: ${props => props.theme.alertText}; - cursor: pointer; - } - - .label { - cursor: pointer; - padding-left: 8px; - } - } -` - -export const LogoutContent = styled.div` - display: flex; - align-items: center; - justify-content: center; - padding: 8px; - - .logoutMode { - padding-right: 8px; - color: ${props => props.theme.mainText}; - } ` export const ProfileDetailsWrapper = styled.div` diff --git a/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx b/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx index 9ffa2a0d..eb5925a2 100644 --- a/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx +++ b/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx @@ -1,12 +1,14 @@ -import { AccountAccessWrapper, LoginModal, SealModal } from './AccountAccess.styled'; +import { AccountAccessWrapper, LoginModal, SealModal, LogoutContent } from './AccountAccess.styled'; import { useAccountAccess } from './useAccountAccess.hook'; import { Button, Modal, Switch, Input, Radio, Select } from 'antd'; -import { SettingOutlined, UserOutlined, LockOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; +import { LogoutOutlined, SettingOutlined, UserOutlined, LockOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; +import { useRef } from 'react'; export function AccountAccess() { const [ modal, modalContext ] = Modal.useModal(); const { state, actions } = useAccountAccess(); + const all = useRef(false); const saveSeal = async () => { try { @@ -52,6 +54,24 @@ export function AccountAccess() { } } + const logout = () => { + modal.confirm({ + title: {state.strings.confirmLogout}, + icon: , + content: e.stopPropagation()}> + { state.strings.allDevices } + all.current = e} size="small" /> + , + bodyStyle: { borderRadius: 8, padding: 16, ...state.menuStyle }, + okText: state.strings.ok, + onOk() { + actions.logout(all.current); + }, + cancelText: state.strings.cancel, + onCancel() {}, + }); + } + return ( { modalContext } @@ -76,6 +96,14 @@ export function AccountAccess() {
{state.strings.changeLogin}
+ { state.display === 'small' && ( +
+
+ +
+
{ state.strings.logout }
+
+ )}
@@ -123,7 +151,7 @@ export function AccountAccess() { defaultValue={null} style={{ width: '60%' }} size="small" - value={state.audioInput} + value={state.audioId} onChange={actions.setAudio} options={[ { value: null, label: 'Default' }, ...state.audioInputs ]} /> @@ -134,7 +162,7 @@ export function AccountAccess() { defaultValue={null} style={{ width: '60%' }} size="small" - value={state.videoInput} + value={state.videoId} onChange={actions.setVideo} options={[ { value: null, label: 'Default' }, ...state.videoInputs ]} /> diff --git a/net/web/src/session/account/profile/accountAccess/AccountAccess.styled.js b/net/web/src/session/account/profile/accountAccess/AccountAccess.styled.js index 5677ada2..589a5251 100644 --- a/net/web/src/session/account/profile/accountAccess/AccountAccess.styled.js +++ b/net/web/src/session/account/profile/accountAccess/AccountAccess.styled.js @@ -39,7 +39,7 @@ export const AccountAccessWrapper = styled.div` .label { padding-right: 16px; - min-width: 130px; + min-width: 33%; height: 28px; display: flex; align-items: center; @@ -247,3 +247,14 @@ export const LoginModal = styled.div` } ` +export const LogoutContent = styled.div` + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + + .logoutMode { + padding-right: 8px; + color: ${props => props.theme.mainText}; + } +` diff --git a/net/web/src/session/account/profile/accountAccess/useAccountAccess.hook.js b/net/web/src/session/account/profile/accountAccess/useAccountAccess.hook.js index f18d8ea6..933b5f2b 100644 --- a/net/web/src/session/account/profile/accountAccess/useAccountAccess.hook.js +++ b/net/web/src/session/account/profile/accountAccess/useAccountAccess.hook.js @@ -27,6 +27,7 @@ export function useAccountAccess() { sealDelete: null, sealUnlock: null, + display: null, strings: {}, menuStyle: {}, timeFormat: '12h', @@ -35,9 +36,9 @@ export function useAccountAccess() { themes: [], language: null, languages: [], - audioInput: null, + audioId: null, audioInputs: [], - videoInput: null, + videoId: null, videoInputs: [], seal: null, @@ -65,21 +66,10 @@ export function useAccountAccess() { }, [account.state]); useEffect(() => { - const { audioInput, audioInputs, videoInput, videoInputs, strings, menuStyle, timeFormat, dateFormat, theme, themes, language, languages } = settings.state; - updateState({ audioInput, audioInputs, videoInput, videoInputs, strings, menuStyle, timeFormat, dateFormat, theme, themes, language, languages }); + const { display, audioId, audioInputs, videoId, videoInputs, strings, menuStyle, timeFormat, dateFormat, theme, themes, language, languages } = settings.state; + updateState({ display, audioId, audioInputs, videoId, videoInputs, strings, menuStyle, timeFormat, dateFormat, theme, themes, language, languages }); }, [settings.state]); - const showDevices = async () => { - const audio = await ring.actions.getDevices('audio'); - const video = await ring.actions.getDevices('video'); - - console.log('devices', audio, video); - }; - - useEffect(() => { - showDevices(); - }, []); - const sealUnlock = async () => { const unlocked = unlockSeal(state.seal, state.sealUnlock); await account.actions.unlockSeal(unlocked); diff --git a/net/web/src/session/cards/useCards.hook.js b/net/web/src/session/cards/useCards.hook.js index 87b1b2e6..e0062084 100644 --- a/net/web/src/session/cards/useCards.hook.js +++ b/net/web/src/session/cards/useCards.hook.js @@ -21,6 +21,7 @@ export function useCards() { menuStyle: {}, allowUnsealed: false, cards: [], + audioId: null, }); const ring = useContext(RingContext); @@ -35,8 +36,9 @@ export function useCards() { } useEffect(() => { - const { display, strings, menuStyle } = settings.state; - updateState({ display, strings, menuStyle }); + const { display, strings, menuStyle, audioId } = settings.state; +console.log("AUDIO ID: ", audioId); + updateState({ display, strings, menuStyle, audioId }); }, [settings.state]); useEffect(() => { @@ -164,7 +166,7 @@ export function useCards() { }, call: async (contact) => { const { cardId, node, guid, token } = contact; - await ring.actions.call(cardId, node, `${guid}.${token}`); + await ring.actions.call(cardId, node, `${guid}.${token}`, state.audioId); }, }; diff --git a/net/web/src/session/conversation/addTopic/AddTopic.styled.js b/net/web/src/session/conversation/addTopic/AddTopic.styled.js index 7cd8ecd2..6d03cfd2 100644 --- a/net/web/src/session/conversation/addTopic/AddTopic.styled.js +++ b/net/web/src/session/conversation/addTopic/AddTopic.styled.js @@ -53,8 +53,8 @@ export const AddTopicWrapper = styled.div` flex-align: center; justify-content: center; align-items: center; - width: 36px; - height: 36px; + width: 32px; + height: 32px; cursor: pointer; border: 1px solid ${props => props.theme.sectionBorder}; background-color: ${props => props.theme.inputArea}; @@ -63,7 +63,7 @@ export const AddTopicWrapper = styled.div` } .space { - margin-right: 8px; + margin-right: 12px; } .end { diff --git a/net/web/src/session/useSession.hook.js b/net/web/src/session/useSession.hook.js index c3007728..382fa5bc 100644 --- a/net/web/src/session/useSession.hook.js +++ b/net/web/src/session/useSession.hook.js @@ -32,6 +32,8 @@ export function useSession() { remoteStream: null, remoteVideo: false, remoteAudio: false, + audioId: null, + videoId: null, }); const app = useContext(AppContext); @@ -96,8 +98,8 @@ export function useSession() { }, [app.state]); useEffect(() => { - const { display, theme } = settings.state; - updateState({ display, theme }); + const { display, theme, audioId } = settings.state; + updateState({ display, theme, audioId }); }, [settings.state]); useEffect(() => { @@ -171,13 +173,13 @@ export function useSession() { accept: async (call) => { const { cardId, callId, contactNode, contactToken, calleeToken, iceUrl, iceUsername, icePassword } = call; const node = contactNode ? contactNode : window.location.host; - await ring.actions.accept(cardId, callId, node, contactToken, calleeToken, iceUrl, iceUsername, icePassword); + await ring.actions.accept(cardId, callId, node, contactToken, calleeToken, iceUrl, iceUsername, icePassword, state.audioId); }, end: async () => { await ring.actions.end(); }, enableVideo: async () => { - await ring.actions.enableVideo(); + await ring.actions.enableVideo(state.videoId, state.audioId); }, disableVideo: async () => { await ring.actions.disableVideo();