diff --git a/app/mobile/ios/Databag.xcodeproj/project.pbxproj b/app/mobile/ios/Databag.xcodeproj/project.pbxproj
index c36d2958..4400d142 100644
--- a/app/mobile/ios/Databag.xcodeproj/project.pbxproj
+++ b/app/mobile/ios/Databag.xcodeproj/project.pbxproj
@@ -571,7 +571,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "c++17";
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -643,7 +643,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "c++17";
+ CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
diff --git a/app/mobile/src/api/removeContactCall.js b/app/mobile/src/api/removeContactCall.js
index 2d2dd315..8e2a553f 100644
--- a/app/mobile/src/api/removeContactCall.js
+++ b/app/mobile/src/api/removeContactCall.js
@@ -1,6 +1,6 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
-export async function removeContactCall(server, token, calllId) {
+export async function removeContactCall(server, token, callId) {
const call = await fetchWithTimeout(`https://${server}/talk/calls/${callId}?contact=${token}`, { method: 'DELETE' });
checkResponse(call);
}
diff --git a/app/mobile/src/context/useRingContext.hook.js b/app/mobile/src/context/useRingContext.hook.js
index 2bbf3e57..7f53f7d3 100644
--- a/app/mobile/src/context/useRingContext.hook.js
+++ b/app/mobile/src/context/useRingContext.hook.js
@@ -71,7 +71,7 @@ export function useRingContext() {
updateState({ ringing: ringing.current });
}, EXPIRE);
},
- ignore: (cardId, callId) => {
+ ignore: async (cardId, callId) => {
const key = `${cardId}:${callId}`
const call = ringing.current.get(key);
if (call) {
diff --git a/app/mobile/src/session/Session.jsx b/app/mobile/src/session/Session.jsx
index 997d37e7..b2c6db44 100644
--- a/app/mobile/src/session/Session.jsx
+++ b/app/mobile/src/session/Session.jsx
@@ -1,4 +1,4 @@
-import { View, ScrollView, TouchableOpacity, StatusBar, Text, Image } from 'react-native';
+import { View, ScrollView, TouchableOpacity, StatusBar, Text, Image, Modal } from 'react-native';
import { useState, useEffect, useContext } from 'react';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
@@ -6,6 +6,7 @@ import { createDrawerNavigator } from '@react-navigation/drawer';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native';
import Ionicons from 'react-native-vector-icons/AntDesign';
+import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import { useSession } from './useSession.hook';
import { styles } from './Session.styled';
import Colors from 'constants/Colors';
@@ -22,6 +23,7 @@ import { ConversationContext } from 'context/ConversationContext';
import { ProfileContext } from 'context/ProfileContext';
import { ProfileIcon } from './profileIcon/ProfileIcon';
import { CardsIcon } from './cardsIcon/CardsIcon';
+import { Logo } from 'utils/Logo';
import splash from 'images/session.png';
const ConversationStack = createStackNavigator();
@@ -159,6 +161,7 @@ function ContactStackScreen() {
export function Session() {
+ const [ringing, setRinging] = useState([]);
const { state, actions } = useSession();
const drawerParams = { drawerPosition: 'right', headerShown: false, swipeEnabled: false, drawerType: 'front' };
@@ -310,6 +313,31 @@ export function Session() {
);
}
+ useEffect(() => {
+ let incoming = [];
+ for (let i = 0; i < state.ringing.length; i++) {
+ const { img, name, handle, callId, cardId, contactNode, contactToken, calleeToken } = state.ringing[i];
+ const label = name ? name : `${handle}@${contactNode}`;
+ const key = `${cardId}:${callId}`
+ incoming.push(
+
+
+ { label }
+ actions.ignore(cardId, callId)}>
+
+
+ actions.decline(cardId, contactNode, contactToken, callId)}>
+
+
+ actions.accept(cardId, callId, contactNode, contactToken, calleeToken)}>
+
+
+
+ );
+ }
+ setRinging(incoming);
+ }, [state.ringing]);
+
return (
@@ -379,6 +407,18 @@ export function Session() {
)}
+ 0}
+ supportedOrientations={['portrait', 'landscape']}
+ >
+
+
+ { ringing }
+
+
+
);
}
diff --git a/app/mobile/src/session/Session.styled.js b/app/mobile/src/session/Session.styled.js
index d13a93c9..2f36f45e 100644
--- a/app/mobile/src/session/Session.styled.js
+++ b/app/mobile/src/session/Session.styled.js
@@ -138,5 +138,53 @@ export const styles = StyleSheet.create({
fontSize: 18,
color: Colors.tetx,
},
+ ringBase: {
+ display: 'flex',
+ width: '100%',
+ height: '100%',
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: 'rgba(52, 52, 52, 0.8)'
+ },
+ ringFrame: {
+ backgroundColor: Colors.formBackground,
+ padding: 16,
+ width: '90%',
+ maxWidth: 400,
+ borderRadius: 4,
+ },
+ ringEntry: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ ringName: {
+ flexGrow: 1,
+ paddingLeft: 8,
+ paddingRight: 8,
+ },
+ ringIgnore: {
+ borderWidth: 1,
+ borderRadius: 20,
+ borderColor: Colors.text,
+ padding: 6,
+ marginRight: 4,
+ },
+ ringDecline: {
+ borderWidth: 1,
+ borderRadius: 20,
+ borderColor: Colors.alert,
+ padding: 6,
+ marginLeft: 8,
+ marginRight: 8,
+ },
+ ringAccept: {
+ borderWidth: 1,
+ borderRadius: 20,
+ borderColor: Colors.primary,
+ padding: 6,
+ marginLeft: 4,
+ },
});
diff --git a/app/mobile/src/session/useSession.hook.js b/app/mobile/src/session/useSession.hook.js
index 06ee8333..a6dcceb4 100644
--- a/app/mobile/src/session/useSession.hook.js
+++ b/app/mobile/src/session/useSession.hook.js
@@ -3,10 +3,13 @@ import { useWindowDimensions } from 'react-native';
import { useNavigate } from 'react-router-dom';
import config from 'constants/Config';
import { StoreContext } from 'context/StoreContext';
+import { CardContext } from 'context/CardContext';
+import { RingContext } from 'context/RingContext';
export function useSession() {
const [state, setState] = useState({
+ ringing: [],
tabbled: null,
subWidth: '50%',
baseWidth: '50%',
@@ -15,6 +18,8 @@ export function useSession() {
firstRun: null,
});
+ const ring = useContext(RingContext);
+ const card = useContext(CardContext);
const store = useContext(StoreContext);
const dimensions = useWindowDimensions();
const navigate = useNavigate();
@@ -24,6 +29,27 @@ export function useSession() {
setState((s) => ({ ...s, ...value }));
}
+ useEffect(() => {
+ const ringing = [];
+ const expired = Date.now();
+ ring.state.ringing.forEach(call => {
+ if (call.expires > expired && !call.status) {
+ const { callId, cardId, calleeToken } = call;
+ const contact = card.state.cards.get(cardId);
+ if (contact) {
+ const { imageSet, name, handle, node, guid } = contact.card?.profile || {};
+ const { token } = contact.card?.detail || {};
+ const contactToken = `${guid}.${token}`;
+ const img = imageSet ? card.actions.getCardImageUrl(cardId) : null;
+ ringing.push({ cardId, img, name, handle, contactNode: node, callId, contactToken, calleeToken });
+ }
+ }
+ });
+
+ const { callStatus, localStream, localVideo, localAudio, remoteStream, remoteVideo, remoteAudio } = ring.state;
+ updateState({ ringing, callStatus, localStream, localVideo, localAudio, remoteStream, remoteVideo, remoteAudio });
+ }, [ring.state]);
+
useEffect(() => {
checkFirstRun();
}, []);
@@ -55,6 +81,16 @@ export function useSession() {
updateState({ firstRun: false });
store.actions.setFirstRun();
},
+ ignore: async (cardId, callId) => {
+ await ring.actions.ignore(cardId, callId);
+ },
+ decline: async (cardId, contactNode, contactToken, callId) => {
+ await ring.actions.decline(cardId, contactNode, contactToken, callId);
+ },
+ accept: async (cardId, callId, contactNode, contactToken, calleeToken) => {
+ await ring.actions.accept(cardId, callId, contactNode, contactToken, calleeToken);
+ },
+
};
return { state, actions };