removing temp files

This commit is contained in:
Roland Osborne 2025-01-29 11:36:07 -08:00
parent e9d1a1e676
commit ceb9365bdd
6 changed files with 0 additions and 843 deletions

View File

@ -1,83 +0,0 @@
import {StyleSheet} from 'react-native';
import { Colors } from '../constants/Colors';
export const styles = StyleSheet.create({
blur: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
},
active: {
display: 'flex',
width: '100%',
height: '100%',
position: 'absolute',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgb(64,64,64)',
},
inactive: {
display: 'none',
width: '100%',
height: '100%',
position: 'absolute',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgb(64,64,64)',
},
container: {
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
call: {
width: '100%',
height: '100%',
display: 'flex',
},
image: {
width: '100%',
height: '100%',
borderRadius: 8,
},
frame: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 8,
overflow: 'hidden',
padding: 2,
position: 'absolute',
},
closeIcon: {
borderRadius: 8,
},
name: {
fontSize: 28,
minWidth: '50%',
color: '#aaaaaa',
paddingLeft: 16,
width: '100%',
textAlign: 'center',
},
overlap: {
display: 'flex',
flexDirection: 'row',
position: 'absolute',
alignItems: 'center',
justifyContent: 'center',
paddingBottom: 8,
paddingTop: 8,
gap: 32,
},
local: {
position: 'absolute',
right: 16,
width: '20%',
height: '20%',
},
});

View File

@ -1,170 +0,0 @@
import React, { useEffect, useState } from 'react';
import { useWindowDimensions, Image, SafeAreaView, Modal, ScrollView, View } from 'react-native';
import { Surface, Icon, Divider, Button, IconButton, Text, TextInput} from 'react-native-paper';
import {styles} from './Calling.styled';
import {useCalling} from './useCalling.hook';
import {BlurView} from '@react-native-community/blur';
import { Confirm } from '../confirm/Confirm';
import { ActivityIndicator } from 'react-native-paper';
import FastImage from 'react-native-fast-image'
import LinearGradient from 'react-native-linear-gradient';
import { Colors } from '../constants/Colors';
import { RTCView } from 'react-native-webrtc';
export function Calling({ callCard }: { callCard: string }) {
const { state, actions } = useCalling();
const [alert, setAlert] = useState(false);
const [connecting, setConnecting] = useState(false);
const [ending, setEnding] = useState(false);
const {height, width} = useWindowDimensions();
const [applyingVideo, setApplyingVideo] = useState(false);
const [applyingAudio, setApplyingAudio] = useState(false);
const toggleVideo = async () => {
if (!applyingVideo) {
setApplyingVideo(true);
try {
if (state.video && state.videoEnabled) {
await actions.disableVideo();
} else if (state.video && !state.videoEnabled) {
await actions.enableVideo();
}
} catch (err) {
console.log(err);
setAlert(true);
}
setApplyingVideo(false);
}
}
const toggleAudio = async () => {
if (!applyingAudio) {
setApplyingAudio(true);
try {
if (state.audio && state.audioEnabled) {
await actions.disableAudio();
} else if (state.audio && !state.audioEnabled) {
await actions.enableAudio();
}
} catch (err) {
console.log(err);
setAlert(true);
}
setApplyingAudio(false);
}
}
const end = async () => {
if (!ending) {
setEnding(true);
try {
await actions.end();
} catch (err) {
console.log(err);
setAlert(true);
}
setEnding(false);
}
}
const call = async (cardId: string) => {
if (!connecting) {
setConnecting(true);
try {
await actions.call(cardId);
} catch (err) {
console.log(err);
setAlert(true);
}
setConnecting(false);
}
}
const alertParams = {
title: state.strings.operationFailed,
prompt: state.strings.tryAgain,
cancel: {
label: state.strings.close,
action: () => {
setAlert(false);
},
},
};
useEffect(() => {
const { cardId } = callCard;
if (cardId) {
call(cardId);
}
}, [callCard]);
const overlap = (width + 128) > height;
const frameWidth = width > height ? height : width - 16;
const frameHeight = frameWidth;
const frameOffset = (height - frameHeight) / 8;
return (
<SafeAreaView style={(connecting || state.calling || state.ringing.length > 0 || alert) ? styles.active : styles.inactive}>
<View style={styles.container}>
{ connecting && !state.calling && (
<ActivityIndicator size={72} />
)}
{ state.calling && (
<View style={{ ...styles.frame, top: frameOffset, width: frameWidth, height: frameHeight }}>
<Image
style={styles.image}
resizeMode="contain"
source={{ uri: state.calling.imageUrl }}
onLayout={actions.loaded}
/>
{ state.loaded && (
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, top: 2, borderRadius: 8}} start={{x: 0, y: 0}} end={{x: 0, y: 0.5}} colors={['rgba(64,64,64,1)', 'rgba(64,64,64, 0)']}>
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, top: 2, borderRadius: 8}} start={{x: 0, y: 0}} end={{x: 0, y: 0.5}} colors={['rgba(64,64,64,1)', 'rgba(64,64,64, 0)']} />
</LinearGradient>
)}
{ state.loaded && (
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, bottom: 2, borderRadius: 8}} start={{x: 0, y: 0.5}} end={{x: 0, y: 1}} colors={['rgba(64,64,64,0)', 'rgba(64,64,64, 1)']}>
<LinearGradient style={{...styles.overlap, width: '100%', height: frameHeight / 2, bottom: 2, borderRadius: 8}} start={{x: 0, y: 0.5}} end={{x: 0, y: 1}} colors={['rgba(64,64,64,0)', 'rgba(64,64,64, 1)']} />
</LinearGradient>
)}
{ state.loaded && (
<LinearGradient style={{...styles.overlap, height: '100%', width: 16, right: 0}} start={{x: 0, y: 0}} end={{x: 1, y: 0}} colors={['rgba(64,64,64,0)', 'rgba(64,64,64, 1)']} />
)}
{ state.loaded && (
<LinearGradient style={{...styles.overlap, height: '100%', width: 16, left: 0}} start={{x: 1, y: 0}} end={{x: 0, y: 0}} colors={['rgba(64,64,64,0)', 'rgba(64,64,64, 1)']} />
)}
</View>
)}
{ state.calling && state.loaded && (
<View style={{ ...styles.overlap, top: 0 }}>
{ state.calling.name && (
<Text style={styles.name} adjustsFontSizeToFit={true} numberOfLines={1}>{ state.calling.name }</Text>
)}
{ !state.calling.name && (
<Text style={styles.name} adjustsFontSizeToFit={true} numberOfLines={1}>{ `${state.calling.handle}/${state.calling.node}` }</Text>
)}
</View>
)}
{ state.calling && state.loaded && (
<View style={{ ...styles.overlap, bottom: frameOffset }}>
<View style={{ paddingTop: 8, paddingBottom: 8, paddingLeft: 16, paddingRight: 16, gap: 16, display: 'flex', flexDirection: 'row', borderRadius: 16, backgroundColor: 'rgba(128,128,128,0.5)' }}>
<IconButton style={styles.closeIcon} iconColor="white" containerColor={Colors.primary} icon={state.audioEnabled ? 'microphone-off' : 'microphone'} loading={applyingAudio} disabled={!state.audio} compact="true" mode="contained" size={32} onPress={toggleAudio} />
<IconButton style={styles.closeIcon} iconColor="white" containerColor={Colors.primary} icon={state.videoEnabled ? 'video-off-outline' : 'video-outline'} loading={applyingVideo} disabled={!state.video} compact="true" mode="contained" size={32} onPress={toggleVideo} />
<IconButton style={styles.closeIcon} iconColor="white" containerColor={Colors.danger} icon="phone-hangup-outline" compact="true" mode="contained" size={32} onPress={end} />
</View>
</View>
)}
{ state.calling && state.loaded && state.local && (
<RTCView
style={styles.local}
mirror={true}
objectFit={'contain'}
streamURL={state.local.toURL()}
zOrder={2}
/>
)}
</View>
<Confirm show={alert} params={alertParams} />
</SafeAreaView>
);
}

View File

@ -1,303 +0,0 @@
import { useState, useContext, useEffect, useRef } from 'react'
import { DisplayContext } from '../context/DisplayContext';
import { AppContext } from '../context/AppContext'
import { ContextType } from '../context/ContextType'
import { Link, type Card } from 'databag-client-sdk';
import {
ScreenCapturePickerView,
RTCPeerConnection,
RTCIceCandidate,
RTCSessionDescription,
RTCView,
MediaStream,
MediaStreamTrack,
mediaDevices,
registerGlobals
} from 'react-native-webrtc';
export function useCalling() {
const app = useContext(AppContext) as ContextType;
const display = useContext(DisplayContext) as ContextType;
const call = useRef(null as { policy: string, peer: RTCPeerConnection, link: Link, candidates: RTCIceCandidate[] } | null);
const stream = useRef(null);
const [state, setState] = useState({
strings: {},
ringing: [],
calls: [],
cards: [],
calling: null as null | Card,
failed: false,
loaded: false,
panelOffset: 0,
local: null,
audio: null,
audioEnabled: false,
video: null,
videoEnabled: false,
videoAdded: false,
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const updateState = (value: any) => {
setState((s) => ({ ...s, ...value }))
}
useEffect(() => {
const calls = state.ringing
.map(ring => ({ callId: ring.callId, card: state.cards.find(card => ring.cardId === card.cardId) }) )
.filter(ring => (ring.card && !ring.card.blocked));
updateState({ calls });
}, [state.ringing, state.cards]);
useEffect(() => {
const { strings } = display.state;
updateState({ strings });
}, [display.state]);
const constraints = {
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: false,
VoiceActivityDetection: true
}
};
const linkStatus = async (status: string) => {
if (call.current) {
const { policy, peer, link } = call.current;
if (status === 'connected') {
try {
stream.current = await mediaDevices.getUserMedia({
audio: true,
video: {
frameRate: 30,
facingMode: 'user'
}
});
const audio = stream.current.getTracks().find(track => track.kind === 'audio');
const video = stream.current.getTracks().find(track => track.kind === 'video');
if (audio) {
audio.enabled = true;
peer.addTrack(audio, stream.current);
}
if (video) {
video.enabled = false;
}
updateState({ audio, video, audioAdded: true, audioEnabled: true, videoAdded: false, videoEnabled: false });
} catch (err) {
console.log(err);
updateState({ failed: true });
}
} else if (status === 'closed') {
try {
peer.close();
link.close();
} catch (err) {
console.log(err);
}
call.current = null;
stream.current = null;
updateState({ calling: null, failed: false, audio: null, video: null });
}
}
}
const linkMessage = async (message: any) => {
if (call.current) {
const { peer, link, candidates, policy } = call.current;
try {
if (message.description) {
if (message.description.type === 'offer' && peer.signalingState !== 'stable') {
if (policy === 'polite') {
const rollback = new RTCSessionDescription({ type: 'rollback' });
await peer.setLocalDescription(rollback);
} else {
return;
}
}
const offer = new RTCSessionDescription(message.description);
await peer.setRemoteDescription(offer);
if (message.description.type === 'offer') {
const description = await peer.createAnswer();
await peer.setLocalDescription(description);
link.sendMessage({ description });
}
for (const candidate of candidates) {
await peer.addIceCandidate(candidate);
};
candidates.length = 0;
} else if (message.candidate) {
const candidate = new RTCIceCandidate(message.candidate);
if (peer.remoteDescription == null) {
candidates.push(candidate);
} else {
await peer.addIceCandidate(candidate);
}
}
} catch (err) {
console.log(err);
updateState({ failed: true });
}
}
}
const peerCandidate = async (candidate) => {
if (call.current && candidate) {
const { link } = call.current;
await link.sendMessage({ candidate });
}
}
const peerNegotiate = async () => {
if (call.current) {
const { peer, link } = call.current;
const description = await peer.createOffer(constraints);
await peer.setLocalDescription(description);
await link.sendMessage({ description });
}
}
const transmit = (ice: { urls: string; username: string; credential: string }[]) => {
const peerConnection = new RTCPeerConnection({ iceServers: ice });
peerConnection.addEventListener( 'connectionstatechange', event => {
console.log("CONNECTION STATE", event);
});
peerConnection.addEventListener( 'icecandidate', event => {
peerCandidate(event.candidate);
});
peerConnection.addEventListener( 'icecandidateerror', event => {
console.log("ICE ERROR");
});
peerConnection.addEventListener( 'iceconnectionstatechange', event => {
console.log("ICE STATE CHANGE", event);
});
peerConnection.addEventListener( 'negotiationneeded', event => {
peerNegotiate();
});
peerConnection.addEventListener( 'signalingstatechange', event => {
console.log("ICE SIGNALING", event);
});
peerConnection.addEventListener( 'track', event => {
//stream.current.addTrack(event.track, stream.current);
});
return peerConnection;
}
useEffect(() => {
if (app.state.session) {
const setRinging = (ringing: { cardId: string, callId: string }[]) => {
updateState({ ringing });
}
const setContacts = (cards: Card[]) => {
updateState({ cards });
}
const ring = app.state.session.getRing();
ring.addRingingListener(setRinging);
const contact = app.state.session.getContact();
contact.addCardListener(setContacts);
return () => {
ring.removeRingingListener(setRinging);
contact.removeCardListener(setContacts);
}
}
}, [app.state.session]);
const actions = {
end: async () => {
if (!call.current) {
throw new Error('no active call');
}
const { link, peer } = call.current;
try {
peer.close();
link.close();
} catch (err) {
console.log(err);
}
call.current = null;
stream.current = null;
updateState({ calling: null, audio: null, video: null });
},
accept: async (callId: string, call: Call) => {
if (call.current) {
throw new Error('active call in progress');
}
const { cardId, node } = call;
const ring = app.state.session.getRing();
const link = await ring.accept(cardId, callId, node);
const ice = link.getIce();
const peer = transmit(ice);
const policy = 'impolite';
const candidates = [];
call.current = { policy, peer, link, candidates };
link.setStatusListener(linkStatus);
link.setMessageListener(linkMessage);
updateState({ calling: call.card });
},
call: async (cardId: string) => {
if (call.current) {
throw new Error('active call in proegress');
}
const card = state.cards.find(contact => contact.cardId === cardId);
if (!card) {
throw new Error('calling contact not found');
}
const contact = app.state.session.getContact();
const link = await contact.callCard(cardId);
const ice = link.getIce();
const peer = transmit(ice);
const policy = 'polite';
const candidates = [];
call.current = { policy, peer, link, candidates };
link.setStatusListener(linkStatus);
link.setMessageListener(linkMessage);
updateState({ calling: card });
},
loaded: (e) => {
const { width, height } = e.nativeEvent.layout;
if (width > (height + 80)) {
updateState({ panelOffset: 0, loaded: true });
} else {
updateState({ panelOffset: ((height - width) - 80) / 2, loaded: true });
}
},
enableAudio: async () => {
if (!call.current || !state.audio || !state.audioAdded) {
throw new Error('cannot unmute audio');
}
state.audio.enabled = true;
updateState({ audioEnabled: true });
},
disableAudio: () => {
if (!call.current || !state.audio || !state.audioAdded) {
throw new Error('cannot mute audio');
}
state.audio.enabled = false;
updateState({ audioEnabled: false });
},
enableVideo: () => {
if (!call.current || !state.video) {
throw new Error('cannot start video');
}
if (!state.videoAdded) {
call.current.peer.addTrack(state.video, stream.current);
const local = new MediaStream();
local.addTrack(state.video, local);
updateState({ local });
}
state.video.enabled = true;
updateState({ videoAdded: true, videoEnabled: true });
},
disableVideo: () => {
if (!call.current || !state.video) {
throw new Error('cannot stop video');
}
state.video.enabled = false;
updateState({ videoEnabled: false });
},
}
return { state, actions }
}

View File

@ -1 +0,0 @@
/Users/rolandosborne/Library/Developer/CoreSimulator/Devices/A017730F-AC73-4ABE-AE12-C105BCEA1AD5/data/Containers/Data/Application/DC451C73-674B-47A7-B70C-D76CB45E7F8C/Library/LocalDatabase/db_v239.db

View File

@ -1,213 +0,0 @@
import React, {useState} from 'react';
import {SafeAreaView, View, useColorScheme} from 'react-native';
import {styles} from './Session.styled';
import {BottomNavigation, Surface, Text} from 'react-native-paper';
import {Settings} from '../settings/Settings';
import {Channels} from '../channels/Channels';
import {Contacts} from '../contacts/Contacts';
import {Registry} from '../registry/Registry';
import {Profile, ContactParams} from '../profile/Profile';
import {Details} from '../details/Details';
import {Identity} from '../identity/Identity';
import {useSession} from './useSession.hook';
import {
NavigationContainer,
DefaultTheme,
DarkTheme,
} from '@react-navigation/native';
import {createDrawerNavigator} from '@react-navigation/drawer';
import { createStackNavigator } from '@react-navigation/stack';
const SettingsDrawer = createDrawerNavigator();
const ContactsDrawer = createDrawerNavigator();
const RegistryDrawer = createDrawerNavigator();
const ProfileDrawer = createDrawerNavigator();
const DetailsDrawer = createDrawerNavigator();
const ContactStack = createStackNavigator();
const TopicStack = createStackNavigator();
export function Session() {
const {state} = useSession();
const scheme = useColorScheme();
const [index, setIndex] = useState(0);
const [routes] = useState([
{
key: 'channels',
title: 'Channels',
focusedIcon: 'comment-multiple',
unfocusedIcon: 'comment-multiple-outline',
},
{
key: 'contacts',
title: 'Contacts',
focusedIcon: 'contacts',
unfocusedIcon: 'contacts-outline',
},
{
key: 'settings',
title: 'Settings',
focusedIcon: 'cog',
unfocusedIcon: 'cog-outline',
},
]);
const sessionNav = {strings: state.strings};
const ChannelsRoute = () => <Channels />;
const SettingsRoute = () => <Settings showLogout={true} />;
const renderScene = BottomNavigation.SceneMap({
channels: ChannelsRoute,
contacts: () => <ContactTab />,
settings: SettingsRoute,
});
return (
<View style={styles.screen}>
{state.layout !== 'large' && (
<NavigationContainer
theme={scheme === 'dark' ? DarkTheme : DefaultTheme}>
<BottomNavigation
screenOptions={{lazy: false}}
barStyle={{ height: 92 }}
labeled={false}
navigationState={{index, routes}}
onIndexChange={setIndex}
renderScene={renderScene}
/>
</NavigationContainer>
)}
{state.layout === 'large' && (
<NavigationContainer
theme={scheme === 'dark' ? DarkTheme : DefaultTheme}>
<DetailsScreen nav={sessionNav} />
</NavigationContainer>
)}
</View>
);
}
function ContactTab() {
return (
<SafeAreaView style={{ width: '100%', height: '100%' }}>
<ContactStack.Navigator initialRouteName="contacts" screenOptions={{ headerShown: false }}>
<ContactStack.Screen name="contacts" options={{ headerBackTitleVisible: false }}>
{(props) => <Contacts openRegistry={()=>{console.log('openreg')}} openContact={(params: ContactParams)=>{console.log('opencon', params)}} />}
</ContactStack.Screen>
</ContactStack.Navigator>
</SafeAreaView>
);
}
function DetailsScreen({nav}) {
return (
<DetailsDrawer.Navigator
id="DetailsDrawer"
drawerContent={Details}
screenOptions={{
drawerPosition: 'right',
drawerType: 'front',
headerShown: false,
}}>
<DetailsDrawer.Screen name="details">
{({navigation}) => (
<ProfileScreen nav={{...nav, details: navigation}} />
)}
</DetailsDrawer.Screen>
</DetailsDrawer.Navigator>
);
}
function ProfileScreen({nav}) {
return (
<ProfileDrawer.Navigator
id="ProfileDrawer"
drawerContent={Profile}
screenOptions={{
drawerPosition: 'right',
drawerType: 'front',
headerShown: false,
}}>
<ProfileDrawer.Screen name="registry">
{({navigation}) => (
<RegistryScreen nav={{...nav, profile: navigation}} />
)}
</ProfileDrawer.Screen>
</ProfileDrawer.Navigator>
);
}
function RegistryScreen({nav}) {
return (
<RegistryDrawer.Navigator
id="RegistryDrawer"
drawerContent={Registry}
screenOptions={{
drawerPosition: 'right',
drawerType: 'front',
headerShown: false,
}}>
<RegistryDrawer.Screen name="contacts">
{({navigation}) => (
<ContactsScreen nav={{...nav, registry: navigation}} />
)}
</RegistryDrawer.Screen>
</RegistryDrawer.Navigator>
);
}
function ContactsScreen({nav}) {
return (
<ContactsDrawer.Navigator
id="ContactsDrawer"
drawerContent={() => <Contacts onRegistry={()=>{console.log('openreg')}} openContact={(params: ContactParams)=>{console.log('opencon', params)}} />}
screenOptions={{
drawerPosition: 'right',
drawerType: 'front',
headerShown: false,
}}>
<ContactsDrawer.Screen name="settings">
{({navigation}) => (
<SettingsScreen nav={{...nav, contacts: navigation}} />
)}
</ContactsDrawer.Screen>
</ContactsDrawer.Navigator>
);
}
function SettingsScreen({nav}) {
return (
<SettingsDrawer.Navigator
id="SettingsDrawer"
drawerContent={Settings}
screenOptions={{
drawerStyle: {width: '40%'},
drawerPosition: 'right',
drawerType: 'front',
headerShown: false,
}}>
<SettingsDrawer.Screen name="home">
{({navigation}) => <HomeScreen nav={{...nav, settings: navigation}} />}
</SettingsDrawer.Screen>
</SettingsDrawer.Navigator>
);
}
function HomeScreen({nav}) {
return (
<View style={styles.frame}>
<View style={styles.left}>
<Surface elevation={2} mode="flat">
<Identity openSettings={nav.settings.openDrawer} />
</Surface>
<Surface style={styles.channels} elevation={1} mode="flat">
<Text>CHANNELS</Text>
</Surface>
</View>
<View style={styles.right}>
<Text>CONVERSATION</Text>
</View>
</View>
);
}

View File

@ -1,73 +0,0 @@
message:
| header
| share
| edit
| delete
| block
| report
| text
| carousel
| image
| audio
| video
| binary
| sanitize and tap
| unlock seal while open
| thumb as object not callback
| show skeleton until confirmed
| show skeleton until asset ready
add:
| text
| carousel
| image
| audio
| video
| binary
header:
| status icons
| details icon
details:
| subject
| actions
| members
channels:
- use names
| highlight active
| sdk dont parse unconfirmed: warn: invalid sealed topic
| show unseale summary
contacts:
| avoid self connection
| direct message
settings:
| blocked items
*****
contact indicator
call module
welcome component
node admin
share sheet [mobile]
splash screen [mobile]
avoid flash of access [mobile]
tool tips [web]
manage block entities
persist offsync contacts [web]
merge strings
light theme
*****
fdroid w/ unified push support
deploy docker/ios/android/fdroid/openwrt
api updates
group management
reactions and read receipt
photo album
music playlist
repeater bot