From 843a22c17b2dea61bd8eb2ace57476b85287225e Mon Sep 17 00:00:00 2001 From: balzack Date: Wed, 5 Apr 2023 22:27:33 -0700 Subject: [PATCH] invoking dm and call from contact list in mobile --- app/mobile/src/session/Session.jsx | 318 +++++++++--------- app/mobile/src/session/cards/Cards.jsx | 24 +- .../src/session/cards/cardItem/CardItem.jsx | 14 +- .../session/cards/cardItem/CardItem.styled.js | 7 + app/mobile/src/session/cards/useCards.hook.js | 7 + app/mobile/src/session/channels/Channels.jsx | 8 +- app/mobile/src/session/contact/Contact.jsx | 4 - .../src/session/contact/useContact.hook.js | 9 - app/mobile/src/session/useSession.hook.js | 18 + 9 files changed, 236 insertions(+), 173 deletions(-) diff --git a/app/mobile/src/session/Session.jsx b/app/mobile/src/session/Session.jsx index b939c3a1..f42a2db6 100644 --- a/app/mobile/src/session/Session.jsx +++ b/app/mobile/src/session/Session.jsx @@ -37,7 +37,7 @@ const CardDrawer = createDrawerNavigator(); const RegistryDrawer = createDrawerNavigator(); const Tab = createBottomTabNavigator(); -function ConversationStackScreen() { +function ConversationStackScreen({ dmChannel }) { const stackParams = { headerStyle: { backgroundColor: Colors.titleBackground }, headerBackTitleVisible: false }; const screenParams = { headerShown: true, headerTintColor: Colors.primary }; @@ -74,7 +74,7 @@ function ConversationStackScreen() { (screenParams)} > - {(props) => openConversation(props.navigation, cardId, channelId)} />} + {(props) => openConversation(props.navigation, cardId, channelId)} />} @@ -107,7 +107,7 @@ function ProfileStackScreen() { ); } -function ContactStackScreen() { +function ContactStackScreen({ addChannel }) { const stackParams = { headerStyle: { backgroundColor: Colors.titleBackground }, headerBackTitleVisible: false }; const screenParams = { headerShown: true, headerTintColor: Colors.primary }; @@ -140,7 +140,7 @@ function ContactStackScreen() { ( )}}> - {(props) => openContact(props.navigation, contact)} />} + {(props) => openContact(props.navigation, contact)} addChannel={addChannel} />} ( @@ -160,160 +160,172 @@ function ContactStackScreen() { ); } +function HomeScreen({ navParams }) { + + const drawerParams = { drawerPosition: 'right', headerShown: false, swipeEnabled: false, drawerType: 'front' }; + const conversation = useContext(ConversationContext); + const [channel, setChannel] = useState(false); + const [cardId, setCardId] = useState(); + const [channelId, setChannelId] = useState(); + + const setConversation = (card, channel) => { + (async () => { + conversation.actions.setConversation(card, channel); + setCardId(card); + setChannelId(channel); + setChannel(true); + navParams.cardNav.closeDrawer(); + })(); + }; + const closeConversation = () => { + conversation.actions.clearConversation(); + setCardId(null); + setChannelId(null); + setChannel(false); + }; + const openDetails = () => { + navParams.detailNav.openDrawer(); + }; + const openProfile = () => { + navParams.profileNav.openDrawer(); + } + const openCards = () => { + navParams.cardNav.openDrawer(); + } + + useEffect(() => { + navParams.detailNav.closeDrawer(); + setChannelId(null); + setCardId(null); + setChannel(false); + }, [navParams.closeCount]); + + return ( + + + + + + Profile + + + + Contacts + + + + + + + + { channel && ( + + + + )} + { !channel && ( + + )} + + + ) +} + +function CardDrawerScreen({ navParams }) { + const drawerParams = { drawerPosition: 'right', headerShown: false, swipeEnabled: false, drawerType: 'front' }; + const [dmChannel, setDmChannel] = useState(null); + const openContact = (contact) => { + navParams.setContact(contact); + navParams.contactNav.openDrawer(); + }; + const openRegistry = () => { + navParams.registryNav.openDrawer(); + }; + + return ( + ( + + + + )}> + + {(props) => } + + + ); +}; + +function RegistryDrawerScreen({ navParams }) { + const drawerParams = { drawerPosition: 'right', headerShown: false, swipeEnabled: false, drawerType: 'front' }; + const openContact = (contact) => { + navParams.setContact(contact); + navParams.contactNav.openDrawer(); + }; + + return ( + ( + + + + )}> + + {(props) => } + + + ); +}; + +function ContactDrawerScreen({ navParams }) { + const drawerParams = { drawerPosition: 'right', headerShown: false, swipeEnabled: false, drawerType: 'front' }; + const [contact, setContact] = useState(null); + + return ( + ( + + + + + + )}> + + {(props) => } + + + ); +} + +function DetailDrawerScreen({ navParams }) { + const drawerParams = { drawerPosition: 'right', headerShown: false, swipeEnabled: false, drawerType: 'front' }; + const [closeCount, setCloseCount] = useState(0); + const clearConversation = (navigation) => { + setCloseCount(closeCount+1); + }; + + return ( + ( + +
clearConversation(props.navigation)} /> + + )}> + + {(props) => } + + + ); +} + export function Session() { const [ringing, setRinging] = useState([]); const { state, actions } = useSession(); - const drawerParams = { drawerPosition: 'right', headerShown: false, swipeEnabled: false, drawerType: 'front' }; - const HomeScreen = ({ navParams }) => { - - const conversation = useContext(ConversationContext); - const [channel, setChannel] = useState(false); - const [cardId, setCardId] = useState(); - const [channelId, setChannelId] = useState(); - - const setConversation = (card, channel) => { - (async () => { - conversation.actions.setConversation(card, channel); - setCardId(card); - setChannelId(channel); - setChannel(true); - })(); - }; - const closeConversation = () => { - conversation.actions.clearConversation(); - setCardId(null); - setChannelId(null); - setChannel(false); - }; - const openDetails = () => { - navParams.detailNav.openDrawer(); - }; - const openProfile = () => { - navParams.profileNav.openDrawer(); - } - const openCards = () => { - navParams.cardNav.openDrawer(); - } - - useEffect(() => { - navParams.detailNav.closeDrawer(); - setChannelId(null); - setCardId(null); - setChannel(false); - }, [navParams.closeCount]); - - return ( - - - - - - Profile - - - - Contacts - - - - - - - - { channel && ( - - - - )} - { !channel && ( - - )} - - - ) - } - - const CardDrawerScreen = ({ navParams }) => { - const openContact = (contact) => { - navParams.setContact(contact); - navParams.contactNav.openDrawer(); - }; - const openRegistry = () => { - navParams.registryNav.openDrawer(); - }; - - return ( - ( - - - - )}> - - {(props) => } - - - ); + const [ dmChannel, setDmChannel ] = useState(null); + const addChannel = async (cardId) => { + const id = await actions.setDmChannel(cardId); + setDmChannel({ id }); }; - const RegistryDrawerScreen = ({ navParams }) => { - const openContact = (contact) => { - navParams.setContact(contact); - navParams.contactNav.openDrawer(); - }; - - return ( - ( - - - - )}> - - {(props) => } - - - ); - }; - - const ContactDrawerScreen = ({ navParams }) => { - const [contact, setContact] = useState(null); - - return ( - ( - - - - - - )}> - - {(props) => } - - - ); - } - - const DetailDrawerScreen = ({ navParams }) => { - const [closeCount, setCloseCount] = useState(0); - const clearConversation = (navigation) => { - setCloseCount(closeCount+1); - }; - - return ( - ( - -
clearConversation(props.navigation)} /> - - )}> - - {(props) => } - - - ); - } - useEffect(() => { let incoming = []; for (let i = 0; i < state.ringing.length; i++) { @@ -375,7 +387,7 @@ export function Session() { )}> - {(props) => } + {(props) => } )} @@ -399,9 +411,9 @@ export function Session() { tabBarActiveTintColor: Colors.white, tabBarInactiveTintColor: Colors.disabled, })}> - + } /> - + } /> )} diff --git a/app/mobile/src/session/cards/Cards.jsx b/app/mobile/src/session/cards/Cards.jsx index d565c99e..61fbf851 100644 --- a/app/mobile/src/session/cards/Cards.jsx +++ b/app/mobile/src/session/cards/Cards.jsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { FlatList, ScrollView, View, TextInput, TouchableOpacity, Text } from 'react-native'; +import { Alert, FlatList, ScrollView, View, TextInput, TouchableOpacity, Text } from 'react-native'; import { styles } from './Cards.styled'; import { useCards } from './useCards.hook'; import { SafeAreaView } from 'react-native-safe-area-context'; @@ -38,9 +38,22 @@ export function CardsHeader({ filter, setFilter, sort, setSort, openRegistry }) ); } -export function CardsBody({ filter, sort, openContact }) { +export function CardsBody({ filter, sort, openContact, addChannel }) { const { state, actions } = useCards(filter, sort); + const call = async (contact) => { + try { + actions.call(contact); + } + catch (err) { + console.log(err); + Alert.alert( + 'Failed to Call Contact', + 'Please try again.' + ) + } + } + return ( <> { state.cards.length == 0 && ( @@ -52,7 +65,8 @@ export function CardsBody({ filter, sort, openContact }) { } + renderItem={({ item }) => call(item)} message={() => addChannel(item.cardId)} />} keyExtractor={item => item.cardId} /> )} @@ -60,14 +74,14 @@ export function CardsBody({ filter, sort, openContact }) { ); } -export function Cards({ openRegistry, openContact }) { +export function Cards({ openRegistry, openContact, addChannel }) { const [filter, setFilter] = useState(); const [sort, setSort] = useState(false); return ( - + ); } diff --git a/app/mobile/src/session/cards/cardItem/CardItem.jsx b/app/mobile/src/session/cards/cardItem/CardItem.jsx index 3d1b2e9f..b4c51c68 100644 --- a/app/mobile/src/session/cards/cardItem/CardItem.jsx +++ b/app/mobile/src/session/cards/cardItem/CardItem.jsx @@ -1,8 +1,10 @@ import { Text, TouchableOpacity, View } from 'react-native'; import { Logo } from 'utils/Logo'; import { styles } from './CardItem.styled'; +import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons'; +import Colors from 'constants/Colors'; -export function CardItem({ item, openContact }) { +export function CardItem({ item, openContact, call, message }) { const select = () => { const { guid, name, handle, node, location, description, imageSet } = item; @@ -19,6 +21,16 @@ export function CardItem({ item, openContact }) { { item.name } { item.handle } + { item.status === 'connected' && ( + + + + + + + + + )} { item.status === 'connected' && item.offsync === 1 && ( )} diff --git a/app/mobile/src/session/cards/cardItem/CardItem.styled.js b/app/mobile/src/session/cards/cardItem/CardItem.styled.js index b316c21a..0b9545a1 100644 --- a/app/mobile/src/session/cards/cardItem/CardItem.styled.js +++ b/app/mobile/src/session/cards/cardItem/CardItem.styled.js @@ -66,5 +66,12 @@ export const styles = StyleSheet.create({ borderRadius: 4, backgroundColor: Colors.confirmed, }, + options: { + display: 'flex', + flexDirection: 'row', + }, + option: { + marginRight: 24, + }, }) diff --git a/app/mobile/src/session/cards/useCards.hook.js b/app/mobile/src/session/cards/useCards.hook.js index fcb0f712..4d53bba8 100644 --- a/app/mobile/src/session/cards/useCards.hook.js +++ b/app/mobile/src/session/cards/useCards.hook.js @@ -1,5 +1,6 @@ import { useState, useEffect, useRef, useContext } from 'react'; import { CardContext } from 'context/CardContext'; +import { RingContext } from 'context/RingContext'; export function useCards(filter, sort) { @@ -8,6 +9,7 @@ export function useCards(filter, sort) { }); const card = useContext(CardContext); + const ring = useContext(RingContext); const updateState = (value) => { setState((s) => ({ ...s, ...value })); @@ -26,6 +28,7 @@ export function useCards(filter, sort) { location: location, description: description, status: detail.status, + token: detail.token, offsync: item.offsync, blocked: item.blocked, offsync: item.offsync, @@ -85,6 +88,10 @@ export function useCards(filter, sort) { }, [card, filter, sort]); const actions = { + call: async (card) => { + const { cardId, guid, node, token } = card || {}; + await ring.actions.call(cardId, node, `${guid}.${token}`); + }, }; return { state, actions }; diff --git a/app/mobile/src/session/channels/Channels.jsx b/app/mobile/src/session/channels/Channels.jsx index e07e583a..e8948c66 100644 --- a/app/mobile/src/session/channels/Channels.jsx +++ b/app/mobile/src/session/channels/Channels.jsx @@ -7,7 +7,7 @@ import { Colors } from 'constants/Colors'; import { ChannelItem } from './channelItem/ChannelItem'; import { AddMember } from './addMember/AddMember'; -export function Channels({ cardId, channelId, navigation, openConversation }) { +export function Channels({ cardId, channelId, navigation, openConversation, dmChannel }) { const { state, actions } = useChannels(); @@ -26,6 +26,12 @@ export function Channels({ cardId, channelId, navigation, openConversation }) { } }; + useEffect(() => { + if (dmChannel?.id) { + openConversation(null, dmChannel.id); + } + }, [dmChannel]); + useEffect(() => { if (navigation) { navigation.setOptions({ diff --git a/app/mobile/src/session/contact/Contact.jsx b/app/mobile/src/session/contact/Contact.jsx index 3046e771..6670342a 100644 --- a/app/mobile/src/session/contact/Contact.jsx +++ b/app/mobile/src/session/contact/Contact.jsx @@ -198,10 +198,6 @@ export function ContactBody({ contact }) { Report Contact - - - Call Contact - )} { state.status === 'connecting' && ( diff --git a/app/mobile/src/session/contact/useContact.hook.js b/app/mobile/src/session/contact/useContact.hook.js index df6f2f37..92af0fe7 100644 --- a/app/mobile/src/session/contact/useContact.hook.js +++ b/app/mobile/src/session/contact/useContact.hook.js @@ -1,6 +1,5 @@ import { useState, useEffect, useRef, useContext } from 'react'; import { CardContext } from 'context/CardContext'; -import { RingContext } from 'context/RingContext'; import { getListingMessage } from 'api/getListingMessage'; import { getListingImageUrl } from 'api/getListingImageUrl'; import { addFlag } from 'api/addFlag'; @@ -23,7 +22,6 @@ export function useContact(contact) { }); const card = useContext(CardContext); - const ring = useContext(RingContext); const updateState = (value) => { setState((s) => ({ ...s, ...value })); @@ -153,13 +151,6 @@ export function useContact(contact) { resync: () => { card.actions.resync(contact.card); }, - ring: async () => { - console.log("calling!!"); - const contact = card.state.cards.get(state.cardId); - const { node, guid } = contact.card?.profile || {} - const { token } = contact.card?.detail || {} - await ring.actions.call(state.cardId, node, `${guid}.${token}`); - }, }; return { state, actions }; diff --git a/app/mobile/src/session/useSession.hook.js b/app/mobile/src/session/useSession.hook.js index 4231d9a1..80578343 100644 --- a/app/mobile/src/session/useSession.hook.js +++ b/app/mobile/src/session/useSession.hook.js @@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom'; import config from 'constants/Config'; import { StoreContext } from 'context/StoreContext'; import { CardContext } from 'context/CardContext'; +import { ChannelContext } from 'context/ChannelContext'; import { RingContext } from 'context/RingContext'; export function useSession() { @@ -27,6 +28,7 @@ export function useSession() { }); const ring = useContext(RingContext); + const channel = useContext(ChannelContext); const card = useContext(CardContext); const store = useContext(StoreContext); const dimensions = useWindowDimensions(); @@ -122,6 +124,22 @@ export function useSession() { disableAudio: async () => { await ring.actions.disableAudio(); }, + setDmChannel: async (cardId) => { + let channelId; + channel.state.channels.forEach((entry, id) => { + const cards = entry?.detail?.contacts?.cards || []; + const subject = entry?.detail?.data || ''; + const type = entry?.detail?.dataType || ''; + if (cards.length == 1 && cards[0] === cardId && type === 'superbasic' && subject === '{"subject":null}') { + channelId = entry.channelId; + } + }); + if (channelId != null) { + return channelId; + } + const conversation = await channel.actions.addChannel('superbasic', { subject: null }, [ cardId ]); + return conversation.id; + }, }; return { state, actions };