passing shared item to conversation

This commit is contained in:
balzack 2025-02-24 21:50:41 -08:00
parent cc4fd187bb
commit b30ff56093
9 changed files with 245 additions and 20 deletions

View File

@ -1,5 +1,5 @@
import React, { useEffect, useRef } from 'react';
import {Text, StatusBar} from 'react-native';
import React, { useState, useEffect, useRef } from 'react';
import {Alert, Text, StatusBar} from 'react-native';
import {AppContextProvider} from './src/context/AppContext';
import {DisplayContextProvider} from './src/context/DisplayContext';
import {NativeRouter} from 'react-router-native';
@ -102,10 +102,14 @@ const databagColors = {
function App(): React.JSX.Element {
const colorScheme = useColorScheme();
const [share, setShare] = useState(null as null | { filePath: string, mimeType: string });
useEffect(() => {
ReceiveSharingIntent.getReceivedFiles(files => {
console.log("GOT FILES!!!", files);
if (files && files.length) {
const { filePath, mimeType } = files[0];
setShare({ filePath, mimeType });
}
},
(error) =>{
console.log(error);
@ -134,7 +138,7 @@ function App(): React.JSX.Element {
<Route path="/" element={<Text>EMPTY</Text>} />
<Route path="/access" element={<Access />} />
<Route path="/service" element={<Service />} />
<Route path="/session" element={<Session />} />
<Route path="/session" element={<Session share={share} />} />
</Routes>
</NativeRouter>
</PaperProvider>

View File

@ -20,6 +20,7 @@ export const en = {
setup: 'Setup',
accounts: 'Accounts',
noAccounts: 'No Accounts',
selectShare: 'Select Sharing Topic',
membership: 'Membership',
channelGuest: 'Topic Guest',
@ -313,6 +314,7 @@ export const fr = {
setup: 'Installation',
accounts: 'Comptes',
noAccounts: 'Aucun Compte',
selectShare: 'Sélectionnez le Sujet de Partage',
addingTitle: 'Ajout d\'un Compte',
addingLink: 'Utilisez le lien suivant pour créer un compte',
@ -601,6 +603,7 @@ export const sp = {
setup: 'Configuración',
accounts: 'Cuentas',
noAccounts: 'No hay cuentas',
selectShare: 'Seleccionar Tema Para Compartir',
addingTitle: 'Añadiendo cuenta',
addingLink: 'Utilice el siguiente enlace para crear una cuenta',
@ -889,6 +892,7 @@ export const pt = {
setup: 'configurar',
accounts: 'Contas',
noAccounts: 'Sem Contas',
selectShare: 'Selecione o Tópico de Compartilhamento',
addingTitle: 'Adicionando conta',
addingLink: 'Use o seguinte link para criar uma conta',
@ -1178,7 +1182,8 @@ export const de = {
setup: 'Aufstellen',
accounts: 'Konten',
noAccounts: 'Keine Konten',
selectShare: 'Wählen Sie Das Thema Zum Teilen Aus',
addingTitle: 'Konto hinzufügen',
addingLink: 'Verwenden Sie den folgenden Link, um ein Konto zu erstellen',
addingToken: 'Verwenden Sie das folgende Token, um ein Konto vom Anmeldebildschirm aus zu erstellen',
@ -1466,6 +1471,7 @@ export const ru = {
setup: 'настраивать',
accounts: 'Учетные записи',
noAccounts: 'Нет учетных записей',
selectShare: 'Выберите тему для обмена',
addingTitle: 'Добавление аккаунта',
addingLink: 'Используйте следующую ссылку для создания аккаунта',

View File

@ -8,8 +8,9 @@ import {Focus} from 'databag-client-sdk';
import {BlurView} from '@react-native-community/blur';
import {Card} from '../card/Card';
import {Confirm} from '../confirm/Confirm';
import {Selector} from '../selector/Selector';
export function Content({openConversation, textCard}: {openConversation: ()=>void, textCard: {cardId: null|string}}) {
export function Content({share, closeAll, openConversation, textCard}: { share: { filePath: string, mimeType: string}, closeAll: ()=>void, openConversation: ()=>void, textCard: {cardId: null|string}}) {
const [add, setAdd] = useState(false);
const [adding, setAdding] = useState(false);
const [sealedTopic, setSealedTopic] = useState(false);
@ -28,6 +29,17 @@ export function Content({openConversation, textCard}: {openConversation: ()=>voi
});
const cards = state.sealSet && sealedTopic ? state.sealable : state.connected;
const select = (cardId: string, channelId: string) => {
actions.setFocus(cardId, channelId);
openConversation();
}
useEffect(() => {
if (share) {
closeAll();
}
}, [share]);
useEffect(() => {
if (textCard.cardId) {
openTopic(textCard.cardId);
@ -105,8 +117,7 @@ export function Content({openConversation, textCard}: {openConversation: ()=>voi
renderItem={({item}) => {
const {sealed, focused, hosted, unread, imageUrl, subject, message} = item;
const open = () => {
actions.setFocus(item.cardId, item.channelId);
openConversation();
select(item.cardId, item.channelId);
};
const Wrap = (state.layout === 'large' && focused) ? Surface : View;
return (
@ -231,6 +242,7 @@ export function Content({openConversation, textCard}: {openConversation: ()=>voi
</View>
</Modal>
<Confirm show={alert} params={alertParams} />
<Selector share={share} selected={select} channels={state.channels} />
</View>
);
}

View File

@ -29,6 +29,7 @@ export function useContent() {
connected: [] as Card[],
sealable: [] as Card[],
sorted: [] as Channel[],
channels: [] as ChannelParams[],
filtered: [] as ChannelParams[],
filter: '',
topic: '',
@ -158,7 +159,7 @@ export function useContent() {
return true;
});
updateState({filtered});
updateState({channels, filtered});
}, [state.sorted, state.cards, state.guid, state.filter, state.focused]);
useEffect(() => {

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { SafeAreaView, Platform, Modal, ScrollView, View } from 'react-native';
import {useTheme, Switch, Surface, Icon, Divider, Button, IconButton, Text, TextInput} from 'react-native-paper';
import {styles} from './Details.styled';

View File

@ -0,0 +1,80 @@
import {StyleSheet} from 'react-native';
import { Colors } from '../constants/Colors';
export const styles = StyleSheet.create({
modal: {
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
blur: {
position: 'absolute',
width: '100%',
height: '100%',
},
content: {
position: 'relative',
width: '80%',
display: 'flex',
flexDirection: 'column',
borderRadius: 8,
},
data: {
width: '100%',
paddingLeft: 16,
paddingRight: 16,
},
channels: {
minHeight: 100,
maxHeight: 400,
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 8,
overflow: 'hidden'
},
header: {
width: '100%',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
title: {
flexGrow: 1,
paddingLeft: 16,
fontSize: 20,
},
close: {
backgroundColor: 'transparent',
},
controls: {
display: 'flex',
flexDirection: 'row',
gap: 16,
justifyContent: 'flex-end',
padding: 16,
},
empty: {
fontSize: 18,
color: Colors.placeholder,
},
control: {
borderRadius: 4,
},
list: {
width: '100%',
height: 200,
},
channel: {
width: '100%',
height: 48,
paddingTop: 8,
paddingBottom: 8,
paddingRight: 16,
paddingLeft: 16,
borderBottomWidth: 1,
},
});

View File

@ -0,0 +1,92 @@
import React, { useEffect, useState } from 'react';
import { Modal, View, FlatList } from 'react-native';
import {useTheme, Surface, Button, Text, IconButton} from 'react-native-paper';
import {BlurView} from '@react-native-community/blur';
import { styles } from './Selector.styled';
import { useSelector } from './useSelector.hook';
import { ChannelParams } from '../content/Content';
import { Channel } from '../channel/Channel';
export function Selector({ share, selected, channels }: { share: { filePath: string, mimeType: string }, selected: (cardId: string, channelId: string)=>void, channels: ChannelParams[] }) {
const { state, actions } = useSelector();
const [show, setShow] = useState(false);
const theme = useTheme();
const [topic, setTopic] = useState(null as null | { cardId: string, channelId: stirng});
useEffect(() => {
if (share) {
setShow(true);
}
}, [share]);
const select = () => {
const { cardId, channelId } = topic;
setShow(false);
selected(cardId, channelId);
}
return (
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={show} onRequestClose={()=>setShow(false)}>
<View style={styles.modal}>
<BlurView style={styles.blur} blurType="dark" blurAmount={6} reducedTransparencyFallbackColor="dark" />
<Surface elevation={3} style={styles.content}>
<View style={styles.header}>
<Text style={styles.title}>{ state.strings.selectShare }</Text>
<IconButton style={styles.close} icon="close" size={24} onPress={() => setShow(false)} />
</View>
<View style={styles.data}>
<Surface elevation={1} mode="flat" style={styles.channels}>
{ channels.length === 0 && (
<Text style={styles.empty}>{ state.strings.noTopics }</Text>
)}
{ channels.length > 0 && (
<FlatList
style={styles.list}
data={channels}
initialNumToRender={32}
showsVerticalScrollIndicator={false}
renderItem={({item}) => {
const {cardId, channelId, sealed, focused, hosted, unread, imageUrl, subject, message} = item;
const select = () => {
setTopic({ cardId, channelId });
};
return (
<Surface elevation={topic?.cardId === cardId && topic?.channelId === channelId ? 0 : 2 }>
<Channel
containerStyle={{
...styles.channel,
borderColor: theme.colors.outlineVariant,
}}
select={select}
unread={false}
sealed={sealed}
hosted={hosted}
imageUrl={imageUrl}
notesPlaceholder={state.strings.notes}
subjectPlaceholder={state.strings.unknown}
subject={subject}
messagePlaceholder={`[${state.strings.sealed}]`}
message={message}
/>
</Surface>
);
}}
keyExtractor={channel => `${channel.cardId}:${channel.channelId}`}
/>
)}
</Surface>
</View>
<View style={styles.controls}>
<Button style={styles.control} mode="outlined" onPress={()=>setShow(false)}>
{state.strings.cancel}
</Button>
<Button style={styles.control} disabled={topic==null} mode="contained" onPress={select}>
{state.strings.selectImage}
</Button>
</View>
</Surface>
</View>
</Modal>
);
}

View File

@ -0,0 +1,24 @@
import { useState, useContext, useEffect } from 'react'
import { AppContext } from '../context/AppContext'
import { DisplayContext } from '../context/DisplayContext';
import { ContextType } from '../context/ContextType'
import { Channel } from 'databag-client-sdk';
export function useSelector() {
const app = useContext(AppContext) as ContextType
const display = useContext(DisplayContext) as ContextType
const [state, setState] = useState({
strings: display.state.strings,
channels: [] as Channel[],
})
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const updateState = (value: any) => {
setState((s) => ({ ...s, ...value }))
}
const actions = {
}
return { state, actions }
}

View File

@ -1,5 +1,5 @@
import React, {useState, useCallback, useEffect} from 'react';
import {SafeAreaView, Pressable, View, useColorScheme} from 'react-native';
import {SafeAreaView, Modal, Pressable, View, useColorScheme} from 'react-native';
import {RingContextProvider} from '../context/RingContext';
import {styles} from './Session.styled';
import {IconButton, Surface, Text, Icon} from 'react-native-paper';
@ -30,7 +30,7 @@ const DetailsDrawer = createDrawerNavigator();
const ContactStack = createNativeStackNavigator();
const ContentStack = createNativeStackNavigator();
export function Session() {
export function Session({ share }: { share: { filePath: string, mimeType: string }}) {
const {state} = useSession();
const scheme = useColorScheme();
const [tab, setTab] = useState('content');
@ -39,6 +39,7 @@ export function Session() {
const [dismissed, setDismissed] = useState(false);
const [disconnected, setDisconnected] = useState(false);
const [showDisconnected, setShowDisconnected] = useState(false);
const [focus, setFocus] = useState(false);
const textContact = (cardId: null|string) => {
setTextCard({ cardId });
@ -48,7 +49,7 @@ export function Session() {
setCallCard({ card });
}
const sessionNav = {strings: state.strings, callContact, callCard, textContact, textCard};
const sessionNav = {strings: state.strings, callContact, callCard, textContact, textCard, focus, setFocus, share};
const showContent = {display: tab === 'content' ? 'flex' : 'none'};
const showContact = {display: tab === 'contacts' ? 'flex' : 'none'};
const showSettings = {display: tab === 'settings' ? 'flex' : 'none'};
@ -66,6 +67,12 @@ export function Session() {
}
}
useEffect(() => {
if (share) {
contentTab();
}
}, [share]);
useEffect(() => {
if (state.appState && !state.sdkState) {
setDisconnected(true);
@ -91,7 +98,7 @@ export function Session() {
...styles.body,
...showContent,
}}>
<ContentTab textCard={textCard} scheme={scheme} contentTab={contentTab} />
<ContentTab share={share} textCard={textCard} scheme={scheme} contentTab={contentTab} />
</View>
<View
style={{
@ -205,7 +212,7 @@ export function Session() {
);
}
function ContentTab({scheme, textCard, contentTab}: {scheme: string, textCard: {cardId: null|string}, contentTab: ()=>void}) {
function ContentTab({scheme, textCard, contentTab, share}: {scheme: string, textCard: {cardId: null|string}, contentTab: ()=>void, share: {filePath: string, mimeType: string}}) {
const openConversation = (props) => {
props.navigation.navigate('conversation');
contentTab();
@ -216,7 +223,7 @@ function ContentTab({scheme, textCard, contentTab}: {scheme: string, textCard: {
<ContentStack.Navigator initialRouteName="contacts" screenOptions={{headerShown: false}}>
<ContentStack.Screen name="content" options={{headerBackTitleVisible: false}}>
{props => (
<Content textCard={textCard} openConversation={()=>openConversation(props)} />
<Content share={share} textCard={textCard} closeAll={()=>props.navigation.popToTop()} openConversation={()=>openConversation(props)} />
)}
</ContentStack.Screen>
<ContentStack.Screen name="conversation" options={styles.noHeader}>
@ -279,11 +286,10 @@ function ContactTab({scheme, textContact, callContact}: {scheme: string, textCon
}
function DetailsScreen({nav}) {
const [focus, setFocus] = useState(false);
const closeAll = (props) => {
props.navigation.closeDrawer();
setFocus(false);
nav.setFocus(false);
}
const DetailsComponent = useCallback(
@ -307,7 +313,7 @@ function DetailsScreen({nav}) {
headerShown: false,
overlayColor: 'rgba(8,8,8,.9)',
}}>
<DetailsDrawer.Screen name="details">{({navigation}) => <ProfileScreen nav={{...nav, focus, setFocus, details: navigation}} />}</DetailsDrawer.Screen>
<DetailsDrawer.Screen name="details">{({navigation}) => <ProfileScreen nav={{...nav, details: navigation}} />}</DetailsDrawer.Screen>
</DetailsDrawer.Navigator>
);
}
@ -448,7 +454,7 @@ function HomeScreen({nav}) {
<Identity openSettings={nav.settings.openDrawer} openContacts={nav.contacts.openDrawer} />
</Surface>
<Surface style={styles.channels} elevation={2} mode="flat">
<Content textCard={nav.textCard} openConversation={()=>nav.setFocus(true)} />
<Content share={nav.share} textCard={nav.textCard} closeAll={()=>{}} openConversation={()=>nav.setFocus(true)} />
</Surface>
</View>
<Surface style={styles.right} mode="flat">