passing share intent to selected topic

This commit is contained in:
balzack 2023-04-22 09:54:53 -07:00
parent 9dbd64833b
commit e3bf231b32
11 changed files with 264 additions and 26 deletions

View File

@ -39,7 +39,6 @@ export default function App() {
const clearSharing = () => {
setSharing(null);
ReceiveSharingIntent.clearReceivedFiles();
};
return (

View File

@ -16,6 +16,7 @@ export const Colors = {
disabled: '#aaaaaa',
text: '#444444',
link: '#0077CC',
lightText: '#686868',
active: '#222222',
idle: '#707070',

View File

@ -39,7 +39,7 @@ const CardDrawer = createDrawerNavigator();
const RegistryDrawer = createDrawerNavigator();
const Tab = createBottomTabNavigator();
function ConversationStackScreen({ dmChannel }) {
function ConversationStackScreen({ dmChannel, shareChannel, shareIntent, setShareIntent }) {
const stackParams = { headerStyle: { backgroundColor: Colors.titleBackground }, headerBackTitleVisible: false };
const screenParams = { headerShown: true, headerTintColor: Colors.primary };
@ -76,11 +76,11 @@ function ConversationStackScreen({ dmChannel }) {
<ConversationStack.Navigator initialRouteName="channels" screenOptions={({ route }) => (screenParams)} >
<ConversationStack.Screen name="channels" options={stackParams}>
{(props) => <Channels navigation={props.navigation} dmChannel={dmChannel} openConversation={(cardId, channelId) => openConversation(props.navigation, cardId, channelId)} />}
{(props) => <Channels navigation={props.navigation} dmChannel={dmChannel} shareChannel={shareChannel} openConversation={(cardId, channelId) => openConversation(props.navigation, cardId, channelId)} />}
</ConversationStack.Screen>
<ConversationStack.Screen name="conversation" options={stackParams}>
{(props) => <Conversation navigation={props.navigation} openDetails={() => openDetails(props.navigation)} closeConversation={(pop) => closeConversation(props.navigation, pop)} /> }
{(props) => <Conversation navigation={props.navigation} openDetails={() => openDetails(props.navigation)} closeConversation={(pop) => closeConversation(props.navigation, pop)} shareIntent={shareIntent} setShareIntent={setShareIntent} /> }
</ConversationStack.Screen>
<ConversationStack.Screen name="details" options={{ ...stackParams, headerTitle: (props) => (
@ -216,13 +216,13 @@ function HomeScreen({ navParams }) {
</TouchableOpacity>
</View>
<View style={styles.channels}>
<Channels dmChannel={navParams.dmChannel} cardId={cardId} channelId={channelId} openConversation={setConversation} />
<Channels dmChannel={navParams.dmChannel} shareChannel={shareChannel} cardId={cardId} channelId={channelId} openConversation={setConversation} />
</View>
</SafeAreaView>
<View style={styles.conversation}>
{ channel && (
<SafeAreaView edges={['top', 'bottom', 'right']}>
<Conversation closeConversation={closeConversation} openDetails={openDetails} />
<Conversation closeConversation={closeConversation} openDetails={openDetails} shareIntent={navParams.shareIntent} setShareIntent={navParams.setShareIntent} />
</SafeAreaView>
)}
{ !channel && (
@ -330,17 +330,18 @@ export function Session({ sharing, clearSharing }) {
setDmChannel({ id });
};
const setShare = async (cardId, channelId) => {
console.log("SET SHARE CHANNEL");
const [shareIntent, setShareIntent] = useState(null);
const [shareChannel, setShareChannel] = useState(null);
const setShare = async ({ cardId, channelId }) => {
setShareIntent(sharing);
setShareChannel({ cardId, channelId });
clearSharing();
}
const clearShare = async () => {
console.log("CLEAR SHARE CHANNEL");
clearSharing();
}
useEffect(() => {
console.log("COMPARE", sharing, intent);
if (sharing != intent && sharing != null) {
navigate('/');
}
@ -408,7 +409,7 @@ export function Session({ sharing, clearSharing }) {
<ScrollView style={styles.drawer}><SafeAreaView edges={['top', 'bottom', 'right']}><Profile /></SafeAreaView></ScrollView>
)}>
<ProfileDrawer.Screen name="detail">
{(props) => <DetailDrawerScreen navParams={{ profileNav: props.navigation, state, actions, addChannel, dmChannel }} />}
{(props) => <DetailDrawerScreen navParams={{ profileNav: props.navigation, state, actions, addChannel, dmChannel, shareChannel, shareIntent, setShareIntent }} />}
</ProfileDrawer.Screen>
</ProfileDrawer.Navigator>
)}
@ -432,7 +433,7 @@ export function Session({ sharing, clearSharing }) {
tabBarActiveTintColor: Colors.white,
tabBarInactiveTintColor: Colors.disabled,
})}>
<Tab.Screen name="Conversation" children={()=><ConversationStackScreen dmChannel={dmChannel} />} />
<Tab.Screen name="Conversation" children={()=><ConversationStackScreen dmChannel={dmChannel} shareChannel={shareChannel} shareIntent={shareIntent} setShareIntent={setShareIntent} />} />
<Tab.Screen name="Profile" component={ProfileStackScreen} />
<Tab.Screen name="Contacts" children={()=><ContactStackScreen addChannel={addChannel} />} />
</Tab.Navigator>
@ -464,7 +465,7 @@ export function Session({ sharing, clearSharing }) {
<Modal
animationType="fade"
transparent={true}
visible={intent != null}
visible={sharing != null && intent != null}
supportedOrientations={['portrait', 'landscape']}
>
<Sharing select={setShare} cancel={clearShare} />

View File

@ -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, dmChannel }) {
export function Channels({ cardId, channelId, navigation, openConversation, dmChannel, shareChannel }) {
const { state, actions } = useChannels();
@ -32,6 +32,12 @@ export function Channels({ cardId, channelId, navigation, openConversation, dmCh
}
}, [dmChannel]);
useEffect(() => {
if (shareChannel) {
openConversation(shareChannel.cardId, shareChannel.channelId);
}
}, [shareChannel]);
useEffect(() => {
if (navigation) {
navigation.setOptions({

View File

@ -2,7 +2,6 @@ import { Text, View } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { Logo } from 'utils/Logo';
import { styles } from './ChannelItem.styled';
import { useChannelItem } from './useChannelItem.hook';
import Colors from 'constants/Colors';
import Ionicons from 'react-native-vector-icons/MaterialCommunityIcons';

View File

@ -9,7 +9,7 @@ import { Logo } from 'utils/Logo';
import { AddTopic } from './addTopic/AddTopic';
import { TopicItem } from './topicItem/TopicItem';
export function Conversation({ navigation, cardId, channelId, closeConversation, openDetails }) {
export function Conversation({ navigation, cardId, channelId, closeConversation, openDetails, shareIntent, setShareIntent }) {
const { state, actions } = useConversation();
@ -113,7 +113,7 @@ export function Conversation({ navigation, cardId, channelId, closeConversation,
</View>
)}
</View>
<AddTopic contentKey={state.contentKey} />
<AddTopic contentKey={state.contentKey} shareIntent={shareIntent} setShareIntent={setShareIntent} />
</View>
<Modal
animationType="fade"

View File

@ -1,5 +1,5 @@
import { ActivityIndicator, Modal, Image, FlatList, TextInput, Alert, View, TouchableOpacity, Text, } from 'react-native';
import { useState, useRef } from 'react';
import { useState, useRef, useEffect } from 'react';
import { useAddTopic } from './useAddTopic.hook';
import { styles } from './AddTopic.styled';
import AntIcons from 'react-native-vector-icons/AntDesign';
@ -13,10 +13,35 @@ import { VideoFile } from './videoFile/VideoFile';
import { AudioFile } from './audioFile/AudioFile';
import { ImageFile } from './imageFile/ImageFile';
export function AddTopic({ contentKey }) {
export function AddTopic({ contentKey, shareIntent, setShareIntent }) {
const { state, actions } = useAddTopic(contentKey);
useEffect(() => {
if (shareIntent) {
Alert.alert('SHARING', JSON.stringify(shareIntent));
shareIntent.forEach(share => {
if (share.text) {
actions.setMessage(share.text);
}
if (share.weblink) {
actions.setMessage(share.weblink);
}
const mimeType = share.mimeType?.toLowerCase();
if (mimeType === '.jpg' || mimeType === '.png') {
actions.addImage(share.filePath)
}
if (mimeType === '.mp4') {
actions.addVideo(share.filePath)
}
if (mimeType === '.mp3') {
actions.addAudio(share.filePath)
}
});
setShareIntent(null);
}
}, [shareIntent]);
const addImage = async () => {
try {
const full = await ImagePicker.openPicker({ mediaType: 'photo' });

View File

@ -289,9 +289,9 @@ export function useTopicItem(item, hosting, remove, contentKey) {
}
}
await Share.open({ urls: files, message: data.text, title: 'Databag', subject: 'Shared from Databag' })
await Share.open({ urls: files, message: files.length > 0 ? null : data.text, title: 'Databag', subject: 'Shared from Databag' })
while (unlink.length > 0) {
const file = fs.unlink.shift();
const file = unlink.shift();
await fs.unlink(file);
}
}

View File

@ -1,15 +1,42 @@
import { Text, View } from 'react-native';
import { useState } from 'react';
import { TouchableOpacity, Text, View, FlatList } from 'react-native';
import { useSharing } from './useSharing.hook';
import { styles } from './Sharing.styled';
import { SharingItem } from './sharingItem/SharingItem';
export function Sharing({ setShare, clearShare }) {
export function Sharing({ select, cancel }) {
const [selection, setSelection] = useState(null);
const { state, actions } = useSharing();
return (
<View style={styles.sharingBase}>
<View style={styles.sharingFrame}>
<Text>SHARING</Text>
<View style={styles.header}>
<Text style={styles.headerText}>Select Topic for Sharing</Text>
</View>
<FlatList
style={styles.content}
data={state.channels}
initialNumToRender={25}
renderItem={({ item }) => <SharingItem select={setSelection} selection={selection} item={item} />}
keyExtractor={item => (`${item.cardId}:${item.channelId}`)}
/>
<View style={styles.controls}>
{ !selection && (
<View style={styles.disabled}>
<Text style={styles.disabledText}>Select</Text>
</View>
)}
{ selection && (
<TouchableOpacity style={styles.select} onPress={() => select(selection)}>
<Text style={styles.selectText}>Select</Text>
</TouchableOpacity>
)}
<TouchableOpacity style={styles.cancel} onPress={cancel}>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
</View>
</View>
</View>
)

View File

@ -12,10 +12,81 @@ export const styles = StyleSheet.create({
},
sharingFrame: {
backgroundColor: Colors.formBackground,
padding: 8,
width: '80%',
height: '80%',
maxWidth: 400,
maxHeight: 600,
borderRadius: 4,
display: 'flex',
alignItems: 'center',
},
header: {
padding: 8,
borderBottomWidth: 1,
borderColor: Colors.divider,
width: '100%',
alignItems: 'center',
},
headerText: {
fontSize: 18,
},
content: {
width: '100%',
flexGrow: 1,
flexShrink: 1,
},
controls: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
width: '100%',
padding: 4,
borderTopWidth: 1,
borderColor: Colors.divider,
},
select: {
borderRadius: 3,
borderWidth: 1,
borderColor: Colors.primary,
backgroundColor: Colors.primary,
paddingLeft: 16,
paddingRight: 16,
paddingTop: 4,
paddingBottom: 4,
margin: 8,
},
selectText: {
fontSize: 16,
color: Colors.white,
},
disabled: {
borderRadius: 3,
borderWidth: 1,
borderColor: Colors.grey,
paddingLeft: 16,
paddingRight: 16,
paddingTop: 4,
paddingBottom: 4,
margin: 8,
},
disabledText: {
fontSize: 16,
color: Colors.grey,
},
cancel: {
borderRadius: 3,
borderWidth: 1,
borderColor: Colors.text,
paddingLeft: 16,
paddingRight: 16,
paddingTop: 4,
paddingBottom: 4,
margin: 8,
},
cancelText: {
fontSize: 16,
color: Colors.text,
},
});

View File

@ -1,16 +1,125 @@
import { useState } from 'react';
import { useState, useRef, useEffect, useContext } from 'react';
import { ChannelContext } from 'context/ChannelContext';
import { CardContext } from 'context/CardContext';
import { AccountContext } from 'context/AccountContext';
import { ProfileContext } from 'context/ProfileContext';
import { getChannelSeals, isUnsealed, getContentKey, encryptChannelSubject, decryptChannelSubject, decryptTopicSubject } from 'context/sealUtil';
import { getCardByGuid } from 'context/cardUtil';
import { getChannelSubjectLogo } from 'context/channelUtil';
export function useSharing() {
const [state, setState] = useState({
channels: [],
});
const channel = useContext(ChannelContext);
const card = useContext(CardContext);
const account = useContext(AccountContext);
const profile = useContext(ProfileContext);
const resync = useRef(false);
const syncing = useRef(false);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
const setChannelItem = async (cardId, channelId, item) => {
const timestamp = item.summary.lastTopic.created;
// decrypt subject and message
let locked = false;
let unlocked = false;
if (item.detail.dataType === 'sealed') {
locked = true;
const seals = getChannelSeals(item.detail.data);
if (isUnsealed(seals, account.state.sealKey)) {
unlocked = true;
}
}
let message;
if (item?.detail?.dataType === 'sealed') {
if (typeof item?.unsealedSummary?.message?.text === 'string') {
message = item.unsealedSummary.message.text;
}
}
if (item.detail.dataType === 'superbasic') {
if (item.summary.lastTopic.dataType === 'superbasictopic') {
try {
const data = JSON.parse(item.summary.lastTopic.data);
if (typeof data.text === 'string') {
message = data.text;
}
}
catch(err) {
console.log(err);
}
}
}
const profileGuid = profile.state?.identity?.guid;
const { logo, subject } = getChannelSubjectLogo(cardId, profileGuid, item, card.state.cards, card.actions.getCardImageUrl);
return { cardId, channelId, subject, message, logo, timestamp, locked, unlocked };
}
useEffect(() => {
syncChannels();
}, [account.state, card.state, channel.state]);
const syncChannels = async () => {
if (syncing.current) {
resync.current = true;
}
else {
syncing.current = true;
const items = [];
channel.state.channels.forEach((item, channelId) => {
items.push({ channelId, channelItem: item });
});
card.state.cards.forEach((cardItem, cardId) => {
cardItem.channels.forEach((channelItem, channelId) => {
items.push({ cardId, channelId, channelItem });
});
});
const channels = [];
for (let i = 0; i < items.length; i++) {
const { cardId, channelId, channelItem } = items[i];
channels.push(await setChannelItem(cardId, channelId, channelItem));
}
const filtered = channels.filter(item => {
if (!item.locked || item.unlocked) {
return true;
}
return false;
});
const sorted = filtered.sort((a, b) => {
const aCreated = a?.timestamp;
const bCreated = b?.timestamp;
if (aCreated === bCreated) {
return 0;
}
if (!aCreated || aCreated < bCreated) {
return 1;
}
return -1;
});
updateState({ channels: sorted });
syncing.current = false;
if(resync.current) {
resync.current = false;
await syncChannels();
}
}
};
const actions = {
};
return { state, actions };
}