mirror of
https://github.com/balzack/databag.git
synced 2025-04-20 00:25:16 +00:00
fixed lint warnings
This commit is contained in:
parent
1c93ad161f
commit
6c4f0f1181
@ -1,6 +1,6 @@
|
|||||||
import { Staging } from 'databag-client-sdk'
|
import { Staging } from 'databag-client-sdk';
|
||||||
import RNFS from 'react-native-fs';
|
import RNFS from 'react-native-fs';
|
||||||
import fileType from 'react-native-file-type'
|
import fileType from 'react-native-file-type';
|
||||||
|
|
||||||
export class StagingFiles implements Staging {
|
export class StagingFiles implements Staging {
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ export class StagingFiles implements Staging {
|
|||||||
if (entry.name.startsWith('dbTmp_')) {
|
if (entry.name.startsWith('dbTmp_')) {
|
||||||
await RNFS.unlink(entry.path);
|
await RNFS.unlink(entry.path);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async read(source: any): Promise<{ size: number, getData: (position: number, length: number)=>Promise<string>, close: ()=>Promise<void> }> {
|
public async read(source: any): Promise<{ size: number, getData: (position: number, length: number)=>Promise<string>, close: ()=>Promise<void> }> {
|
||||||
@ -19,19 +19,19 @@ export class StagingFiles implements Staging {
|
|||||||
const size = stat.size;
|
const size = stat.size;
|
||||||
const getData = async (position: number, length: number) => {
|
const getData = async (position: number, length: number) => {
|
||||||
return await RNFS.read(path, length, position, 'base64');
|
return await RNFS.read(path, length, position, 'base64');
|
||||||
}
|
};
|
||||||
const close = async ()=>{}
|
const close = async ()=>{};
|
||||||
return { size, getData, close };
|
return { size, getData, close };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async write(): Promise<{ setData: (data: string)=>Promise<void>, getUrl: ()=>Promise<string>, close: ()=>Promise<void> }> {
|
public async write(): Promise<{ setData: (data: string)=>Promise<void>, getUrl: ()=>Promise<string>, close: ()=>Promise<void> }> {
|
||||||
let set = false;
|
let set = false;
|
||||||
let extension = '';
|
let extension = '';
|
||||||
const path = RNFS.DocumentDirectoryPath + `/dbTmp_${Date.now()}`
|
const path = RNFS.DocumentDirectoryPath + `/dbTmp_${Date.now()}`;
|
||||||
const setData = async (data: string) => {
|
const setData = async (data: string) => {
|
||||||
set = true;
|
set = true;
|
||||||
await RNFS.appendFile(path, data, 'base64');
|
await RNFS.appendFile(path, data, 'base64');
|
||||||
}
|
};
|
||||||
const getUrl = async () => {
|
const getUrl = async () => {
|
||||||
if (!extension) {
|
if (!extension) {
|
||||||
try {
|
try {
|
||||||
@ -44,8 +44,8 @@ export class StagingFiles implements Staging {
|
|||||||
extension = '.dat';
|
extension = '.dat';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `file://${path}${extension}`
|
return `file://${path}${extension}`;
|
||||||
}
|
};
|
||||||
const close = async () => {
|
const close = async () => {
|
||||||
if (set) {
|
if (set) {
|
||||||
try {
|
try {
|
||||||
@ -54,8 +54,8 @@ export class StagingFiles implements Staging {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return { setData, getUrl, close };
|
return { setData, getUrl, close };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,8 @@ export const styles = StyleSheet.create({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: 8,
|
gap: 8,
|
||||||
|
minHeight: 0,
|
||||||
|
flexGrow: 1,
|
||||||
},
|
},
|
||||||
scroll: {
|
scroll: {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
@ -190,10 +192,6 @@ export const styles = StyleSheet.create({
|
|||||||
modalClose: {
|
modalClose: {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
},
|
},
|
||||||
frame: {
|
|
||||||
minHeight: 0,
|
|
||||||
flexGrow: 1,
|
|
||||||
},
|
|
||||||
line: {
|
line: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
},
|
},
|
||||||
|
@ -80,8 +80,8 @@ export function Access() {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.server:undefined}
|
label={Platform.OS === 'ios' ? state.strings.server : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.server:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.server : undefined}
|
||||||
value={state.node}
|
value={state.node}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="server" />}
|
left={<TextInput.Icon style={styles.icon} icon="server" />}
|
||||||
onChangeText={value => actions.setNode(value)}
|
onChangeText={value => actions.setNode(value)}
|
||||||
@ -92,8 +92,8 @@ export function Access() {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.username:undefined}
|
label={Platform.OS === 'ios' ? state.strings.username : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.username:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.username : undefined}
|
||||||
value={state.username}
|
value={state.username}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="account" />}
|
left={<TextInput.Icon style={styles.icon} icon="account" />}
|
||||||
onChangeText={value => actions.setUsername(value)}
|
onChangeText={value => actions.setUsername(value)}
|
||||||
@ -105,8 +105,8 @@ export function Access() {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.password}
|
value={state.password}
|
||||||
label={Platform.OS==='ios'?state.strings.password:undefined}
|
label={Platform.OS === 'ios' ? state.strings.password : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.password:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.password : undefined}
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -152,8 +152,8 @@ export function Access() {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.token:undefined}
|
label={Platform.OS === 'ios' ? state.strings.token : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.token:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.token : undefined}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="ticket-account" />}
|
left={<TextInput.Icon style={styles.icon} icon="ticket-account" />}
|
||||||
onChangeText={value => actions.setToken(value)}
|
onChangeText={value => actions.setToken(value)}
|
||||||
/>
|
/>
|
||||||
@ -163,8 +163,8 @@ export function Access() {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.server:undefined}
|
label={Platform.OS === 'ios' ? state.strings.server : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.server:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.server : undefined}
|
||||||
value={state.node}
|
value={state.node}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="server" />}
|
left={<TextInput.Icon style={styles.icon} icon="server" />}
|
||||||
onChangeText={value => actions.setNode(value)}
|
onChangeText={value => actions.setNode(value)}
|
||||||
@ -198,8 +198,8 @@ export function Access() {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.token:undefined}
|
label={Platform.OS === 'ios' ? state.strings.token : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.token:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.token : undefined}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="ticket-account" />}
|
left={<TextInput.Icon style={styles.icon} icon="ticket-account" />}
|
||||||
onChangeText={value => actions.setToken(value)}
|
onChangeText={value => actions.setToken(value)}
|
||||||
/>
|
/>
|
||||||
@ -211,8 +211,8 @@ export function Access() {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.server:undefined}
|
label={Platform.OS === 'ios' ? state.strings.server : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.server:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.server : undefined}
|
||||||
value={state.node}
|
value={state.node}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="server" />}
|
left={<TextInput.Icon style={styles.icon} icon="server" />}
|
||||||
onChangeText={value => actions.setNode(value)}
|
onChangeText={value => actions.setNode(value)}
|
||||||
@ -224,8 +224,8 @@ export function Access() {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
error={state.taken}
|
error={state.taken}
|
||||||
label={Platform.OS==='ios'?state.strings.username:undefined}
|
label={Platform.OS === 'ios' ? state.strings.username : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.username:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.username : undefined}
|
||||||
value={state.username}
|
value={state.username}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="account" />}
|
left={<TextInput.Icon style={styles.icon} icon="account" />}
|
||||||
onChangeText={value => actions.setUsername(value)}
|
onChangeText={value => actions.setUsername(value)}
|
||||||
@ -238,8 +238,8 @@ export function Access() {
|
|||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
textContentType={'oneTimeCode'}
|
textContentType={'oneTimeCode'}
|
||||||
value={state.password}
|
value={state.password}
|
||||||
label={Platform.OS==='ios'?state.strings.password:undefined}
|
label={Platform.OS === 'ios' ? state.strings.password : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.password:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.password : undefined}
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -259,8 +259,8 @@ export function Access() {
|
|||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
textContentType={'oneTimeCode'}
|
textContentType={'oneTimeCode'}
|
||||||
value={state.confirm}
|
value={state.confirm}
|
||||||
label={Platform.OS==='ios'?state.strings.confirmPassword:undefined}
|
label={Platform.OS === 'ios' ? state.strings.confirmPassword : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.confirmPassword:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.confirmPassword : undefined}
|
||||||
secureTextEntry={!showConfirm}
|
secureTextEntry={!showConfirm}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -299,8 +299,8 @@ export function Access() {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.server:undefined}
|
label={Platform.OS === 'ios' ? state.strings.server : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.server:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.server : undefined}
|
||||||
value={state.node}
|
value={state.node}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="server" />}
|
left={<TextInput.Icon style={styles.icon} icon="server" />}
|
||||||
onChangeText={value => actions.setNode(value)}
|
onChangeText={value => actions.setNode(value)}
|
||||||
@ -311,8 +311,8 @@ export function Access() {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.password:undefined}
|
label={Platform.OS === 'ios' ? state.strings.password : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.password:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.password : undefined}
|
||||||
value={state.password}
|
value={state.password}
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
|
@ -32,7 +32,7 @@ export function useAccess() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
SplashScreen.hide();
|
SplashScreen.hide();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const {username, token, node, secure, mode} = state;
|
const {username, token, node, secure, mode} = state;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, {useEffect, useState} from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import {FlatList, SafeAreaView, Image, View, Pressable, TouchableOpacity, Modal} from 'react-native';
|
import {FlatList, View, TouchableOpacity, Modal} from 'react-native';
|
||||||
import {Text, Button, IconButton, Divider, Surface, Icon, useTheme} from 'react-native-paper';
|
import {Text, Button, IconButton, Divider, Surface, Icon, useTheme} from 'react-native-paper';
|
||||||
import {useAccounts} from './useAccounts.hook';
|
import {useAccounts} from './useAccounts.hook';
|
||||||
import {styles} from './Accounts.styled';
|
import {styles} from './Accounts.styled';
|
||||||
@ -27,6 +27,7 @@ export function Accounts({ setup }: { setup: ()=>void }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadAccounts();
|
loadAccounts();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadAccounts = async () => {
|
const loadAccounts = async () => {
|
||||||
@ -39,7 +40,7 @@ export function Accounts({ setup }: { setup: ()=>void }) {
|
|||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const accessAccount = async (accountId: number) => {
|
const accessAccount = async (accountId: number) => {
|
||||||
if (!accessing) {
|
if (!accessing) {
|
||||||
@ -54,7 +55,7 @@ export function Accounts({ setup }: { setup: ()=>void }) {
|
|||||||
}
|
}
|
||||||
setAccessing(null);
|
setAccessing(null);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const addAccount = async () => {
|
const addAccount = async () => {
|
||||||
if (!adding) {
|
if (!adding) {
|
||||||
@ -69,14 +70,14 @@ export function Accounts({ setup }: { setup: ()=>void }) {
|
|||||||
}
|
}
|
||||||
setAdding(false);
|
setAdding(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const failedParams = {
|
const failedParams = {
|
||||||
title: state.strings.operationFailed,
|
title: state.strings.operationFailed,
|
||||||
prompt: state.strings.tryAgain,
|
prompt: state.strings.tryAgain,
|
||||||
cancel: {
|
cancel: {
|
||||||
label: state.strings.close,
|
label: state.strings.close,
|
||||||
action: ()=>{setFailed(false)},
|
action: ()=>{setFailed(false);},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ export function Accounts({ setup }: { setup: ()=>void }) {
|
|||||||
}
|
}
|
||||||
setBlocking(null);
|
setBlocking(null);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const removeAccount = (accountId: number) => {
|
const removeAccount = (accountId: number) => {
|
||||||
if (!remove) {
|
if (!remove) {
|
||||||
@ -116,12 +117,12 @@ export function Accounts({ setup }: { setup: ()=>void }) {
|
|||||||
},
|
},
|
||||||
cancel: {
|
cancel: {
|
||||||
label: state.strings.cancel,
|
label: state.strings.cancel,
|
||||||
action: () => {setRemove(false)},
|
action: () => {setRemove(false);},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
setRemove(true);
|
setRemove(true);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const copyToken = async () => {
|
const copyToken = async () => {
|
||||||
if (!tokenCopy) {
|
if (!tokenCopy) {
|
||||||
@ -159,12 +160,12 @@ export function Accounts({ setup }: { setup: ()=>void }) {
|
|||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
renderItem={({item}) => {
|
renderItem={({item}) => {
|
||||||
const options = [
|
const options = [
|
||||||
<IconButton key="disable" style={styles.icon} loading={accessing === item.accountId} iconColor={Colors.primary} mode="contained" icon="lock-open-variant-outline" onPress={() => {accessAccount(item.accountId)}} />,
|
<IconButton key="disable" style={styles.icon} loading={accessing === item.accountId} iconColor={Colors.primary} mode="contained" icon="lock-open-variant-outline" onPress={() => {accessAccount(item.accountId);}} />,
|
||||||
<IconButton key="reset" style={styles.icon} loading={blocking === item.accountId} iconColor={Colors.pending} mode="contained" icon={item.disabled ? 'account-check-outline' : 'account-cancel-outline'} onPress={()=>{blockAccount(item.accountId, !item.disabled)}} />,
|
<IconButton key="reset" style={styles.icon} loading={blocking === item.accountId} iconColor={Colors.pending} mode="contained" icon={item.disabled ? 'account-check-outline' : 'account-cancel-outline'} onPress={()=>{blockAccount(item.accountId, !item.disabled);}} />,
|
||||||
<IconButton key="remove" style={styles.icon} loading={removing === item.accountId} iconColor={Colors.offsync} mode="contained" icon="trash-can-outline" onPress={()=>{removeAccount(item.accountId)}} />
|
<IconButton key="remove" style={styles.icon} loading={removing === item.accountId} iconColor={Colors.offsync} mode="contained" icon="trash-can-outline" onPress={()=>{removeAccount(item.accountId);}} />,
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
containerStyle={{
|
containerStyle={{
|
||||||
...styles.card,
|
...styles.card,
|
||||||
borderColor: theme.colors.outlineVariant,
|
borderColor: theme.colors.outlineVariant,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {useEffect, useState, useContext, useRef} from 'react';
|
import {useEffect, useState, useContext} from 'react';
|
||||||
import {AppContext} from '../context/AppContext';
|
import {AppContext} from '../context/AppContext';
|
||||||
import {DisplayContext} from '../context/DisplayContext';
|
import {DisplayContext} from '../context/DisplayContext';
|
||||||
import {ContextType} from '../context/ContextType';
|
import {ContextType} from '../context/ContextType';
|
||||||
@ -31,7 +31,7 @@ export function useAccounts() {
|
|||||||
updateState({ loading: false });
|
updateState({ loading: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { layout, strings} = display.state;
|
const { layout, strings} = display.state;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { View, Image } from 'react-native';
|
import { View, Image } from 'react-native';
|
||||||
import {useTheme, Text, Icon} from 'react-native-paper';
|
import {useTheme, Text, Icon} from 'react-native-paper';
|
||||||
import { styles } from './Base.styled';
|
import { styles } from './Base.styled';
|
||||||
@ -9,13 +9,13 @@ import { Colors } from '../constants/Colors';
|
|||||||
|
|
||||||
export function Base() {
|
export function Base() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { state, actions } = useBase();
|
const { state } = useBase();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ ...styles.base, backgroundColor: theme.colors.base }}>
|
<View style={{ ...styles.base, backgroundColor: theme.colors.base }}>
|
||||||
<Text style={styles.title}>Databag</Text>
|
<Text style={styles.title}>Databag</Text>
|
||||||
<Text style={styles.description}>{ state.strings.communication }</Text>
|
<Text style={styles.description}>{ state.strings.communication }</Text>
|
||||||
<Image style={styles.image} source={theme.colors.name == 'light' ? light : dark} resizeMode="contain" />
|
<Image style={styles.image} source={theme.colors.name === 'light' ? light : dark} resizeMode="contain" />
|
||||||
{ (state.profileSet === false || state.cardSet === false || state.channelSet === false) && (
|
{ (state.profileSet === false || state.cardSet === false || state.channelSet === false) && (
|
||||||
<View style={styles.steps}>
|
<View style={styles.steps}>
|
||||||
{ state.profileSet === false && (
|
{ state.profileSet === false && (
|
||||||
|
@ -1,48 +1,48 @@
|
|||||||
import { useState, useContext, useEffect } from 'react'
|
import { useState, useContext, useEffect } from 'react';
|
||||||
import { DisplayContext } from '../context/DisplayContext';
|
import { DisplayContext } from '../context/DisplayContext';
|
||||||
import { AppContext } from '../context/AppContext';
|
import { AppContext } from '../context/AppContext';
|
||||||
import { ContextType } from '../context/ContextType'
|
import { ContextType } from '../context/ContextType';
|
||||||
|
|
||||||
export function useBase() {
|
export function useBase() {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
profileSet: null as null | boolean,
|
profileSet: null as null | boolean,
|
||||||
cardSet: null as null | boolean,
|
cardSet: null as null | boolean,
|
||||||
channelSet: null as null | boolean,
|
channelSet: null as null | boolean,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setProfile = (profile: Profile) => {
|
const setProfile = (profile: Profile) => {
|
||||||
updateState({ profileSet: Boolean(profile.name) });
|
updateState({ profileSet: Boolean(profile.name) });
|
||||||
}
|
};
|
||||||
const setCards = (cards: Card[]) => {
|
const setCards = (cards: Card[]) => {
|
||||||
updateState({ cardSet: cards.length > 0 });
|
updateState({ cardSet: cards.length > 0 });
|
||||||
}
|
};
|
||||||
const setChannels = ({ channels, cardId }: { channels: Channel[]; cardId: string | null }) => {
|
const setChannels = ({ channels, cardId }: { channels: Channel[]; cardId: string | null }) => {
|
||||||
updateState({ channelSet: channels.length > 0 });
|
updateState({ channelSet: cardId && channels.length > 0 });
|
||||||
}
|
};
|
||||||
|
|
||||||
const { identity, contact, content } = app.state.session
|
const { identity, contact, content } = app.state.session;
|
||||||
identity.addProfileListener(setProfile)
|
identity.addProfileListener(setProfile);
|
||||||
contact.addCardListener(setCards)
|
contact.addCardListener(setCards);
|
||||||
content.addChannelListener(setChannels)
|
content.addChannelListener(setChannels);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
identity.removeProfileListener(setProfile);
|
identity.removeProfileListener(setProfile);
|
||||||
contact.removeCardListener(setCards);
|
contact.removeCardListener(setCards);
|
||||||
content.removeChannelListener(setChannels);
|
content.removeChannelListener(setChannels);
|
||||||
}
|
};
|
||||||
}, []);
|
}, [app.state.session]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import { Colors } from '../constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
active: {
|
active: {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Animated, useAnimatedValue, useWindowDimensions, Dimensions, Image, View } from 'react-native';
|
import { Animated, useAnimatedValue, Image, View } from 'react-native';
|
||||||
import { useCall } from './useCall.hook';
|
import { useCall } from './useCall.hook';
|
||||||
import { styles } from './Call.styled'
|
import { styles } from './Call.styled';
|
||||||
import { Card as Contact } from '../card/Card';
|
import { Text, Surface, IconButton } from 'react-native-paper';
|
||||||
import { Text, Surface, IconButton, ActivityIndicator } from 'react-native-paper';
|
|
||||||
import { Confirm } from '../confirm/Confirm';
|
import { Confirm } from '../confirm/Confirm';
|
||||||
import { Colors } from '../constants/Colors';
|
import { Colors } from '../constants/Colors';
|
||||||
import { RTCView } from 'react-native-webrtc';
|
import { RTCView } from 'react-native-webrtc';
|
||||||
@ -14,11 +13,7 @@ export function Call() {
|
|||||||
const [ending, setEnding] = useState(false);
|
const [ending, setEnding] = useState(false);
|
||||||
const [applyingAudio, setApplyingAudio] = useState(false);
|
const [applyingAudio, setApplyingAudio] = useState(false);
|
||||||
const [applyingVideo, setApplyingVideo] = useState(false);
|
const [applyingVideo, setApplyingVideo] = useState(false);
|
||||||
const [accepting, setAccepting] = useState(null as null|string);
|
const opacity = useAnimatedValue(0);
|
||||||
const [ignoring, setIgnoring] = useState(null as null|string);
|
|
||||||
const [declining, setDeclining] = useState(null as null|string);
|
|
||||||
const {height, width} = useWindowDimensions();
|
|
||||||
const opacity = useAnimatedValue(0)
|
|
||||||
|
|
||||||
const toggleAudio = async () => {
|
const toggleAudio = async () => {
|
||||||
if (!applyingAudio) {
|
if (!applyingAudio) {
|
||||||
@ -35,7 +30,7 @@ export function Call() {
|
|||||||
}
|
}
|
||||||
setApplyingAudio(false);
|
setApplyingAudio(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const toggleVideo = async () => {
|
const toggleVideo = async () => {
|
||||||
if (!applyingVideo) {
|
if (!applyingVideo) {
|
||||||
@ -52,7 +47,7 @@ export function Call() {
|
|||||||
}
|
}
|
||||||
setApplyingVideo(false);
|
setApplyingVideo(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const end = async () => {
|
const end = async () => {
|
||||||
if (!ending) {
|
if (!ending) {
|
||||||
@ -65,7 +60,7 @@ export function Call() {
|
|||||||
}
|
}
|
||||||
setEnding(false);
|
setEnding(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const alertParams = {
|
const alertParams = {
|
||||||
title: state.strings.operationFailed,
|
title: state.strings.operationFailed,
|
||||||
@ -92,6 +87,7 @@ export function Call() {
|
|||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state.calling, state.fullscreen]);
|
}, [state.calling, state.fullscreen]);
|
||||||
|
|
||||||
const viewStyle = state.calling && state.fullscreen ? styles.active : styles.inactive;
|
const viewStyle = state.calling && state.fullscreen ? styles.active : styles.inactive;
|
||||||
@ -114,7 +110,7 @@ export function Call() {
|
|||||||
resizeMode="contain"
|
resizeMode="contain"
|
||||||
source={{ uri: state.calling.imageUrl }}
|
source={{ uri: state.calling.imageUrl }}
|
||||||
/>
|
/>
|
||||||
<Text style={styles.duration}>{ `${Math.floor(state.duration/60)}:${(state.duration % 60).toString().padStart(2, '0')}` }</Text>
|
<Text style={styles.duration}>{ `${Math.floor(state.duration / 60)}:${(state.duration % 60).toString().padStart(2, '0')}` }</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useEffect, useRef } from 'react';
|
||||||
import { RingContext } from '../context/RingContext'
|
import { RingContext } from '../context/RingContext';
|
||||||
import { DisplayContext } from '../context/DisplayContext'
|
import { DisplayContext } from '../context/DisplayContext';
|
||||||
import { ContextType } from '../context/ContextType'
|
import { ContextType } from '../context/ContextType';
|
||||||
import { Card } from 'databag-client-sdk';
|
import { Card } from 'databag-client-sdk';
|
||||||
|
|
||||||
export function useCall() {
|
export function useCall() {
|
||||||
@ -25,12 +25,12 @@ export function useCall() {
|
|||||||
failed: false,
|
failed: false,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { width, height, strings } = display.state;
|
const { width, height, strings } = display.state;
|
||||||
@ -41,14 +41,14 @@ export function useCall() {
|
|||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
if (offset.current) {
|
if (offset.current) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const duration = Math.floor((now.getTime() / 1000) - offsetTime.current);
|
const duration = Math.floor((now.getTime() / 1000) - offsetTime.current);
|
||||||
updateState({ duration });
|
updateState({ duration });
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { calls, calling, fullscreen, localStream, remoteStream, remoteVideo, localVideo, audioEnabled, videoEnabled, connected, connectedTime, failed } = ring.state;
|
const { calls, calling, fullscreen, localStream, remoteStream, remoteVideo, localVideo, audioEnabled, videoEnabled, connected, connectedTime, failed } = ring.state;
|
||||||
|
@ -20,7 +20,7 @@ export const en = {
|
|||||||
server: 'Server',
|
server: 'Server',
|
||||||
token: 'Token',
|
token: 'Token',
|
||||||
delayMessage: 'Key generation can take several minutes.',
|
delayMessage: 'Key generation can take several minutes.',
|
||||||
noAccess: 'No Access',
|
noAccess: 'No Access',
|
||||||
connecting: 'Connecting',
|
connecting: 'Connecting',
|
||||||
|
|
||||||
setup: 'Setup',
|
setup: 'Setup',
|
||||||
@ -294,7 +294,7 @@ export const en = {
|
|||||||
disable: 'Disable',
|
disable: 'Disable',
|
||||||
confirmDisable: 'Disabling Multi-Factor Authentication',
|
confirmDisable: 'Disabling Multi-Factor Authentication',
|
||||||
disablePrompt: 'Are you sure you want to disable multi-factor authentication',
|
disablePrompt: 'Are you sure you want to disable multi-factor authentication',
|
||||||
}
|
};
|
||||||
|
|
||||||
export const fr = {
|
export const fr = {
|
||||||
viewTerms: 'Voir les conditions d\'utilisation',
|
viewTerms: 'Voir les conditions d\'utilisation',
|
||||||
@ -590,7 +590,7 @@ export const fr = {
|
|||||||
disable: 'Désactiver',
|
disable: 'Désactiver',
|
||||||
confirmDisable: "Désactivation de l'authentification multi-facteurs",
|
confirmDisable: "Désactivation de l'authentification multi-facteurs",
|
||||||
disablePrompt: "Êtes-vous sûr de vouloir désactiver l'authentification multi-facteurs",
|
disablePrompt: "Êtes-vous sûr de vouloir désactiver l'authentification multi-facteurs",
|
||||||
}
|
};
|
||||||
|
|
||||||
export const sp = {
|
export const sp = {
|
||||||
viewTerms: 'Ver los términos de servicio',
|
viewTerms: 'Ver los términos de servicio',
|
||||||
@ -630,7 +630,7 @@ export const sp = {
|
|||||||
accessingLink: 'Utilice el siguiente enlace para acceder a la cuenta especificada',
|
accessingLink: 'Utilice el siguiente enlace para acceder a la cuenta especificada',
|
||||||
accessingToken: 'Utilice el siguiente token para acceder a la cuenta especificada desde la pantalla de inicio de sesión',
|
accessingToken: 'Utilice el siguiente token para acceder a la cuenta especificada desde la pantalla de inicio de sesión',
|
||||||
|
|
||||||
noAccess: 'Sin Acceso',
|
noAccess: 'Sin Acceso',
|
||||||
membership: 'Afiliación',
|
membership: 'Afiliación',
|
||||||
channelHost: 'Anfitrión del Tema',
|
channelHost: 'Anfitrión del Tema',
|
||||||
channelGuest: 'Invitado de Tema',
|
channelGuest: 'Invitado de Tema',
|
||||||
@ -885,7 +885,7 @@ export const sp = {
|
|||||||
disable: 'Desactivar',
|
disable: 'Desactivar',
|
||||||
confirmDisable: 'Desactivación de la autenticación de dos factores',
|
confirmDisable: 'Desactivación de la autenticación de dos factores',
|
||||||
disablePrompt: '¿Estás seguro de que quieres desactivar la autenticación de dos factores?',
|
disablePrompt: '¿Estás seguro de que quieres desactivar la autenticación de dos factores?',
|
||||||
}
|
};
|
||||||
|
|
||||||
export const pt = {
|
export const pt = {
|
||||||
viewTerms: 'Ver os termos de serviço',
|
viewTerms: 'Ver os termos de serviço',
|
||||||
@ -1180,7 +1180,7 @@ export const pt = {
|
|||||||
disable: 'Desativar',
|
disable: 'Desativar',
|
||||||
confirmDisable: 'Desativando Autenticação de Dois Fatores',
|
confirmDisable: 'Desativando Autenticação de Dois Fatores',
|
||||||
disablePrompt: 'Tem certeza de que deseja desativar a autenticação de dois fatores?',
|
disablePrompt: 'Tem certeza de que deseja desativar a autenticação de dois fatores?',
|
||||||
}
|
};
|
||||||
|
|
||||||
export const de = {
|
export const de = {
|
||||||
viewTerms: 'Nutzungsbedingungen anzeigen',
|
viewTerms: 'Nutzungsbedingungen anzeigen',
|
||||||
@ -1213,7 +1213,7 @@ export const de = {
|
|||||||
accounts: 'Konten',
|
accounts: 'Konten',
|
||||||
noAccounts: 'Keine Konten',
|
noAccounts: 'Keine Konten',
|
||||||
selectShare: 'Wählen Sie Das Thema Zum Teilen Aus',
|
selectShare: 'Wählen Sie Das Thema Zum Teilen Aus',
|
||||||
|
|
||||||
addingTitle: 'Konto hinzufügen',
|
addingTitle: 'Konto hinzufügen',
|
||||||
addingLink: 'Verwenden Sie den folgenden Link, um ein Konto zu erstellen',
|
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',
|
addingToken: 'Verwenden Sie das folgende Token, um ein Konto vom Anmeldebildschirm aus zu erstellen',
|
||||||
@ -1475,7 +1475,7 @@ export const de = {
|
|||||||
disable: 'Deaktivieren',
|
disable: 'Deaktivieren',
|
||||||
confirmDisable: 'Deaktivierung der Zwei-Faktor-Authentifizierung',
|
confirmDisable: 'Deaktivierung der Zwei-Faktor-Authentifizierung',
|
||||||
disablePrompt: 'Sind Sie sicher, dass Sie die Zwei-Faktor-Authentifizierung deaktivieren möchten?',
|
disablePrompt: 'Sind Sie sicher, dass Sie die Zwei-Faktor-Authentifizierung deaktivieren möchten?',
|
||||||
}
|
};
|
||||||
|
|
||||||
export const ru = {
|
export const ru = {
|
||||||
viewTerms: 'Просмотреть условия обслуживания',
|
viewTerms: 'Просмотреть условия обслуживания',
|
||||||
@ -1770,7 +1770,7 @@ export const ru = {
|
|||||||
disable: 'Отключить',
|
disable: 'Отключить',
|
||||||
confirmDisable: 'Отключение двухфакторной аутентификации',
|
confirmDisable: 'Отключение двухфакторной аутентификации',
|
||||||
disablePrompt: 'Вы уверены, что хотите отключить двухфакторную аутентификацию?',
|
disablePrompt: 'Вы уверены, что хотите отключить двухфакторную аутентификацию?',
|
||||||
}
|
};
|
||||||
|
|
||||||
export const el = {
|
export const el = {
|
||||||
viewTerms: 'Δείτε τους όρους υπηρεσίας',
|
viewTerms: 'Δείτε τους όρους υπηρεσίας',
|
||||||
@ -1972,7 +1972,7 @@ export const el = {
|
|||||||
enableService: 'Υπηρεσία cloudflare',
|
enableService: 'Υπηρεσία cloudflare',
|
||||||
serviceHint: 'Ενεργοποίηση υπηρεσίας CloudFlare',
|
serviceHint: 'Ενεργοποίηση υπηρεσίας CloudFlare',
|
||||||
serverUrl: 'URL διακομιστή WebRTC',
|
serverUrl: 'URL διακομιστή WebRTC',
|
||||||
urlHint: 'turn:ip:port?transport=udp',
|
urlHint: 'turn:ip:port?transport=udp',
|
||||||
webUsername: 'Όνομα χρήστη WebRTC',
|
webUsername: 'Όνομα χρήστη WebRTC',
|
||||||
webPassword: 'Κωδικός πρόσβασης WebRTC',
|
webPassword: 'Κωδικός πρόσβασης WebRTC',
|
||||||
failedLoad: 'Αποτυχία φόρτωσης',
|
failedLoad: 'Αποτυχία φόρτωσης',
|
||||||
@ -2037,7 +2037,7 @@ export const el = {
|
|||||||
disable: 'Καθιστώ ανίκανο',
|
disable: 'Καθιστώ ανίκανο',
|
||||||
confirmDisable: 'Απενεργοποίηση ελέγχου ταυτότητας πολλαπλών παραγόντων',
|
confirmDisable: 'Απενεργοποίηση ελέγχου ταυτότητας πολλαπλών παραγόντων',
|
||||||
disablePrompt: 'Είστε βέβαιοι ότι θέλετε να απενεργοποιήσετε τον έλεγχο ταυτότητας πολλαπλών παραγόντων',
|
disablePrompt: 'Είστε βέβαιοι ότι θέλετε να απενεργοποιήσετε τον έλεγχο ταυτότητας πολλαπλών παραγόντων',
|
||||||
}
|
};
|
||||||
|
|
||||||
export function getLanguageStrings() {
|
export function getLanguageStrings() {
|
||||||
const locale = Platform.OS === 'ios' ? NativeModules.SettingsManager?.settings.AppleLocale || NativeModules.SettingsManager?.settings.AppleLanguages[0] : NativeModules.I18nManager?.localeIdentifier;
|
const locale = Platform.OS === 'ios' ? NativeModules.SettingsManager?.settings.AppleLocale || NativeModules.SettingsManager?.settings.AppleLanguages[0] : NativeModules.I18nManager?.localeIdentifier;
|
||||||
|
@ -478,7 +478,7 @@ Falls Sie Fragen zu diesen Bedingungen oder zum Dienst haben, können Sie uns ü
|
|||||||
|
|
||||||
Wir freuen uns, Sie als Teil der Databag-Community begrüßen zu dürfen, und wir hoffen, dass Sie unsere Dienste genießen.
|
Wir freuen uns, Sie als Teil der Databag-Community begrüßen zu dürfen, und wir hoffen, dass Sie unsere Dienste genießen.
|
||||||
`,
|
`,
|
||||||
pt:
|
pt:
|
||||||
`Agradeço por se juntar à comunidade Databag! Estes Termos de Serviço (os "Termos") abrangem seus direitos e obrigações relacionados ao seu acesso e uso dos serviços da Databag, incluindo, mas não se limitando ao Databag (coletivamente, o "Serviço"). Todas as referências a "você", "seu" ou "usuário" se referem ao usuário do Serviço. Além destes Termos, por favor, reveja a Política de Privacidade da Databag, que descreve nossas práticas relacionadas à coleta e uso de suas informações. Estes Termos se aplicam também à nossa Política de Privacidade. Ao usar o Serviço, você declara e concorda que leu, entende e concorda em cumprir tanto estes Termos quanto nossa Política de Privacidade como acordos vinculativos. Além disso, você concorda que estes Termos e nossa Política de Privacidade se aplicam ao seu uso anterior, se houver.
|
`Agradeço por se juntar à comunidade Databag! Estes Termos de Serviço (os "Termos") abrangem seus direitos e obrigações relacionados ao seu acesso e uso dos serviços da Databag, incluindo, mas não se limitando ao Databag (coletivamente, o "Serviço"). Todas as referências a "você", "seu" ou "usuário" se referem ao usuário do Serviço. Além destes Termos, por favor, reveja a Política de Privacidade da Databag, que descreve nossas práticas relacionadas à coleta e uso de suas informações. Estes Termos se aplicam também à nossa Política de Privacidade. Ao usar o Serviço, você declara e concorda que leu, entende e concorda em cumprir tanto estes Termos quanto nossa Política de Privacidade como acordos vinculativos. Além disso, você concorda que estes Termos e nossa Política de Privacidade se aplicam ao seu uso anterior, se houver.
|
||||||
|
|
||||||
POR FAVOR, LEIA CUIDADOSAMENTE ESTES TERMOS, POIS CONTÊM INFORMAÇÕES IMPORTANTES SOBRE SEUS DIREITOS E RESPONSABILIDADES, INCLUINDO A LIMITAÇÃO DE NOSSA RESPONSABILIDADE. SE VOCÊ NÃO ACEITAR ESTE ACORDO EM SUA TOTALIDADE, NÃO PODERÁ ACESSAR OU UTILIZAR O SERVIÇO.
|
POR FAVOR, LEIA CUIDADOSAMENTE ESTES TERMOS, POIS CONTÊM INFORMAÇÕES IMPORTANTES SOBRE SEUS DIREITOS E RESPONSABILIDADES, INCLUINDO A LIMITAÇÃO DE NOSSA RESPONSABILIDADE. SE VOCÊ NÃO ACEITAR ESTE ACORDO EM SUA TOTALIDADE, NÃO PODERÁ ACESSAR OU UTILIZAR O SERVIÇO.
|
||||||
@ -825,5 +825,5 @@ support@databag.com
|
|||||||
|
|
||||||
© 2022 Databag, Inc.
|
© 2022 Databag, Inc.
|
||||||
|
|
||||||
`
|
`,
|
||||||
}
|
};
|
||||||
|
@ -4,7 +4,6 @@ import {SafeAreaView, Modal, FlatList, View} from 'react-native';
|
|||||||
import {styles} from './Content.styled';
|
import {styles} from './Content.styled';
|
||||||
import {useContent} from './useContent.hook';
|
import {useContent} from './useContent.hook';
|
||||||
import {Channel} from '../channel/Channel';
|
import {Channel} from '../channel/Channel';
|
||||||
import {Focus} from 'databag-client-sdk';
|
|
||||||
import {BlurView} from '@react-native-community/blur';
|
import {BlurView} from '@react-native-community/blur';
|
||||||
import {Card} from '../card/Card';
|
import {Card} from '../card/Card';
|
||||||
import {Confirm} from '../confirm/Confirm';
|
import {Confirm} from '../confirm/Confirm';
|
||||||
@ -35,23 +34,25 @@ export function Content({share, closeAll, openConversation, textCard}: { share:
|
|||||||
actions.setSharing({ cardId, channelId, filePath, mimeType });
|
actions.setSharing({ cardId, channelId, filePath, mimeType });
|
||||||
}
|
}
|
||||||
open(cardId, channelId);
|
open(cardId, channelId);
|
||||||
}
|
};
|
||||||
|
|
||||||
const open = (cardId: string | null, channelId: string) => {
|
const open = (cardId: string | null, channelId: string) => {
|
||||||
actions.setFocus(cardId, channelId);
|
actions.setFocus(cardId, channelId);
|
||||||
openConversation();
|
openConversation();
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (share) {
|
if (share) {
|
||||||
closeAll();
|
closeAll();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [share]);
|
}, [share]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (textCard.cardId) {
|
if (textCard.cardId) {
|
||||||
openTopic(textCard.cardId);
|
openTopic(textCard.cardId);
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [textCard]);
|
}, [textCard]);
|
||||||
|
|
||||||
const openTopic = async (cardId: string) => {
|
const openTopic = async (cardId: string) => {
|
||||||
@ -65,7 +66,7 @@ export function Content({share, closeAll, openConversation, textCard}: { share:
|
|||||||
setAlert(true);
|
setAlert(true);
|
||||||
}
|
}
|
||||||
setAdding(false);
|
setAdding(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const addTopic = async () => {
|
const addTopic = async () => {
|
||||||
setAdding(true);
|
setAdding(true);
|
||||||
@ -73,7 +74,7 @@ export function Content({share, closeAll, openConversation, textCard}: { share:
|
|||||||
const id = await actions.addTopic(
|
const id = await actions.addTopic(
|
||||||
sealedTopic,
|
sealedTopic,
|
||||||
subjectTopic,
|
subjectTopic,
|
||||||
members.filter(id => Boolean(cards.find(card => card.cardId === id))),
|
members.filter(memberId => Boolean(cards.find(card => card.cardId === memberId))),
|
||||||
);
|
);
|
||||||
setAdd(false);
|
setAdd(false);
|
||||||
setSubjectTopic('');
|
setSubjectTopic('');
|
||||||
|
@ -48,7 +48,7 @@ export function useContent() {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState(s => ({...s, ...value}));
|
setState(s => ({...s, ...value}));
|
||||||
};
|
};
|
||||||
@ -94,19 +94,19 @@ export function useContent() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const selectImage = () => {
|
const selectImage = () => {
|
||||||
if (contacts.length == 0) {
|
if (contacts.length === 0) {
|
||||||
return notes;
|
return notes;
|
||||||
} else if (contacts.length == 1) {
|
} else if (contacts.length === 1) {
|
||||||
if (contacts[0]) {
|
if (contacts[0]) {
|
||||||
return contacts[0].imageUrl;
|
return contacts[0].imageUrl;
|
||||||
} else {
|
} else {
|
||||||
return unknown;
|
return unknown;
|
||||||
}
|
}
|
||||||
} else if (contacts.length == 2) {
|
} else if (contacts.length === 2) {
|
||||||
return iii_group;
|
return iii_group;
|
||||||
} else if (contacts.length == 3) {
|
} else if (contacts.length === 3) {
|
||||||
return iiii_group;
|
return iiii_group;
|
||||||
} else if (contacts.length == 4) {
|
} else if (contacts.length === 4) {
|
||||||
return iiiii_group;
|
return iiiii_group;
|
||||||
} else {
|
} else {
|
||||||
return group;
|
return group;
|
||||||
@ -204,7 +204,7 @@ export function useContent() {
|
|||||||
const sorted = filtered.sort((a, b) => {
|
const sorted = filtered.sort((a, b) => {
|
||||||
const aUpdated = a?.lastTopic?.created;
|
const aUpdated = a?.lastTopic?.created;
|
||||||
const bUpdated = b?.lastTopic?.created;
|
const bUpdated = b?.lastTopic?.created;
|
||||||
if (aUpdated == bUpdated) {
|
if (aUpdated === bUpdated) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (!aUpdated) {
|
} else if (!aUpdated) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -231,7 +231,7 @@ export function useContent() {
|
|||||||
content.removeChannelListener(setChannels);
|
content.removeChannelListener(setChannels);
|
||||||
settings.removeConfigListener(setConfig);
|
settings.removeConfigListener(setConfig);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [app.state.session]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setSharing: app.actions.setSharing,
|
setSharing: app.actions.setSharing,
|
||||||
@ -244,9 +244,9 @@ export function useContent() {
|
|||||||
setFocus: async (cardId: string | null, channelId: string) => {
|
setFocus: async (cardId: string | null, channelId: string) => {
|
||||||
await app.actions.setFocus(cardId, channelId);
|
await app.actions.setFocus(cardId, channelId);
|
||||||
},
|
},
|
||||||
openTopic: async (cardId: string) => {
|
openTopic: async (contactId: string) => {
|
||||||
const content = app.state.session.getContent()
|
const content = app.state.session.getContent();
|
||||||
const card = state.cards.find(card => card.cardId === cardId)
|
const card = state.cards.find(member => member.cardId === contactId);
|
||||||
if (card) {
|
if (card) {
|
||||||
const sealable = card.sealable && state.sealSet;
|
const sealable = card.sealable && state.sealSet;
|
||||||
const thread = state.sorted.find(channel => {
|
const thread = state.sorted.find(channel => {
|
||||||
@ -256,21 +256,21 @@ export function useContent() {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
if (thread) {
|
if (thread) {
|
||||||
return thread.channelId;
|
return thread.channelId;
|
||||||
} else {
|
} else {
|
||||||
const topic = await content.addChannel(sealable, sealable ? 'sealed' : 'superbasic', {}, [cardId]);
|
const topic = await content.addChannel(sealable, sealable ? 'sealed' : 'superbasic', {}, [cardId]);
|
||||||
return topic.id;
|
return topic.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTopic: async (sealed: boolean, subject: string, contacts: string[]) => {
|
addTopic: async (sealed: boolean, subject: string, contacts: string[]) => {
|
||||||
const content = app.state.session.getContent()
|
const content = app.state.session.getContent();
|
||||||
if (sealed) {
|
if (sealed) {
|
||||||
const topic = await content.addChannel(true, 'sealed', { subject }, contacts)
|
const topic = await content.addChannel(true, 'sealed', { subject }, contacts);
|
||||||
return topic.id;
|
return topic.id;
|
||||||
} else {
|
} else {
|
||||||
const topic = await content.addChannel(false, 'superbasic', { subject }, contacts)
|
const topic = await content.addChannel(false, 'superbasic', { subject }, contacts);
|
||||||
return topic.id;
|
return topic.id;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React, { ReactNode, createContext } from 'react'
|
import React, { ReactNode, createContext } from 'react';
|
||||||
import { useRingContext } from './useRingContext.hook'
|
import { useRingContext } from './useRingContext.hook';
|
||||||
|
|
||||||
export const RingContext = createContext({})
|
export const RingContext = createContext({});
|
||||||
|
|
||||||
export function RingContextProvider({ children }: { children: ReactNode }) {
|
export function RingContextProvider({ children }: { children: ReactNode }) {
|
||||||
const { state, actions } = useRingContext()
|
const { state, actions } = useRingContext();
|
||||||
return <RingContext.Provider value={{ state, actions }}>{children}</RingContext.Provider>
|
return <RingContext.Provider value={{ state, actions }}>{children}</RingContext.Provider>;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import {Platform, PermissionsAndroid} from 'react-native';
|
|||||||
import {SessionStore} from '../SessionStore';
|
import {SessionStore} from '../SessionStore';
|
||||||
import {NativeCrypto} from '../NativeCrypto';
|
import {NativeCrypto} from '../NativeCrypto';
|
||||||
import {LocalStore} from '../LocalStore';
|
import {LocalStore} from '../LocalStore';
|
||||||
import { StagingFiles } from '../StagingFiles'
|
import { StagingFiles } from '../StagingFiles';
|
||||||
import messaging from '@react-native-firebase/messaging';
|
import messaging from '@react-native-firebase/messaging';
|
||||||
|
|
||||||
const DATABAG_DB = 'db_v244.db';
|
const DATABAG_DB = 'db_v244.db';
|
||||||
@ -85,7 +85,7 @@ export function useAppContext() {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
return { token: '', type: '' };
|
return { token: '', type: '' };
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
setMonthFirstDate: async (monthFirstDate: boolean) => {
|
setMonthFirstDate: async (monthFirstDate: boolean) => {
|
||||||
@ -171,7 +171,7 @@ export function useAppContext() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearFocus: () => {
|
clearFocus: () => {
|
||||||
if (state.session) {
|
if (state.session) {
|
||||||
state.session.clearFocus();
|
state.session.clearFocus();
|
||||||
updateState({ focus: null });
|
updateState({ focus: null });
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ export function useDisplayContext() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const layout = dim.width < SMALL_LARGE ? 'small' : 'large';
|
const layout = dim.width < SMALL_LARGE ? 'small' : 'large';
|
||||||
updateState({layout, width: dim.width, height: dim.height});
|
updateState({layout, width: dim.width, height: dim.height});
|
||||||
}, [dim.width]);
|
}, [dim.height, dim.width]);
|
||||||
|
|
||||||
const actions = {};
|
const actions = {};
|
||||||
|
|
||||||
|
@ -1,27 +1,21 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useEffect, useRef } from 'react';
|
||||||
import { DisplayContext } from '../context/DisplayContext';
|
import { AppContext } from '../context/AppContext';
|
||||||
import { AppContext } from '../context/AppContext'
|
import { ContextType } from '../context/ContextType';
|
||||||
import { ContextType } from '../context/ContextType'
|
|
||||||
import { Link, type Card } from 'databag-client-sdk';
|
import { Link, type Card } from 'databag-client-sdk';
|
||||||
import InCallManager from 'react-native-incall-manager';
|
import InCallManager from 'react-native-incall-manager';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ScreenCapturePickerView,
|
|
||||||
RTCPeerConnection,
|
RTCPeerConnection,
|
||||||
RTCIceCandidate,
|
RTCIceCandidate,
|
||||||
RTCSessionDescription,
|
RTCSessionDescription,
|
||||||
RTCView,
|
|
||||||
MediaStream,
|
MediaStream,
|
||||||
MediaiStreamTrack,
|
|
||||||
mediaDevices,
|
mediaDevices,
|
||||||
registerGlobals
|
|
||||||
} from 'react-native-webrtc';
|
} from 'react-native-webrtc';
|
||||||
|
|
||||||
const CLOSE_POLL_MS = 100;
|
const CLOSE_POLL_MS = 100;
|
||||||
|
|
||||||
export function useRingContext() {
|
export function useRingContext() {
|
||||||
const app = useContext(AppContext) as ContextType;
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType;
|
|
||||||
const call = useRef(null as { peer: RTCPeerConnection, link: Link, candidates: RTCIceCandidate[] } | null);
|
const call = useRef(null as { peer: RTCPeerConnection, link: Link, candidates: RTCIceCandidate[] } | null);
|
||||||
const sourceStream = useRef(null as null|MediaStream);
|
const sourceStream = useRef(null as null|MediaStream);
|
||||||
const localStream = useRef(null as null|MediaStream);
|
const localStream = useRef(null as null|MediaStream);
|
||||||
@ -52,12 +46,12 @@ export function useRingContext() {
|
|||||||
connectedTime: 0,
|
connectedTime: 0,
|
||||||
failed: false,
|
failed: false,
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const calls = ringing.map(ring => ({ callId: ring.callId, card: cards.find(card => ring.cardId === card.cardId) }))
|
const calls = ringing.map(ring => ({ callId: ring.callId, card: cards.find(card => ring.cardId === card.cardId) }))
|
||||||
@ -65,18 +59,9 @@ export function useRingContext() {
|
|||||||
updateState({ calls });
|
updateState({ calls });
|
||||||
}, [ringing, cards]);
|
}, [ringing, cards]);
|
||||||
|
|
||||||
const constraints = {
|
|
||||||
mandatory: {
|
|
||||||
OfferToReceiveAudio: true,
|
|
||||||
OfferToReceiveVideo: false,
|
|
||||||
VoiceActivityDetection: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const linkStatus = async (status: string) => {
|
const linkStatus = async (status: string) => {
|
||||||
if (call.current) {
|
if (call.current) {
|
||||||
try {
|
try {
|
||||||
const { peer, link } = call.current;
|
|
||||||
if (status === 'connected') {
|
if (status === 'connected') {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const connectedTime = Math.floor(now.getTime() / 1000);
|
const connectedTime = Math.floor(now.getTime() / 1000);
|
||||||
@ -89,10 +74,10 @@ export function useRingContext() {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const updatePeer = async (type: string, data?: any) => {
|
const updatePeer = async (mode: string, value?: any) => {
|
||||||
peerUpdate.current.push({ type, data });
|
peerUpdate.current.push({ type: mode, data: value });
|
||||||
|
|
||||||
if (!updatingPeer.current) {
|
if (!updatingPeer.current) {
|
||||||
updatingPeer.current = true;
|
updatingPeer.current = true;
|
||||||
@ -114,13 +99,13 @@ export function useRingContext() {
|
|||||||
const offer = new RTCSessionDescription(data.description);
|
const offer = new RTCSessionDescription(data.description);
|
||||||
await peer.setRemoteDescription(offer);
|
await peer.setRemoteDescription(offer);
|
||||||
if (data.description.type === 'offer') {
|
if (data.description.type === 'offer') {
|
||||||
const description = await peer.createAnswer();
|
const desc = await peer.createAnswer();
|
||||||
await peer.setLocalDescription(description);
|
await peer.setLocalDescription(desc);
|
||||||
link.sendMessage({ description });
|
link.sendMessage({ description: desc });
|
||||||
}
|
}
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
await peer.addIceCandidate(candidate);
|
await peer.addIceCandidate(candidate);
|
||||||
};
|
}
|
||||||
call.current.candidates = [];
|
call.current.candidates = [];
|
||||||
} else if (data.candidate) {
|
} else if (data.candidate) {
|
||||||
const candidate = new RTCIceCandidate(data.candidate);
|
const candidate = new RTCIceCandidate(data.candidate);
|
||||||
@ -153,7 +138,7 @@ export function useRingContext() {
|
|||||||
}
|
}
|
||||||
if (data.kind === 'video') {
|
if (data.kind === 'video') {
|
||||||
InCallManager.setForceSpeakerphoneOn(true);
|
InCallManager.setForceSpeakerphoneOn(true);
|
||||||
updateState({ localVideo: true })
|
updateState({ localVideo: true });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -167,7 +152,7 @@ export function useRingContext() {
|
|||||||
}
|
}
|
||||||
updatingPeer.current = false;
|
updatingPeer.current = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const setup = async (link: Link, card: Card, polite: boolean) => {
|
const setup = async (link: Link, card: Card, polite: boolean) => {
|
||||||
|
|
||||||
@ -179,8 +164,8 @@ export function useRingContext() {
|
|||||||
audio: true,
|
audio: true,
|
||||||
video: {
|
video: {
|
||||||
frameRate: 30,
|
frameRate: 30,
|
||||||
facingMode: 'user'
|
facingMode: 'user',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
InCallManager.start({media: 'audio'});
|
InCallManager.start({media: 'audio'});
|
||||||
localAudio.current = sourceStream.current.getTracks().find(track => track.kind === 'audio');
|
localAudio.current = sourceStream.current.getTracks().find(track => track.kind === 'audio');
|
||||||
@ -201,7 +186,7 @@ export function useRingContext() {
|
|||||||
localStream: localStream.current, remoteStream: remoteStream.current });
|
localStream: localStream.current, remoteStream: remoteStream.current });
|
||||||
link.setStatusListener(linkStatus);
|
link.setStatusListener(linkStatus);
|
||||||
link.setMessageListener((msg: any) => updatePeer('message', msg));
|
link.setMessageListener((msg: any) => updatePeer('message', msg));
|
||||||
}
|
};
|
||||||
|
|
||||||
const cleanup = async () => {
|
const cleanup = async () => {
|
||||||
closing.current = true;
|
closing.current = true;
|
||||||
@ -232,11 +217,11 @@ export function useRingContext() {
|
|||||||
updateState({ calling: null, connected: false, connectedTime: 0, fullscreen: false, failed: false,
|
updateState({ calling: null, connected: false, connectedTime: 0, fullscreen: false, failed: false,
|
||||||
localStream: null, remoteStream: null, localVideo: false, remoteVideo: false });
|
localStream: null, remoteStream: null, localVideo: false, remoteVideo: false });
|
||||||
closing.current = false;
|
closing.current = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
const transmit = (ice: { urls: string; username: string; credential: string }[]) => {
|
const transmit = (ice: { urls: string; username: string; credential: string }[]) => {
|
||||||
const peerConnection = new RTCPeerConnection({ iceServers: ice });
|
const peerConnection = new RTCPeerConnection({ iceServers: ice });
|
||||||
peerConnection.addEventListener( 'connectionstatechange', event => {
|
peerConnection.addEventListener( 'connectionstatechange', () => {
|
||||||
if (peerConnection.connectionState === 'failed') {
|
if (peerConnection.connectionState === 'failed') {
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
@ -245,31 +230,31 @@ export function useRingContext() {
|
|||||||
updatePeer('candidate', event.candidate);
|
updatePeer('candidate', event.candidate);
|
||||||
});
|
});
|
||||||
peerConnection.addEventListener( 'icecandidateerror', event => {
|
peerConnection.addEventListener( 'icecandidateerror', event => {
|
||||||
console.log("ICE ERROR");
|
console.log('ICE ERROR', event);
|
||||||
});
|
});
|
||||||
peerConnection.addEventListener( 'iceconnectionstatechange', event => {
|
peerConnection.addEventListener( 'iceconnectionstatechange', event => {
|
||||||
console.log("ICE STATE CHANGE", event);
|
console.log('ICE STATE CHANGE', event);
|
||||||
});
|
});
|
||||||
peerConnection.addEventListener( 'negotiationneeded', event => {
|
peerConnection.addEventListener( 'negotiationneeded', () => {
|
||||||
updatePeer('negotiate');
|
updatePeer('negotiate');
|
||||||
});
|
});
|
||||||
peerConnection.addEventListener( 'signalingstatechange', event => {
|
peerConnection.addEventListener( 'signalingstatechange', event => {
|
||||||
console.log("ICE SIGNALING", event);
|
console.log('ICE SIGNALING', event);
|
||||||
});
|
});
|
||||||
peerConnection.addEventListener( 'track', event => {
|
peerConnection.addEventListener( 'track', event => {
|
||||||
updatePeer('remote_track', event.track);
|
updatePeer('remote_track', event.track);
|
||||||
});
|
});
|
||||||
return peerConnection;
|
return peerConnection;
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (app.state.session) {
|
if (app.state.session) {
|
||||||
const setRing = (ringing: { cardId: string, callId: string }[]) => {
|
const setRing = (incoming: { cardId: string, callId: string }[]) => {
|
||||||
setRinging(ringing);
|
setRinging(incoming);
|
||||||
}
|
};
|
||||||
const setContacts = (cards: Card[]) => {
|
const setContacts = (contacts: Card[]) => {
|
||||||
setCards(cards);
|
setCards(contacts);
|
||||||
}
|
};
|
||||||
const ring = app.state.session.getRing();
|
const ring = app.state.session.getRing();
|
||||||
ring.addRingingListener(setRinging);
|
ring.addRingingListener(setRinging);
|
||||||
const contact = app.state.session.getContact();
|
const contact = app.state.session.getContact();
|
||||||
@ -278,8 +263,9 @@ export function useRingContext() {
|
|||||||
ring.removeRingingListener(setRing);
|
ring.removeRingingListener(setRing);
|
||||||
contact.removeCardListener(setContacts);
|
contact.removeCardListener(setContacts);
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [app.state.session]);
|
}, [app.state.session]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
@ -330,7 +316,7 @@ export function useRingContext() {
|
|||||||
},
|
},
|
||||||
enableAudio: async () => {
|
enableAudio: async () => {
|
||||||
if (closing.current || !call.current) {
|
if (closing.current || !call.current) {
|
||||||
throw new Error('cannot unmute audio')
|
throw new Error('cannot unmute audio');
|
||||||
}
|
}
|
||||||
if (!localAudio.current) {
|
if (!localAudio.current) {
|
||||||
throw new Error('audio not available');
|
throw new Error('audio not available');
|
||||||
@ -377,8 +363,8 @@ export function useRingContext() {
|
|||||||
}
|
}
|
||||||
updateState({ videoEnabled: false });
|
updateState({ videoEnabled: false });
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,10 +95,10 @@ export const styles = StyleSheet.create({
|
|||||||
color: Colors.placeholder,
|
color: Colors.placeholder,
|
||||||
},
|
},
|
||||||
add: {
|
add: {
|
||||||
height: 72,
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
flexDirection: 'column',
|
||||||
justifyContent: 'center',
|
paddingTop: 8,
|
||||||
|
paddingBottom: 8,
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
@ -138,7 +138,6 @@ export const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
alignItems: 'center',
|
|
||||||
},
|
},
|
||||||
largeHeader: {
|
largeHeader: {
|
||||||
paddingLeft: 16,
|
paddingLeft: 16,
|
||||||
@ -159,12 +158,6 @@ export const styles = StyleSheet.create({
|
|||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
},
|
},
|
||||||
add: {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
paddingTop: 8,
|
|
||||||
paddingBottom: 8,
|
|
||||||
},
|
|
||||||
message: {
|
message: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@ -200,5 +193,5 @@ export const styles = StyleSheet.create({
|
|||||||
separator: {
|
separator: {
|
||||||
width: 1,
|
width: 1,
|
||||||
height: '100%',
|
height: '100%',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState, useRef } from 'react';
|
import React, { useEffect, useState, useRef } from 'react';
|
||||||
import {Animated, useAnimatedValue, KeyboardAvoidingView, Modal, Platform, ScrollView, Pressable, View, FlatList, TouchableOpacity} from 'react-native';
|
import {Animated, useAnimatedValue, Modal, ScrollView, Pressable, View, FlatList } from 'react-native';
|
||||||
import {styles} from './Conversation.styled';
|
import {styles} from './Conversation.styled';
|
||||||
import {useConversation} from './useConversation.hook';
|
import {useConversation} from './useConversation.hook';
|
||||||
import {Message} from '../message/Message';
|
import {Message} from '../message/Message';
|
||||||
@ -7,14 +7,14 @@ import {Surface, Icon, Text, TextInput, Menu, IconButton, Divider} from 'react-n
|
|||||||
import { ActivityIndicator } from 'react-native-paper';
|
import { ActivityIndicator } from 'react-native-paper';
|
||||||
import { Colors } from '../constants/Colors';
|
import { Colors } from '../constants/Colors';
|
||||||
import { Confirm } from '../confirm/Confirm';
|
import { Confirm } from '../confirm/Confirm';
|
||||||
import ColorPicker from 'react-native-wheel-color-picker'
|
import ColorPicker from 'react-native-wheel-color-picker';
|
||||||
import {BlurView} from '@react-native-community/blur';
|
import {BlurView} from '@react-native-community/blur';
|
||||||
import ImagePicker from 'react-native-image-crop-picker'
|
import ImagePicker from 'react-native-image-crop-picker';
|
||||||
import { ImageFile } from './imageFile/ImageFile';
|
import { ImageFile } from './imageFile/ImageFile';
|
||||||
import { VideoFile } from './videoFile/VideoFile';
|
import { VideoFile } from './videoFile/VideoFile';
|
||||||
import { AudioFile } from './audioFile/AudioFile';
|
import { AudioFile } from './audioFile/AudioFile';
|
||||||
import { BinaryFile } from './binaryFile/BinaryFile';
|
import { BinaryFile } from './binaryFile/BinaryFile';
|
||||||
import DocumentPicker from 'react-native-document-picker'
|
import DocumentPicker from 'react-native-document-picker';
|
||||||
|
|
||||||
const SCROLL_THRESHOLD = 16;
|
const SCROLL_THRESHOLD = 16;
|
||||||
|
|
||||||
@ -40,8 +40,8 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
const contentHeight = useRef(0);
|
const contentHeight = useRef(0);
|
||||||
const contentLead = useRef(null);
|
const contentLead = useRef(null);
|
||||||
const scrollOffset = useRef(0);
|
const scrollOffset = useRef(0);
|
||||||
const busy = useRef(false);
|
const busy = useRef(false);
|
||||||
const scale = useAnimatedValue(0)
|
const scale = useAnimatedValue(0);
|
||||||
|
|
||||||
const alertParams = {
|
const alertParams = {
|
||||||
title: state.strings.operationFailed,
|
title: state.strings.operationFailed,
|
||||||
@ -68,6 +68,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
useNativeDriver: false,
|
useNativeDriver: false,
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state.assets]);
|
}, [state.assets]);
|
||||||
|
|
||||||
const sendMessage = async () => {
|
const sendMessage = async () => {
|
||||||
@ -84,7 +85,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
setSending(false);
|
setSending(false);
|
||||||
busy.current = false;
|
busy.current = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const loadMore = async () => {
|
const loadMore = async () => {
|
||||||
if (!more) {
|
if (!more) {
|
||||||
@ -92,12 +93,12 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
await actions.more();
|
await actions.more();
|
||||||
setMore(false);
|
setMore(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
actions.close();
|
actions.close();
|
||||||
close();
|
close();
|
||||||
}
|
};
|
||||||
|
|
||||||
const onContent = (width, height) => {
|
const onContent = (width, height) => {
|
||||||
const currentLead = state.topics.length > 0 ? state.topics[0].topicId : null;
|
const currentLead = state.topics.length > 0 ? state.topics[0].topicId : null;
|
||||||
@ -110,7 +111,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
}
|
}
|
||||||
contentLead.current = currentLead;
|
contentLead.current = currentLead;
|
||||||
contentHeight.current = height;
|
contentHeight.current = height;
|
||||||
}
|
};
|
||||||
|
|
||||||
const onScroll = (ev) => {
|
const onScroll = (ev) => {
|
||||||
const { contentOffset } = ev.nativeEvent;
|
const { contentOffset } = ev.nativeEvent;
|
||||||
@ -125,7 +126,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
scrollOffset.current = offset;
|
scrollOffset.current = offset;
|
||||||
}
|
};
|
||||||
|
|
||||||
const addImage = async () => {
|
const addImage = async () => {
|
||||||
try {
|
try {
|
||||||
@ -135,7 +136,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const addVideo = async () => {
|
const addVideo = async () => {
|
||||||
try {
|
try {
|
||||||
@ -145,7 +146,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
catch (err) {
|
catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const addAudio = async () => {
|
const addAudio = async () => {
|
||||||
try {
|
try {
|
||||||
@ -153,12 +154,12 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
presentationStyle: 'fullScreen',
|
presentationStyle: 'fullScreen',
|
||||||
copyTo: 'cachesDirectory',
|
copyTo: 'cachesDirectory',
|
||||||
type: DocumentPicker.types.audio,
|
type: DocumentPicker.types.audio,
|
||||||
})
|
});
|
||||||
actions.addAudio(audio.fileCopyUri, audio.name);
|
actions.addAudio(audio.fileCopyUri, audio.name);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const addBinary = async () => {
|
const addBinary = async () => {
|
||||||
try {
|
try {
|
||||||
@ -166,27 +167,27 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
presentationStyle: 'fullScreen',
|
presentationStyle: 'fullScreen',
|
||||||
copyTo: 'cachesDirectory',
|
copyTo: 'cachesDirectory',
|
||||||
type: DocumentPicker.types.allFiles,
|
type: DocumentPicker.types.allFiles,
|
||||||
})
|
});
|
||||||
actions.addBinary(binary.fileCopyUri, binary.name);
|
actions.addBinary(binary.fileCopyUri, binary.name);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const media = state.assets.map((asset, index) => {
|
const media = state.assets.map((asset, index) => {
|
||||||
if (asset.type === 'image') {
|
if (asset.type === 'image') {
|
||||||
return <ImageFile key={index} path={asset.path} disabled={sending} remove={()=>actions.removeAsset(index)} />
|
return <ImageFile key={index} path={asset.path} disabled={sending} remove={()=>actions.removeAsset(index)} />;
|
||||||
} else if (asset.type === 'video') {
|
} else if (asset.type === 'video') {
|
||||||
return <VideoFile key={index} path={asset.path} thumbPosition={(position: number) => actions.setThumbPosition(index, position)} disabled={sending} remove={()=>actions.removeAsset(index)} />
|
return <VideoFile key={index} path={asset.path} thumbPosition={(position: number) => actions.setThumbPosition(index, position)} disabled={sending} remove={()=>actions.removeAsset(index)} />;
|
||||||
} else if (asset.type === 'audio') {
|
} else if (asset.type === 'audio') {
|
||||||
return <AudioFile key={index} path={asset.path} disabled={sending} remove={()=>actions.removeAsset(index)} />
|
return <AudioFile key={index} path={asset.path} disabled={sending} remove={()=>actions.removeAsset(index)} />;
|
||||||
} else {
|
} else {
|
||||||
return <BinaryFile key={index} path={asset.path} disabled={sending} remove={()=>actions.removeAsset(index)} />
|
return <BinaryFile key={index} path={asset.path} disabled={sending} remove={()=>actions.removeAsset(index)} />;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const containerStyle = state.layout === 'large' ? { ...styles.conversation, ...styles.largeConversation } : styles.conversation;
|
const containerStyle = state.layout === 'large' ? { ...styles.conversation, ...styles.largeConversation } : styles.conversation;
|
||||||
const headerStyle = state.layout === 'large' ? { ...styles.header, ...styles.largeHeader } : styles.header;
|
const headerStyle = state.layout === 'large' ? { ...styles.header, ...styles.largeHeader, flexDirection: 'row-reverse' } : { ...styles.header, flexDirection: 'row' };
|
||||||
const padStyle = state.layout === 'large' ? styles.pad : styles.nopad;
|
const padStyle = state.layout === 'large' ? styles.pad : styles.nopad;
|
||||||
const inputPadStyle = state.layout === 'large' ? styles.pad : styles.indent;
|
const inputPadStyle = state.layout === 'large' ? styles.pad : styles.indent;
|
||||||
const offset = state.layout === 'large' ? state.avoid - 64 : state.avoid - 120;
|
const offset = state.layout === 'large' ? state.avoid - 64 : state.avoid - 120;
|
||||||
@ -194,18 +195,18 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
const disableVideo = !state.detailSet || !state.detail?.enableVideo;
|
const disableVideo = !state.detailSet || !state.detail?.enableVideo;
|
||||||
const disableAudio = !state.detailSet || !state.detail?.enableAudio;
|
const disableAudio = !state.detailSet || !state.detail?.enableAudio;
|
||||||
const disableBinary = !state.detailSet || !state.detail?.enableBinary;
|
const disableBinary = !state.detailSet || !state.detail?.enableBinary;
|
||||||
|
const statusStyle = state.layout === 'large' ? { ...styles.status, flexDirection: 'row-reverse' } : { ...styles.status, flexDirection: 'row' };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={containerStyle}>
|
<View style={containerStyle}>
|
||||||
<View style={{ ...headerStyle, flexDirection: state.layout === 'large' ? 'row-reverse' : 'row' }}>
|
<View style={headerStyle}>
|
||||||
<IconButton style={styles.icon} mode="contained" icon={wide ? 'close' : 'arrow-left'} size={28} onPress={onClose} />
|
<IconButton style={styles.icon} mode="contained" icon={wide ? 'close' : 'arrow-left'} size={28} onPress={onClose} />
|
||||||
<View style={styles.status}>
|
<View style={styles.status} />
|
||||||
</View>
|
|
||||||
<View style={styles.title}>
|
<View style={styles.title}>
|
||||||
{ state.detailSet && state.subject && (
|
{ state.detailSet && state.subject && (
|
||||||
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={styles.label}>{ state.subject }</Text>
|
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={styles.label}>{ state.subject }</Text>
|
||||||
)}
|
)}
|
||||||
{ state.detailSet && state.host && !state.subject && state.subjectNames.length == 0 && (
|
{ state.detailSet && state.host && !state.subject && state.subjectNames.length === 0 && (
|
||||||
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={styles.label}>{ state.strings.notes }</Text>
|
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={styles.label}>{ state.strings.notes }</Text>
|
||||||
)}
|
)}
|
||||||
{ state.detailSet && !state.subject && state.subjectNames.length > 0 && (
|
{ state.detailSet && !state.subject && state.subjectNames.length > 0 && (
|
||||||
@ -215,7 +216,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={styles.unknown}>{ `, ${state.strings.unknownContact} (${state.unknownContacts})` }</Text>
|
<Text adjustsFontSizeToFit={true} numberOfLines={1} style={styles.unknown}>{ `, ${state.strings.unknownContact} (${state.unknownContacts})` }</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
<View style={{ ...styles.status, flexDirection: state.layout === 'large' ? 'row-reverse' : 'row' }}>
|
<View style={statusStyle}>
|
||||||
{ state.detailSet && !state.access && (
|
{ state.detailSet && !state.access && (
|
||||||
<Icon source="alert-circle-outline" size={20} color={Colors.offsync} />
|
<Icon source="alert-circle-outline" size={20} color={Colors.offsync} />
|
||||||
)}
|
)}
|
||||||
@ -229,7 +230,7 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
<Icon source="shield-outline" size={20} />
|
<Icon source="shield-outline" size={20} />
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
<IconButton style={styles.icon} mode="contained" icon={state.layout==='large' ? 'cog-transfer-outline' : 'dots-vertical'} size={28} onPress={openDetails} />
|
<IconButton style={styles.icon} mode="contained" icon={state.layout === 'large' ? 'cog-transfer-outline' : 'dots-vertical'} size={28} onPress={openDetails} />
|
||||||
</View>
|
</View>
|
||||||
<View style={padStyle}>
|
<View style={padStyle}>
|
||||||
<Divider style={styles.topBorder} bold={true} />
|
<Divider style={styles.topBorder} bold={true} />
|
||||||
@ -260,13 +261,13 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
select={(id)=>setSelected(id)}
|
select={(id)=>setSelected(id)}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}}
|
}}
|
||||||
keyExtractor={topic => (topic.topicId)}
|
keyExtractor={topic => (topic.topicId)}
|
||||||
/>
|
/>
|
||||||
{ state.loaded && state.topics.length === 0 && (
|
{ state.loaded && state.topics.length === 0 && (
|
||||||
<Text style={styles.empty}>{state.strings.noMessages}</Text>
|
<Text style={styles.empty}>{state.strings.noMessages}</Text>
|
||||||
)}
|
)}
|
||||||
{ !state.loaded && (
|
{ !state.loaded && (
|
||||||
<View style={styles.loading}>
|
<View style={styles.loading}>
|
||||||
<ActivityIndicator size="large" />
|
<ActivityIndicator size="large" />
|
||||||
@ -334,9 +335,9 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
</Surface>
|
</Surface>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)}>
|
)}>
|
||||||
<Menu.Item onPress={() => { actions.setTextSize(12); setSizeMenu(false) }} title={state.strings.textSmall} />
|
<Menu.Item onPress={() => { actions.setTextSize(12); setSizeMenu(false); }} title={state.strings.textSmall} />
|
||||||
<Menu.Item onPress={() => { actions.setTextSize(16); setSizeMenu(false) }} title={state.strings.textMedium} />
|
<Menu.Item onPress={() => { actions.setTextSize(16); setSizeMenu(false); }} title={state.strings.textMedium} />
|
||||||
<Menu.Item onPress={() => { actions.setTextSize(20); setSizeMenu(false) }} title={state.strings.textLarge} />
|
<Menu.Item onPress={() => { actions.setTextSize(20); setSizeMenu(false); }} title={state.strings.textLarge} />
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<View style={styles.end}>
|
<View style={styles.end}>
|
||||||
@ -345,10 +346,10 @@ export function Conversation({close, openDetails, wide}: {close: ()=>void, openD
|
|||||||
{ sending && (
|
{ sending && (
|
||||||
<ActivityIndicator size="small" />
|
<ActivityIndicator size="small" />
|
||||||
)}
|
)}
|
||||||
{ !sending && state.access && state.validShare && (state.message || state.assets.length != 0) && (
|
{ !sending && state.access && state.validShare && (state.message || state.assets.length !== 0) && (
|
||||||
<Icon style={styles.button} source="send" size={24} color={Colors.primary} />
|
<Icon style={styles.button} source="send" size={24} color={Colors.primary} />
|
||||||
)}
|
)}
|
||||||
{ !sending && (!state.access || !state.validShare || (!state.message && state.assets.length == 0)) && (
|
{ !sending && (!state.access || !state.validShare || (!state.message && state.assets.length === 0)) && (
|
||||||
<Icon style={styles.button} source="send" size={24} color={Colors.placeholder} />
|
<Icon style={styles.button} source="send" size={24} color={Colors.placeholder} />
|
||||||
)}
|
)}
|
||||||
</Surface>
|
</Surface>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import {Colors} from '../constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
audio: {
|
audio: {
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React from 'react';
|
||||||
import { View, Image } from 'react-native'
|
import { View, Image } from 'react-native';
|
||||||
import { IconButton } from 'react-native-paper';
|
import { IconButton } from 'react-native-paper';
|
||||||
import { useAudioFile } from './useAudioFile.hook';
|
import {styles} from './AudioFile.styled';
|
||||||
import {styles} from './AudioFile.styled'
|
|
||||||
import thumb from '../../images/audio.png';
|
import thumb from '../../images/audio.png';
|
||||||
|
|
||||||
export function AudioFile({ path, disabled, remove }: {path: string, disabled: boolean, remove: ()=>void}) {
|
export function AudioFile({ disabled, remove }: {path: string, disabled: boolean, remove: ()=>void}) {
|
||||||
const { state, actions } = useAudioFile();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.audio}>
|
<View style={styles.audio}>
|
||||||
<Image
|
<Image
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react'
|
|
||||||
|
|
||||||
export function useAudioFile(path: string) {
|
|
||||||
const [state, setState] = useState({
|
|
||||||
})
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
|
||||||
setState((s) => ({ ...s, ...value }))
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
}
|
|
||||||
|
|
||||||
return { state, actions }
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import {Colors} from '../constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
binary: {
|
binary: {
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React from 'react';
|
||||||
import { View, Image } from 'react-native'
|
import { View, Image } from 'react-native';
|
||||||
import { IconButton } from 'react-native-paper'
|
import { IconButton } from 'react-native-paper';
|
||||||
import { useBinaryFile } from './useBinaryFile.hook';
|
import {styles} from './BinaryFile.styled';
|
||||||
import {styles} from './BinaryFile.styled'
|
|
||||||
import thumb from '../../images/binary.png';
|
import thumb from '../../images/binary.png';
|
||||||
|
|
||||||
export function BinaryFile({ path, disabled, remove }: {path: string, disabled: boolean, remove: ()=>void}) {
|
export function BinaryFile({ disabled, remove }: {path: string, disabled: boolean, remove: ()=>void}) {
|
||||||
const { state, actions } = useBinaryFile();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.binary}>
|
<View style={styles.binary}>
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react'
|
|
||||||
|
|
||||||
export function useBinaryFile(path: string) {
|
|
||||||
const [state, setState] = useState({
|
|
||||||
})
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
|
||||||
setState((s) => ({ ...s, ...value }))
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
}
|
|
||||||
|
|
||||||
return { state, actions }
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import {Colors} from '../constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
image: {
|
image: {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Image, View, Animated, useAnimatedValue } from 'react-native'
|
import { Image, View, Animated, useAnimatedValue } from 'react-native';
|
||||||
import { IconButton, Text } from 'react-native-paper';
|
import { IconButton } from 'react-native-paper';
|
||||||
import { useImageFile } from './useImageFile.hook';
|
import { useImageFile } from './useImageFile.hook';
|
||||||
import {styles} from './ImageFile.styled'
|
import {styles} from './ImageFile.styled';
|
||||||
|
|
||||||
export function ImageFile({ path, disabled, remove }: {path: string, disabled: boolean, remove: ()=>void}) {
|
export function ImageFile({ path, disabled, remove }: {path: string, disabled: boolean, remove: ()=>void}) {
|
||||||
const { state, actions } = useImageFile();
|
const { state, actions } = useImageFile();
|
||||||
@ -16,21 +16,12 @@ export function ImageFile({ path, disabled, remove }: {path: string, disabled: b
|
|||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state.loaded]);
|
}, [state.loaded]);
|
||||||
|
|
||||||
const showImage = () => {
|
|
||||||
setModal(true);
|
|
||||||
actions.loadImage();
|
|
||||||
};
|
|
||||||
|
|
||||||
const hideImage = () => {
|
|
||||||
setModal(false);
|
|
||||||
actions.cancelLoad();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.image}>
|
<View style={styles.image}>
|
||||||
<Animated.View style={[styles.thumb,{opacity},]}>
|
<Animated.View style={[styles.thumb,{opacity}]}>
|
||||||
<Image
|
<Image
|
||||||
resizeMode="contain"
|
resizeMode="contain"
|
||||||
height={72}
|
height={72}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState } from 'react';
|
||||||
|
|
||||||
export function useImageFile(source: any) {
|
export function useImageFile() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
ratio: 1,
|
ratio: 1,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
loaded: (e) => {
|
loaded: (e) => {
|
||||||
const { width, height } = e.nativeEvent.source;
|
const { width, height } = e.nativeEvent.source;
|
||||||
updateState({ loaded: true, ratio: width / height });
|
updateState({ loaded: true, ratio: width / height });
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,41 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useEffect, useRef } from 'react';
|
||||||
import { Keyboard } from 'react-native'
|
import { Keyboard } from 'react-native';
|
||||||
import { AppContext } from '../context/AppContext'
|
import { AppContext } from '../context/AppContext';
|
||||||
import { DisplayContext } from '../context/DisplayContext'
|
import { DisplayContext } from '../context/DisplayContext';
|
||||||
import { Focus, FocusDetail, Topic, Profile, Card, AssetType, AssetSource, HostingMode, TransformType } from 'databag-client-sdk'
|
import { Focus, FocusDetail, Topic, Profile, Card, AssetType, AssetSource, TransformType } from 'databag-client-sdk';
|
||||||
import { ContextType } from '../context/ContextType'
|
import { ContextType } from '../context/ContextType';
|
||||||
import { placeholder } from '../constants/Icons';
|
|
||||||
import RNFS from 'react-native-fs';
|
import RNFS from 'react-native-fs';
|
||||||
import ImageResizer from '@bam.tech/react-native-image-resizer';
|
import ImageResizer from '@bam.tech/react-native-image-resizer';
|
||||||
import { createThumbnail } from "react-native-create-thumbnail";
|
import { createThumbnail } from 'react-native-create-thumbnail';
|
||||||
import fileType from 'react-native-file-type'
|
import fileType from 'react-native-file-type';
|
||||||
|
|
||||||
const IMAGE_SCALE_SIZE = (128 * 1024);
|
const IMAGE_SCALE_SIZE = (128 * 1024);
|
||||||
const GIF_TYPE = 'image/gif';
|
|
||||||
const WEBP_TYPE = 'image/webp';
|
|
||||||
const LOAD_DEBOUNCE = 1000;
|
const LOAD_DEBOUNCE = 1000;
|
||||||
|
|
||||||
async function getImageThumb(path: string, type: string, size: number) {
|
async function getImageThumb(path: string, type: string, size: number) {
|
||||||
if (size < IMAGE_SCALE_SIZE) {
|
if (size < IMAGE_SCALE_SIZE) {
|
||||||
const type = await fileType(path);
|
const info = await fileType(path);
|
||||||
const base = await RNFS.readFile(path, 'base64')
|
const base = await RNFS.readFile(path, 'base64');
|
||||||
return `data:image/${type.ext};base64,${base}`;
|
return `data:image/${info.ext};base64,${base}`;
|
||||||
} else {
|
} else {
|
||||||
const thumb = await ImageResizer.createResizedImage(path, 192, 192, "JPEG", 50, 0, null);
|
const thumb = await ImageResizer.createResizedImage(path, 192, 192, 'JPEG', 50, 0, null);
|
||||||
const base = await RNFS.readFile(thumb.path, 'base64')
|
const base = await RNFS.readFile(thumb.path, 'base64');
|
||||||
return `data:image/jpeg;base64,${base}`;
|
return `data:image/jpeg;base64,${base}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getVideoThumb(path: string, position?: number) {
|
async function getVideoThumb(path: string, position?: number) {
|
||||||
const timeStamp = position ? position * 1000 : 0;
|
const timeStamp = position ? position * 1000 : 0;
|
||||||
const shot = await createThumbnail({ url: path, timeStamp })
|
const shot = await createThumbnail({ url: path, timeStamp });
|
||||||
const thumb = await ImageResizer.createResizedImage('file://' + shot.path, 192, 192, "JPEG", 50, 0, null);
|
const thumb = await ImageResizer.createResizedImage('file://' + shot.path, 192, 192, 'JPEG', 50, 0, null);
|
||||||
const base = await RNFS.readFile(thumb.path, 'base64')
|
const base = await RNFS.readFile(thumb.path, 'base64');
|
||||||
return `data:image/jpeg;base64,${base}`;
|
return `data:image/jpeg;base64,${base}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useConversation() {
|
export function useConversation() {
|
||||||
const mute = useRef(false);
|
const mute = useRef(false);
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
detail: undefined as FocusDetail | null | undefined,
|
detail: undefined as FocusDetail | null | undefined,
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
@ -66,19 +63,19 @@ export function useConversation() {
|
|||||||
progress: 0,
|
progress: 0,
|
||||||
avoid: 0,
|
avoid: 0,
|
||||||
validShare: true,
|
validShare: true,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
const updateAsset = (index: number, value: any) => {
|
const updateAsset = (index: number, value: any) => {
|
||||||
setState((s) => {
|
setState((s) => {
|
||||||
s.assets[index] = { ...s.assets[index], ...value };
|
s.assets[index] = { ...s.assets[index], ...value };
|
||||||
return { ...s };
|
return { ...s };
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let validShare = true;
|
let validShare = true;
|
||||||
@ -104,14 +101,14 @@ export function useConversation() {
|
|||||||
const { sharing, focus } = app.state;
|
const { sharing, focus } = app.state;
|
||||||
if (sharing && focus && state.loaded) {
|
if (sharing && focus && state.loaded) {
|
||||||
const focused = focus.getFocused();
|
const focused = focus.getFocused();
|
||||||
if (focused.cardId == sharing.cardId && focused.channelId == sharing.channelId) {
|
if (focused.cardId === sharing.cardId && focused.channelId === sharing.channelId) {
|
||||||
const { mimeType, filePath } = sharing;
|
const { mimeType, filePath } = sharing;
|
||||||
const ext = mimeType.toLowerCase();
|
const ext = mimeType.toLowerCase();
|
||||||
if (ext == '.jpg' || ext == 'image/jpeg' || ext == '.png' || ext == 'image/png' || ext == '.webp' || ext == 'image/webp' || ext == '.bmp' || ext == 'image/bmp' || ext == '.gif' || ext == 'image/gif') {
|
if (ext === '.jpg' || ext === 'image/jpeg' || ext === '.png' || ext === 'image/png' || ext === '.webp' || ext === 'image/webp' || ext === '.bmp' || ext === 'image/bmp' || ext === '.gif' || ext === 'image/gif') {
|
||||||
actions.addImage(filePath, mimeType, IMAGE_SCALE_SIZE);
|
actions.addImage(filePath, mimeType, IMAGE_SCALE_SIZE);
|
||||||
} else if (ext == '.mp4' || ext == 'videp/mp4' || ext == '.mov' || ext == 'video/mov') {
|
} else if (ext === '.mp4' || ext === 'videp/mp4' || ext === '.mov' || ext === 'video/mov') {
|
||||||
actions.addVideo(filePath, mimeType);
|
actions.addVideo(filePath, mimeType);
|
||||||
} else if (ext == '.mp3' || ext == 'audio/mp3' || ext == '.aac' || ext == 'audio/aac') {
|
} else if (ext === '.mp3' || ext === 'audio/mp3' || ext === '.aac' || ext === 'audio/aac') {
|
||||||
actions.addAudio(filePath, mimeType);
|
actions.addAudio(filePath, mimeType);
|
||||||
} else {
|
} else {
|
||||||
actions.addBinary(filePath, filePath.split('/').pop());
|
actions.addBinary(filePath, filePath.split('/').pop());
|
||||||
@ -119,12 +116,13 @@ export function useConversation() {
|
|||||||
app.actions.clearSharing();
|
app.actions.clearSharing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [app.state, state.loaded]);
|
}, [app.state, state.loaded]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { layout, strings } = display.state
|
const { layout, strings } = display.state;
|
||||||
updateState({ layout, strings })
|
updateState({ layout, strings });
|
||||||
}, [display.state])
|
}, [display.state]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const host = state.cardId == null;
|
const host = state.cardId == null;
|
||||||
@ -132,8 +130,8 @@ export function useConversation() {
|
|||||||
const access = (state.detail != null);
|
const access = (state.detail != null);
|
||||||
const subject = state.detail?.data?.subject ? state.detail.data.subject : null;
|
const subject = state.detail?.data?.subject ? state.detail.data.subject : null;
|
||||||
const cards = Array.from(state.cards.values());
|
const cards = Array.from(state.cards.values());
|
||||||
const card = cards.find(entry => entry.cardId == state.cardId);
|
const card = cards.find(entry => entry.cardId === state.cardId);
|
||||||
const profileRemoved = state.detail?.members ? state.detail.members.filter(member => state.profile?.guid != member.guid) : [];
|
const profileRemoved = state.detail?.members ? state.detail.members.filter(member => state.profile?.guid !== member.guid) : [];
|
||||||
const unhostedCards = profileRemoved.map(member => state.cards.get(member.guid));
|
const unhostedCards = profileRemoved.map(member => state.cards.get(member.guid));
|
||||||
const contactCards = card ? [ card, ...unhostedCards ] : unhostedCards;
|
const contactCards = card ? [ card, ...unhostedCards ] : unhostedCards;
|
||||||
const subjectCards = contactCards.filter(member => Boolean(member));
|
const subjectCards = contactCards.filter(member => Boolean(member));
|
||||||
@ -160,25 +158,25 @@ export function useConversation() {
|
|||||||
});
|
});
|
||||||
updateState({ topics: sorted, loaded: true });
|
updateState({ topics: sorted, loaded: true });
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const setCards = (cards: Card[]) => {
|
const setCards = (cards: Card[]) => {
|
||||||
const contacts = new Map<string, Card>();
|
const contacts = new Map<string, Card>();
|
||||||
cards.forEach(card => {
|
cards.forEach(card => {
|
||||||
contacts.set(card.guid, card);
|
contacts.set(card.guid, card);
|
||||||
});
|
});
|
||||||
updateState({ cards: contacts });
|
updateState({ cards: contacts });
|
||||||
}
|
};
|
||||||
const setProfile = (profile: Profile) => {
|
const setProfile = (profile: Profile) => {
|
||||||
updateState({ profile });
|
updateState({ profile });
|
||||||
}
|
};
|
||||||
const setDetail = (focused: { cardId: string | null, channelId: string, detail: FocusDetail | null }) => {
|
const setDetail = (focused: { cardId: string | null, channelId: string, detail: FocusDetail | null }) => {
|
||||||
const detail = focused ? focused.detail : null;
|
const detail = focused ? focused.detail : null;
|
||||||
const cardId = focused.cardId;
|
const cardId = focused.cardId;
|
||||||
updateState({ detail, cardId });
|
updateState({ detail, cardId });
|
||||||
}
|
};
|
||||||
const setKeyboard = (event: KeyboardEvent) => {
|
const setKeyboard = (event: KeyboardEvent) => {
|
||||||
updateState({ avoid: event.endCoordinates.height });
|
updateState({ avoid: event.endCoordinates.height });
|
||||||
}
|
};
|
||||||
updateState({ assets: [], message: null, topics: [], loaded: false });
|
updateState({ assets: [], message: null, topics: [], loaded: false });
|
||||||
focus.addTopicListener(setTopics);
|
focus.addTopicListener(setTopics);
|
||||||
focus.addDetailListener(setDetail);
|
focus.addDetailListener(setDetail);
|
||||||
@ -191,9 +189,9 @@ export function useConversation() {
|
|||||||
contact.removeCardListener(setCards);
|
contact.removeCardListener(setCards);
|
||||||
identity.removeProfileListener(setProfile);
|
identity.removeProfileListener(setProfile);
|
||||||
keyboard.remove();
|
keyboard.remove();
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}, [app.state.focus]);
|
}, [app.state.session, app.state.focus]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
close: () => {
|
close: () => {
|
||||||
@ -246,55 +244,55 @@ export function useConversation() {
|
|||||||
if (sealed) {
|
if (sealed) {
|
||||||
sources.push({ type: AssetType.Image, source: asset.path, transforms: [
|
sources.push({ type: AssetType.Image, source: asset.path, transforms: [
|
||||||
{ type: TransformType.Thumb, appId: `it${sources.length}`, thumb: async () => await getImageThumb(asset.path, asset.type, asset.size) },
|
{ type: TransformType.Thumb, appId: `it${sources.length}`, thumb: async () => await getImageThumb(asset.path, asset.type, asset.size) },
|
||||||
{ type: TransformType.Copy, appId: `ic${sources.length}` }
|
{ type: TransformType.Copy, appId: `ic${sources.length}` },
|
||||||
]});
|
]});
|
||||||
return { encrypted: { type: 'image', thumb: `it${sources.length-1}`, parts: `ic${sources.length-1}` } };
|
return { encrypted: { type: 'image', thumb: `it${sources.length - 1}`, parts: `ic${sources.length - 1}` } };
|
||||||
} else {
|
} else {
|
||||||
sources.push({ type: AssetType.Image, source: asset.path, transforms: [
|
sources.push({ type: AssetType.Image, source: asset.path, transforms: [
|
||||||
{ type: TransformType.Thumb, appId: `it${sources.length}` },
|
{ type: TransformType.Thumb, appId: `it${sources.length}` },
|
||||||
{ type: TransformType.Copy, appId: `ic${sources.length}` }
|
{ type: TransformType.Copy, appId: `ic${sources.length}` },
|
||||||
]});
|
]});
|
||||||
return { image: { thumb: `it${sources.length-1}`, full: `ic${sources.length-1}` } };
|
return { image: { thumb: `it${sources.length - 1}`, full: `ic${sources.length - 1}` } };
|
||||||
}
|
}
|
||||||
} else if (asset.type === 'video') {
|
} else if (asset.type === 'video') {
|
||||||
if (sealed) {
|
if (sealed) {
|
||||||
sources.push({ type: AssetType.Video, source: asset.path, transforms: [
|
sources.push({ type: AssetType.Video, source: asset.path, transforms: [
|
||||||
{ type: TransformType.Thumb, appId: `vt${sources.length}`, thumb: async () => await getVideoThumb(asset.path, asset.position) },
|
{ type: TransformType.Thumb, appId: `vt${sources.length}`, thumb: async () => await getVideoThumb(asset.path, asset.position) },
|
||||||
{ type: TransformType.Copy, appId: `vc${sources.length}` }
|
{ type: TransformType.Copy, appId: `vc${sources.length}` },
|
||||||
]});
|
]});
|
||||||
return { encrypted: { type: 'video', thumb: `vt${sources.length-1}`, parts: `vc${sources.length-1}` } };
|
return { encrypted: { type: 'video', thumb: `vt${sources.length - 1}`, parts: `vc${sources.length - 1}` } };
|
||||||
} else {
|
} else {
|
||||||
sources.push({ type: AssetType.Video, source: asset.path, transforms: [
|
sources.push({ type: AssetType.Video, source: asset.path, transforms: [
|
||||||
{ type: TransformType.Thumb, appId: `vt${sources.length}`, position: asset.position},
|
{ type: TransformType.Thumb, appId: `vt${sources.length}`, position: asset.position},
|
||||||
{ type: TransformType.HighQuality, appId: `vh${sources.length}` },
|
{ type: TransformType.HighQuality, appId: `vh${sources.length}` },
|
||||||
{ type: TransformType.LowQuality, appId: `vl${sources.length}` }
|
{ type: TransformType.LowQuality, appId: `vl${sources.length}` },
|
||||||
]});
|
]});
|
||||||
return { video: { thumb: `vt${sources.length-1}`, hd: `vh${sources.length-1}`, lq: `vl${sources.length-1}` } };
|
return { video: { thumb: `vt${sources.length - 1}`, hd: `vh${sources.length - 1}`, lq: `vl${sources.length - 1}` } };
|
||||||
}
|
}
|
||||||
} else if (asset.type === 'audio') {
|
} else if (asset.type === 'audio') {
|
||||||
if (sealed) {
|
if (sealed) {
|
||||||
sources.push({ type: AssetType.Audio, source: asset.path, transforms: [
|
sources.push({ type: AssetType.Audio, source: asset.path, transforms: [
|
||||||
{ type: TransformType.Copy, appId: `ac${sources.length}` }
|
{ type: TransformType.Copy, appId: `ac${sources.length}` },
|
||||||
]});
|
]});
|
||||||
return { encrypted: { type: 'audio', label: asset.label, parts: `ac${sources.length-1}` } };
|
return { encrypted: { type: 'audio', label: asset.label, parts: `ac${sources.length - 1}` } };
|
||||||
} else {
|
} else {
|
||||||
sources.push({ type: AssetType.Audio, source: asset.path, transforms: [
|
sources.push({ type: AssetType.Audio, source: asset.path, transforms: [
|
||||||
{ type: TransformType.Copy, appId: `ac${sources.length}` }
|
{ type: TransformType.Copy, appId: `ac${sources.length}` },
|
||||||
]});
|
]});
|
||||||
return { audio: { label: asset.label, full: `ac${sources.length-1}` } };
|
return { audio: { label: asset.label, full: `ac${sources.length - 1}` } };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const { label, extension } = asset;
|
const { label, extension } = asset;
|
||||||
if (sealed) {
|
if (sealed) {
|
||||||
sources.push({ type: AssetType.Binary, source: asset.path, transforms: [
|
sources.push({ type: AssetType.Binary, source: asset.path, transforms: [
|
||||||
{ type: TransformType.Copy, appId: `bc${sources.length}` }
|
{ type: TransformType.Copy, appId: `bc${sources.length}` },
|
||||||
]});
|
]});
|
||||||
return { encrypted: { type: 'binary', label, extension, parts: `bc${sources.length-1}` } };
|
return { encrypted: { type: 'binary', label, extension, parts: `bc${sources.length - 1}` } };
|
||||||
} else {
|
} else {
|
||||||
sources.push({ type: AssetType.Binary, source: asset.path, transforms: [
|
sources.push({ type: AssetType.Binary, source: asset.path, transforms: [
|
||||||
{ type: TransformType.Copy, appId: `bc${sources.length}` }
|
{ type: TransformType.Copy, appId: `bc${sources.length}` },
|
||||||
]});
|
]});
|
||||||
return { binary: { label, extension, data: `bc${sources.length-1}` } };
|
return { binary: { label, extension, data: `bc${sources.length - 1}` } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -333,8 +331,8 @@ export function useConversation() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { text: state.message, textColor: state.textColorSet ? state.textColor : null, textSize: state.textSizeSet ? state.textSize : null, assets: assets.length > 0 ? assets : null };
|
return { text: state.message, textColor: state.textColorSet ? state.textColor : null, textSize: state.textSizeSet ? state.textSize : null, assets: assets.length > 0 ? assets : null };
|
||||||
}
|
};
|
||||||
const upload = (progress: number) => { updateState({ progress }) };
|
const upload = (progress: number) => { updateState({ progress }); };
|
||||||
await focus.addTopic(sealed, sealed ? 'sealedtopic' : 'superbasictopic', subject, sources, upload);
|
await focus.addTopic(sealed, sealed ? 'sealedtopic' : 'superbasictopic', subject, sources, upload);
|
||||||
|
|
||||||
mute.current = true;
|
mute.current = true;
|
||||||
@ -343,7 +341,7 @@ export function useConversation() {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
updateState({ message: null, assets: [], progress: 0 });
|
updateState({ message: null, assets: [], progress: 0 });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addImage: (path: string, mime: string, size: number) => {
|
addImage: (path: string, mime: string, size: number) => {
|
||||||
const type = 'image';
|
const type = 'image';
|
||||||
updateState({ assets: [ ...state.assets, { type, path, mime, size } ]});
|
updateState({ assets: [ ...state.assets, { type, path, mime, size } ]});
|
||||||
@ -360,7 +358,7 @@ export function useConversation() {
|
|||||||
const type = 'binary';
|
const type = 'binary';
|
||||||
updateState({ assets: [ ...state.assets, { type, path, label: name.split('.').shift(), extension: name.split('.').pop() } ]});
|
updateState({ assets: [ ...state.assets, { type, path, label: name.split('.').shift(), extension: name.split('.').pop() } ]});
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import {Colors} from '../constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
video: {
|
video: {
|
||||||
@ -18,5 +17,5 @@ export const styles = StyleSheet.create({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { Pressable, View, Animated, useAnimatedValue } from 'react-native'
|
import { Pressable, View, Animated, useAnimatedValue } from 'react-native';
|
||||||
import { Icon, IconButton, Text } from 'react-native-paper';
|
import { Icon, IconButton } from 'react-native-paper';
|
||||||
import { useVideoFile } from './useVideoFile.hook';
|
import { useVideoFile } from './useVideoFile.hook';
|
||||||
import {styles} from './VideoFile.styled'
|
import {styles} from './VideoFile.styled';
|
||||||
import Video, { VideoRef } from 'react-native-video'
|
import Video, { VideoRef } from 'react-native-video';
|
||||||
|
|
||||||
export function VideoFile({ path, thumbPosition, disabled, remove }: {path: string, thumbPosition: (position: number)=>void, disabled: boolean, remove: ()=>void}) {
|
export function VideoFile({ path, thumbPosition, disabled, remove }: {path: string, thumbPosition: (position: number)=>void, disabled: boolean, remove: ()=>void}) {
|
||||||
const { state, actions } = useVideoFile();
|
const { state, actions } = useVideoFile();
|
||||||
@ -17,7 +17,7 @@ export function VideoFile({ path, thumbPosition, disabled, remove }: {path: stri
|
|||||||
thumbPosition(pos);
|
thumbPosition(pos);
|
||||||
videoRef.current.seek(pos);
|
videoRef.current.seek(pos);
|
||||||
setSeek(pos);
|
setSeek(pos);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.loaded) {
|
if (state.loaded) {
|
||||||
@ -27,11 +27,12 @@ export function VideoFile({ path, thumbPosition, disabled, remove }: {path: stri
|
|||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state.loaded]);
|
}, [state.loaded]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.video}>
|
<View style={styles.video}>
|
||||||
<Animated.View style={[{...styles.thumb, width: 72 * state.ratio},{opacity},]}>
|
<Animated.View style={[{...styles.thumb, width: 72 * state.ratio},{opacity}]}>
|
||||||
<Video ref={videoRef} source={{ uri: path }} height={72} width={72 * state.ratio} paused={true} controls={false} resizeMode="contain" onLoad={actions.loaded} />
|
<Video ref={videoRef} source={{ uri: path }} height={72} width={72 * state.ratio} paused={true} controls={false} resizeMode="contain" onLoad={actions.loaded} />
|
||||||
{ !disabled && (
|
{ !disabled && (
|
||||||
<Pressable style={styles.next} height={72} width={72 * state.ratio} onPress={next}>
|
<Pressable style={styles.next} height={72} width={72 * state.ratio} onPress={next}>
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState } from 'react';
|
||||||
|
|
||||||
export function useVideoFile(source: any) {
|
export function useVideoFile() {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
loaded: false,
|
loaded: false,
|
||||||
ratio: 1,
|
ratio: 1,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
loaded: (e) => {
|
loaded: (e) => {
|
||||||
const { width, height } = e.naturalSize;
|
const { width, height } = e.naturalSize;
|
||||||
updateState({ loaded: true, ratio: width / height, duration: e.duration });
|
updateState({ loaded: true, ratio: width / height, duration: e.duration });
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -107,6 +107,7 @@ export const styles = StyleSheet.create({
|
|||||||
backgroundColor: 'yellow',
|
backgroundColor: 'yellow',
|
||||||
},
|
},
|
||||||
members: {
|
members: {
|
||||||
|
width: '100%',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -133,13 +134,10 @@ export const styles = StyleSheet.create({
|
|||||||
top: 8,
|
top: 8,
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
padding: 0,
|
padding: 0,
|
||||||
margin: 0,
|
margin: 0,
|
||||||
},
|
},
|
||||||
membership: {
|
membership: {
|
||||||
},
|
},
|
||||||
members: {
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
card: {
|
card: {
|
||||||
paddingBottom: 8,
|
paddingBottom: 8,
|
||||||
paddingTop: 8,
|
paddingTop: 8,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { SafeAreaView, Platform, Modal, ScrollView, View } from 'react-native';
|
import { SafeAreaView, Platform, Modal, ScrollView, View } from 'react-native';
|
||||||
import {useTheme, Switch, Surface, Icon, Divider, Button, IconButton, Text, TextInput} from 'react-native-paper';
|
import {useTheme, Switch, Surface, Icon, Divider, Button, IconButton, Text, TextInput} from 'react-native-paper';
|
||||||
import {styles} from './Details.styled';
|
import {styles} from './Details.styled';
|
||||||
@ -24,34 +24,34 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
const membership = () => {
|
const membership = () => {
|
||||||
setError(false);
|
setError(false);
|
||||||
setMemberModal(true);
|
setMemberModal(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
const remove = () => {
|
const remove = () => {
|
||||||
const apply = async () => {
|
const apply = async () => {
|
||||||
await actions.remove();
|
await actions.remove();
|
||||||
closeAll();
|
closeAll();
|
||||||
}
|
};
|
||||||
confirmAction(state.strings.confirmTopic, state.strings.sureTopic, state.strings.remove, setRemoving, apply);
|
confirmAction(state.strings.confirmTopic, state.strings.sureTopic, state.strings.remove, setRemoving, apply);
|
||||||
}
|
};
|
||||||
|
|
||||||
const leave = () => {
|
const leave = () => {
|
||||||
const apply = async () => {
|
const apply = async () => {
|
||||||
await actions.leave();
|
await actions.leave();
|
||||||
closeAll();
|
closeAll();
|
||||||
}
|
};
|
||||||
confirmAction(state.strings.confirmLeave, state.strings.sureLeave, state.strings.leave, setRemoving, apply);
|
confirmAction(state.strings.confirmLeave, state.strings.sureLeave, state.strings.leave, setRemoving, apply);
|
||||||
}
|
};
|
||||||
|
|
||||||
const block = () => {
|
const block = () => {
|
||||||
const apply = async () => {
|
const apply = async () => {
|
||||||
await actions.block();
|
await actions.block();
|
||||||
}
|
};
|
||||||
confirmAction(state.strings.blockTopic, state.strings.blockTopicPrompt, state.strings.block, setBlocking, apply);
|
confirmAction(state.strings.blockTopic, state.strings.blockTopicPrompt, state.strings.block, setBlocking, apply);
|
||||||
}
|
};
|
||||||
|
|
||||||
const report = () => {
|
const report = () => {
|
||||||
confirmAction(state.strings.reportTopic, state.strings.reportTopicPrompt, state.strings.report, setReporting, actions.report);
|
confirmAction(state.strings.reportTopic, state.strings.reportTopicPrompt, state.strings.report, setReporting, actions.report);
|
||||||
}
|
};
|
||||||
|
|
||||||
const confirmAction = (title: string, prompt: string, label: string, loading: (boolean) => void, action: () => Promise<void>) => {
|
const confirmAction = (title: string, prompt: string, label: string, loading: (boolean) => void, action: () => Promise<void>) => {
|
||||||
setConfirmParams({
|
setConfirmParams({
|
||||||
@ -77,16 +77,6 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
setConfirm(true);
|
setConfirm(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyAction = async (loading: (boolean) => void, action: () => Promise<void>) => {
|
|
||||||
if (!busy) {
|
|
||||||
setBusy(true);
|
|
||||||
loading(true);
|
|
||||||
await setAction(action);
|
|
||||||
loading(false);
|
|
||||||
setBusy(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const setAction = async (action: () => Promise<void>) => {
|
const setAction = async (action: () => Promise<void>) => {
|
||||||
try {
|
try {
|
||||||
await action();
|
await action();
|
||||||
@ -126,13 +116,13 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
setAlert(true);
|
setAlert(true);
|
||||||
}
|
}
|
||||||
setSaving(false);
|
setSaving(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const cards = state.channelCards.map((card, index) => (
|
const cards = state.channelCards.map((card, index) => (
|
||||||
<Card containerStyle={{...styles.card, borderColor: theme.colors.outlineVariant }} key={index} imageUrl={card.imageUrl} name={card.name} placeholder={state.strings.name}
|
<Card containerStyle={{...styles.card, borderColor: theme.colors.outlineVariant }} key={index} imageUrl={card.imageUrl} name={card.name} placeholder={state.strings.name}
|
||||||
handle={card.handle} node={card.node} actions={[]} />
|
handle={card.handle} node={card.node} actions={[]} />
|
||||||
))
|
));
|
||||||
|
|
||||||
const members = state.cards.filter(card => {
|
const members = state.cards.filter(card => {
|
||||||
if (state.detail && state.detail.members.find(member => member.guid === card.guid)) {
|
if (state.detail && state.detail.members.find(member => member.guid === card.guid)) {
|
||||||
@ -161,12 +151,12 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
setError(true);
|
setError(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>,
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card containerStyle={{ ...styles.card, borderColor: theme.colors.outlineVariant }} key={index} imageUrl={card.imageUrl} name={card.name} placeholder={state.strings.name} handle={card.handle} node={card.node} actions={enable} />
|
<Card containerStyle={{ ...styles.card, borderColor: theme.colors.outlineVariant }} key={index} imageUrl={card.imageUrl} name={card.name} placeholder={state.strings.name} handle={card.handle} node={card.node} actions={enable} />
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -180,7 +170,7 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
<Text style={styles.title}>{ state.strings.details }</Text>
|
<Text style={styles.title}>{ state.strings.details }</Text>
|
||||||
{close && (
|
{close && (
|
||||||
<View style={styles.close} />
|
<View style={styles.close} />
|
||||||
)}
|
)}
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
<Divider style={styles.divider} />
|
<Divider style={styles.divider} />
|
||||||
{ !state.access && (
|
{ !state.access && (
|
||||||
@ -201,8 +191,8 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.editSubject}
|
value={state.editSubject}
|
||||||
label={Platform.OS==='ios'?state.strings.subject:undefined}
|
label={Platform.OS === 'ios' ? state.strings.subject : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.subject:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.subject : undefined}
|
||||||
disabled={state.locked}
|
disabled={state.locked}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="label-outline" />}
|
left={<TextInput.Icon style={styles.icon} icon="label-outline" />}
|
||||||
onChangeText={value => actions.setEditSubject(value)}
|
onChangeText={value => actions.setEditSubject(value)}
|
||||||
@ -211,8 +201,8 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
<IconButton style={styles.icon} icon="undo-variant" onPress={actions.undoSubject} />
|
<IconButton style={styles.icon} icon="undo-variant" onPress={actions.undoSubject} />
|
||||||
)}
|
)}
|
||||||
{ state.subject !== state.editSubject && (
|
{ state.subject !== state.editSubject && (
|
||||||
<IconButton style={styles.icon} icon="content-save-outline" loading={saving} onPress={saveSubject} />
|
<IconButton style={styles.icon} icon="content-save-outline" loading={saving} onPress={saveSubject} />
|
||||||
)}
|
)}
|
||||||
</Surface>
|
</Surface>
|
||||||
)}
|
)}
|
||||||
{ !state.host && !state.locked && (
|
{ !state.host && !state.locked && (
|
||||||
@ -335,6 +325,7 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
<Text style={styles.unknown}>{ state.strings.unknown }: {state.unknownContacts}</Text>
|
<Text style={styles.unknown}>{ state.strings.unknown }: {state.unknownContacts}</Text>
|
||||||
)}
|
)}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
<Confirm show={alert} params={alertParams} />
|
||||||
<Confirm show={confirm} busy={busy} params={confirmParams} />
|
<Confirm show={confirm} busy={busy} params={confirmParams} />
|
||||||
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={memberModal} onRequestClose={() => setMemberModal(false)}>
|
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={memberModal} onRequestClose={() => setMemberModal(false)}>
|
||||||
<View style={styles.memberModal}>
|
<View style={styles.memberModal}>
|
||||||
@ -368,8 +359,5 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
|
|||||||
</View>
|
</View>
|
||||||
</Modal>
|
</Modal>
|
||||||
</View>
|
</View>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// input if host and unsealed
|
|
||||||
// text otherwise
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { useState, useContext, useEffect } from 'react'
|
import { useState, useContext, useEffect } from 'react';
|
||||||
import { AppContext } from '../context/AppContext'
|
import { AppContext } from '../context/AppContext';
|
||||||
import { DisplayContext } from '../context/DisplayContext'
|
import { DisplayContext } from '../context/DisplayContext';
|
||||||
import { ContextType } from '../context/ContextType'
|
import { ContextType } from '../context/ContextType';
|
||||||
import { FocusDetail, Card, Profile } from 'databag-client-sdk';
|
import { FocusDetail, Card, Profile } from 'databag-client-sdk';
|
||||||
|
|
||||||
export function useDetails() {
|
export function useDetails() {
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
cardId: null as null | string,
|
cardId: null as null | string,
|
||||||
channelId: '',
|
channelId: '',
|
||||||
@ -26,51 +26,51 @@ export function useDetails() {
|
|||||||
hostCard: null as null | Card,
|
hostCard: null as null | Card,
|
||||||
channelCards: [] as Card[],
|
channelCards: [] as Card[],
|
||||||
unknownContacts: 0,
|
unknownContacts: 0,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
const getTimestamp = (created: number) => {
|
const getTimestamp = (created: number) => {
|
||||||
const now = Math.floor((new Date()).getTime() / 1000)
|
const now = Math.floor((new Date()).getTime() / 1000);
|
||||||
const date = new Date(created * 1000);
|
const date = new Date(created * 1000);
|
||||||
const offset = now - created;
|
const offset = now - created;
|
||||||
if(offset < 43200) {
|
if(offset < 43200) {
|
||||||
if (state.timeFormat === '12h') {
|
if (state.timeFormat === '12h') {
|
||||||
return date.toLocaleTimeString("en-US", {hour: 'numeric', minute:'2-digit'});
|
return date.toLocaleTimeString('en-US', {hour: 'numeric', minute:'2-digit'});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleTimeString("en-GB", {hour: 'numeric', minute:'2-digit'});
|
return date.toLocaleTimeString('en-GB', {hour: 'numeric', minute:'2-digit'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (offset < 31449600) {
|
else if (offset < 31449600) {
|
||||||
if (state.dateFormat === 'mm/dd') {
|
if (state.dateFormat === 'mm/dd') {
|
||||||
return date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
|
return date.toLocaleDateString('en-US', {day: 'numeric', month:'numeric'});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleDateString("en-GB", {day: 'numeric', month:'numeric'});
|
return date.toLocaleDateString('en-GB', {day: 'numeric', month:'numeric'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (state.dateFormat === 'mm/dd') {
|
if (state.dateFormat === 'mm/dd') {
|
||||||
return date.toLocaleDateString("en-US");
|
return date.toLocaleDateString('en-US');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleDateString("en-GB");
|
return date.toLocaleDateString('en-GB');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { strings, timeFormat, dateFormat } = display.state;
|
const { strings, timeFormat, dateFormat } = display.state;
|
||||||
updateState({ strings, timeFormat, dateFormat });
|
updateState({ strings, timeFormat, dateFormat });
|
||||||
}, [display.state]);
|
}, [display.state]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const hostCard = state.cards.find(entry => entry.cardId == state.cardId);
|
const hostCard = state.cards.find(entry => entry.cardId === state.cardId);
|
||||||
const profileRemoved = state.detail?.members ? state.detail.members.filter(member => state.profile?.guid != member.guid) : [];
|
const profileRemoved = state.detail?.members ? state.detail.members.filter(member => state.profile?.guid !== member.guid) : [];
|
||||||
const contactCards = profileRemoved.map(member => state.cards.find(card => card.guid === member.guid));
|
const contactCards = profileRemoved.map(member => state.cards.find(card => card.guid === member.guid));
|
||||||
const channelCards = contactCards.filter(member => Boolean(member));
|
const channelCards = contactCards.filter(member => Boolean(member));
|
||||||
const unknownContacts = contactCards.length - channelCards.length;
|
const unknownContacts = contactCards.length - channelCards.length;
|
||||||
@ -93,10 +93,10 @@ export function useDetails() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
updateState({ cards: sorted });
|
updateState({ cards: sorted });
|
||||||
}
|
};
|
||||||
const setProfile = (profile: Profile) => {
|
const setProfile = (profile: Profile) => {
|
||||||
updateState({ profile });
|
updateState({ profile });
|
||||||
}
|
};
|
||||||
const setDetail = (focused: { cardId: string | null, channelId: string, detail: FocusDetail | null }) => {
|
const setDetail = (focused: { cardId: string | null, channelId: string, detail: FocusDetail | null }) => {
|
||||||
const detail = focused ? focused.detail : null;
|
const detail = focused ? focused.detail : null;
|
||||||
const cardId = focused.cardId;
|
const cardId = focused.cardId;
|
||||||
@ -108,7 +108,7 @@ export function useDetails() {
|
|||||||
const subject = detail?.data?.subject ? detail.data.subject : '';
|
const subject = detail?.data?.subject ? detail.data.subject : '';
|
||||||
const created = detail?.created ? getTimestamp(detail.created) : '';
|
const created = detail?.created ? getTimestamp(detail.created) : '';
|
||||||
updateState({ detail, editSubject: subject, subject, channelId, cardId, access, sealed, locked, host, created });
|
updateState({ detail, editSubject: subject, subject, channelId, cardId, access, sealed, locked, host, created });
|
||||||
}
|
};
|
||||||
focus.addDetailListener(setDetail);
|
focus.addDetailListener(setDetail);
|
||||||
contact.addCardListener(setCards);
|
contact.addCardListener(setCards);
|
||||||
identity.addProfileListener(setProfile);
|
identity.addProfileListener(setProfile);
|
||||||
@ -116,18 +116,19 @@ export function useDetails() {
|
|||||||
focus.removeDetailListener(setDetail);
|
focus.removeDetailListener(setDetail);
|
||||||
contact.removeCardListener(setCards);
|
contact.removeCardListener(setCards);
|
||||||
identity.removeProfileListener(setProfile);
|
identity.removeProfileListener(setProfile);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}, [app.state.focus, state.timeFormat, state.dateFormat]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [app.state.session, app.state.focus, state.timeFormat, state.dateFormat]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
remove: async () => {
|
remove: async () => {
|
||||||
const content = app.state.session.getContent()
|
const content = app.state.session.getContent();
|
||||||
await content.removeChannel(state.channelId);
|
await content.removeChannel(state.channelId);
|
||||||
app.actions.clearFocus();
|
app.actions.clearFocus();
|
||||||
},
|
},
|
||||||
leave: async () => {
|
leave: async () => {
|
||||||
const content = app.state.session.getContent()
|
const content = app.state.session.getContent();
|
||||||
await content.leaveChannel(state.cardId, state.channelId);
|
await content.leaveChannel(state.cardId, state.channelId);
|
||||||
app.actions.clearFocus();
|
app.actions.clearFocus();
|
||||||
},
|
},
|
||||||
@ -155,10 +156,10 @@ export function useDetails() {
|
|||||||
updateState({ editSubject: state.subject });
|
updateState({ editSubject: state.subject });
|
||||||
},
|
},
|
||||||
saveSubject: async () => {
|
saveSubject: async () => {
|
||||||
const content = app.state.session.getContent()
|
const content = app.state.session.getContent();
|
||||||
await content.setChannelSubject(state.channelId, state.sealed ? 'sealed' : 'superbasic', { subject: state.editSubject });
|
await content.setChannelSubject(state.channelId, state.sealed ? 'sealed' : 'superbasic', { subject: state.editSubject });
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Platform, Share } from 'react-native';
|
import { Platform, Share } from 'react-native';
|
||||||
import fileType from 'react-native-file-type'
|
import fileType from 'react-native-file-type';
|
||||||
import RNFS from 'react-native-fs';
|
import RNFS from 'react-native-fs';
|
||||||
import RNFetchBlob from 'rn-fetch-blob';
|
import RNFetchBlob from 'rn-fetch-blob';
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ export async function Download(uri: string, name: string, extension?: string) {
|
|||||||
|
|
||||||
if (Platform.OS === 'ios') {
|
if (Platform.OS === 'ios') {
|
||||||
const options = { fileCache: true, filename: name };
|
const options = { fileCache: true, filename: name };
|
||||||
const download = await RNFetchBlob.config(options).fetch("GET", uri);
|
const download = await RNFetchBlob.config(options).fetch('GET', uri);
|
||||||
const downloadPath = download.path();
|
const downloadPath = download.path();
|
||||||
|
|
||||||
const type = extension ? extension : (await fileType(downloadPath))?.ext;
|
const type = extension ? extension : (await fileType(downloadPath))?.ext;
|
||||||
@ -31,7 +31,7 @@ export async function Download(uri: string, name: string, extension?: string) {
|
|||||||
await RNFS.scanFile(sharePath);
|
await RNFS.scanFile(sharePath);
|
||||||
} else {
|
} else {
|
||||||
const options = { fileCache: true, filename: name };
|
const options = { fileCache: true, filename: name };
|
||||||
const download = await RNFetchBlob.config(options).fetch("GET", uri);
|
const download = await RNFetchBlob.config(options).fetch('GET', uri);
|
||||||
const downloadPath = download.path();
|
const downloadPath = download.path();
|
||||||
|
|
||||||
const type = extension ? extension : (await fileType(downloadPath))?.ext;
|
const type = extension ? extension : (await fileType(downloadPath))?.ext;
|
||||||
@ -42,5 +42,5 @@ export async function Download(uri: string, name: string, extension?: string) {
|
|||||||
await RNFS.moveFile(downloadPath, sharePath);
|
await RNFS.moveFile(downloadPath, sharePath);
|
||||||
await RNFS.scanFile(sharePath);
|
await RNFS.scanFile(sharePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ export const styles = StyleSheet.create({
|
|||||||
paddingTop: 8,
|
paddingTop: 8,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
|
fontSize: 14,
|
||||||
|
padding: 0,
|
||||||
},
|
},
|
||||||
topic: {
|
topic: {
|
||||||
paddingTop: 8,
|
paddingTop: 8,
|
||||||
@ -132,11 +134,6 @@ export const styles = StyleSheet.create({
|
|||||||
height: 64,
|
height: 64,
|
||||||
backgroundColor: 'yellow',
|
backgroundColor: 'yellow',
|
||||||
},
|
},
|
||||||
message: {
|
|
||||||
width: '100%',
|
|
||||||
fontSize: 14,
|
|
||||||
padding: 0,
|
|
||||||
},
|
|
||||||
modal: {
|
modal: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
@ -183,4 +180,4 @@ export const styles = StyleSheet.create({
|
|||||||
paddingTop: 16,
|
paddingTop: 16,
|
||||||
gap: 8,
|
gap: 8,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useRef, useEffect, useState, useCallback } from 'react';
|
import React, { useRef, useEffect, useState } from 'react';
|
||||||
import { avatar } from '../constants/Icons'
|
import { avatar } from '../constants/Icons';
|
||||||
import { Pressable, Linking, ScrollView, View, Image, Modal } from 'react-native';
|
import { Pressable, Linking, ScrollView, View, Image, Modal } from 'react-native';
|
||||||
import {Icon, Text, TextInput, IconButton, Button, Surface, Divider} from 'react-native-paper';
|
import { Text, TextInput, IconButton, Button, Surface, Divider} from 'react-native-paper';
|
||||||
import { Topic, Card, Profile } from 'databag-client-sdk';
|
import { Topic, Card, Profile } from 'databag-client-sdk';
|
||||||
import { ImageAsset } from './imageAsset/ImageAsset';
|
import { ImageAsset } from './imageAsset/ImageAsset';
|
||||||
import { AudioAsset } from './audioAsset/AudioAsset';
|
import { AudioAsset } from './audioAsset/AudioAsset';
|
||||||
@ -10,7 +10,7 @@ import { BinaryAsset } from './binaryAsset/BinaryAsset';
|
|||||||
import { useMessage } from './useMessage.hook';
|
import { useMessage } from './useMessage.hook';
|
||||||
import {styles} from './Message.styled';
|
import {styles} from './Message.styled';
|
||||||
import { MediaAsset } from '../conversation/Conversatin';
|
import { MediaAsset } from '../conversation/Conversatin';
|
||||||
import { Confirm } from '../confirm/Confirm';
|
import { Confirm } from '../confirm/Confirm';
|
||||||
import { Shimmer } from './shimmer/Shimmer';
|
import { Shimmer } from './shimmer/Shimmer';
|
||||||
import {BlurView} from '@react-native-community/blur';
|
import {BlurView} from '@react-native-community/blur';
|
||||||
import { sanitizeUrl } from '@braintree/sanitize-url';
|
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||||
@ -18,9 +18,9 @@ import { sanitizeUrl } from '@braintree/sanitize-url';
|
|||||||
export function Message({ topic, card, profile, host, select, selected }: { topic: Topic, card: Card | null, profile: Profile | null, host: boolean, select: (id: null | string)=>void, selected: string }) {
|
export function Message({ topic, card, profile, host, select, selected }: { topic: Topic, card: Card | null, profile: Profile | null, host: boolean, select: (id: null | string)=>void, selected: string }) {
|
||||||
const { state, actions } = useMessage();
|
const { state, actions } = useMessage();
|
||||||
const { locked, data, created, topicId, status, transform } = topic;
|
const { locked, data, created, topicId, status, transform } = topic;
|
||||||
const { name, handle, node } = profile || card || { name: null, handle: null, node: null }
|
const { name, handle, node } = profile || card || { name: null, handle: null, node: null };
|
||||||
const { text, textColor, textSize, assets } = data || { text: null, textColor: null, textSize: null }
|
const { text, textColor, textSize, assets } = data || { text: null, textColor: null, textSize: null };
|
||||||
const textStyle = textColor && textSize ? { fontSize: textSize, color: textColor } : textColor ? { color: textColor } : textSize ? { fontSize: textSize } : {}
|
const textStyle = textColor && textSize ? { fontSize: textSize, color: textColor } : textColor ? { color: textColor } : textSize ? { fontSize: textSize } : {};
|
||||||
const logoUrl = profile ? profile.imageUrl : card ? card.imageUrl : avatar;
|
const logoUrl = profile ? profile.imageUrl : card ? card.imageUrl : avatar;
|
||||||
const timestamp = actions.getTimestamp(created);
|
const timestamp = actions.getTimestamp(created);
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
@ -34,6 +34,7 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
const loadedCount = useRef(0);
|
const loadedCount = useRef(0);
|
||||||
const [showAsset, setShowAsset] = useState(false);
|
const [showAsset, setShowAsset] = useState(false);
|
||||||
const [message, setMessage] = useState([]);
|
const [message, setMessage] = useState([]);
|
||||||
|
const fontStyle = { fontStyle: 'italic' };
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(() => setShowAsset(true), 2000);
|
setTimeout(() => setShowAsset(true), 2000);
|
||||||
@ -54,22 +55,23 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
if (parsed?.length > 0) {
|
if (parsed?.length > 0) {
|
||||||
const words = parsed as string[];
|
const words = parsed as string[];
|
||||||
words.forEach((word, index) => {
|
words.forEach((word, index) => {
|
||||||
if (!!urlPattern.test(word)) {
|
if (urlPattern.test(word)) {
|
||||||
clickable.push(<Text key={index} style={textStyle}>{ plain }</Text>);
|
clickable.push(<Text key={index} style={textStyle}>{ plain }</Text>);
|
||||||
plain = '';
|
plain = '';
|
||||||
const url = !!hostPattern.test(word) ? word : `https://${word}`;
|
const url = hostPattern.test(word) ? word : `https://${word}`;
|
||||||
clickable.push(<Text key={'link-' + index} onPress={() => Linking.openURL(sanitizeUrl(url))} style={{ fontStyle: 'italic' }}>{ sanitizeUrl(word) + ' ' }</Text>);
|
clickable.push(<Text key={'link-' + index} onPress={() => Linking.openURL(sanitizeUrl(url))} style={fontStyle}>{ sanitizeUrl(word) + ' ' }</Text>);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
plain += `${word} `;
|
plain += `${word} `;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plain) {
|
if (plain) {
|
||||||
clickable.push(<Text key={parsed.length} style={textStyle}>{ plain }</Text>);
|
clickable.push(<Text key={parsed.length} style={textStyle}>{ plain }</Text>);
|
||||||
}
|
}
|
||||||
setMessage(clickable)
|
setMessage(clickable);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [text, locked]);
|
}, [text, locked]);
|
||||||
|
|
||||||
const loaded = () => {
|
const loaded = () => {
|
||||||
@ -77,12 +79,12 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
if (loadedCount.current >= assets.length) {
|
if (loadedCount.current >= assets.length) {
|
||||||
setShowAsset(true);
|
setShowAsset(true);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const edit = () => {
|
const edit = () => {
|
||||||
setEditing(true);
|
setEditing(true);
|
||||||
select(null);
|
select(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
@ -94,7 +96,7 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
}
|
}
|
||||||
setSaving(false);
|
setSaving(false);
|
||||||
setEditing(false);
|
setEditing(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const block = () => {
|
const block = () => {
|
||||||
setConfirmParams({
|
setConfirmParams({
|
||||||
@ -118,7 +120,7 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
}
|
}
|
||||||
setBlocking(false);
|
setBlocking(false);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setConfirmShow(true);
|
setConfirmShow(true);
|
||||||
@ -146,7 +148,7 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
}
|
}
|
||||||
setReporting(false);
|
setReporting(false);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setConfirmShow(true);
|
setConfirmShow(true);
|
||||||
@ -174,7 +176,7 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
}
|
}
|
||||||
setRemoving(false);
|
setRemoving(false);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setConfirmShow(true);
|
setConfirmShow(true);
|
||||||
@ -190,19 +192,19 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
setConfirmShow(true);
|
setConfirmShow(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
const media = !assets ? [] : assets.map((asset: MediaAsset, index: number) => {
|
const media = !assets ? [] : assets.map((asset: MediaAsset, index: number) => {
|
||||||
if (asset.image || asset.encrypted?.type === 'image') {
|
if (asset.image || asset.encrypted?.type === 'image') {
|
||||||
return <ImageAsset key={index} topicId={topicId} asset={asset as MediaAsset} loaded={loaded} show={showAsset} />
|
return <ImageAsset key={index} topicId={topicId} asset={asset as MediaAsset} loaded={loaded} show={showAsset} />;
|
||||||
} else if (asset.audio || asset.encrypted?.type === 'audio') {
|
} else if (asset.audio || asset.encrypted?.type === 'audio') {
|
||||||
return <AudioAsset key={index} topicId={topicId} asset={asset as MediaAsset} loaded={loaded} show={showAsset} />
|
return <AudioAsset key={index} topicId={topicId} asset={asset as MediaAsset} loaded={loaded} show={showAsset} />;
|
||||||
} else if (asset.video || asset.encrypted?.type === 'video') {
|
} else if (asset.video || asset.encrypted?.type === 'video') {
|
||||||
return <VideoAsset key={index} topicId={topicId} asset={asset as MediaAsset} loaded={loaded} show={showAsset} />
|
return <VideoAsset key={index} topicId={topicId} asset={asset as MediaAsset} loaded={loaded} show={showAsset} />;
|
||||||
} else if (asset.binary || asset.encrypted?.type === 'binary') {
|
} else if (asset.binary || asset.encrypted?.type === 'binary') {
|
||||||
return <BinaryAsset key={index} topicId={topicId} asset={asset as MediaAsset} loaded={loaded} show={showAsset} />
|
return <BinaryAsset key={index} topicId={topicId} asset={asset as MediaAsset} loaded={loaded} show={showAsset} />;
|
||||||
} else {
|
} else {
|
||||||
return <View key={index}></View>
|
return <View key={index} />;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -212,7 +214,7 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
<Image style={styles.logo} resizeMode={'contain'} source={{uri: logoUrl}} />
|
<Image style={styles.logo} resizeMode={'contain'} source={{uri: logoUrl}} />
|
||||||
<View style={styles.body}>
|
<View style={styles.body}>
|
||||||
<Pressable style={styles.header} onPress={()=>select(topicId == selected ? null : topicId)}>
|
<Pressable style={styles.header} onPress={()=>select(topicId === selected ? null : topicId)}>
|
||||||
<View style={styles.name}>
|
<View style={styles.name}>
|
||||||
{ name && (
|
{ name && (
|
||||||
<Text style={styles.handle}>{ name }</Text>
|
<Text style={styles.handle}>{ name }</Text>
|
||||||
@ -243,7 +245,7 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{ !locked && assets?.length > 0 && transform === 'complete' && (
|
{ !locked && assets?.length > 0 && transform === 'complete' && (
|
||||||
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false} style={styles.carousel} contentContainerStyle={styles.assets}>
|
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false} style={styles.carousel} contentContainerStyle={styles.assets}>
|
||||||
{ media }
|
{ media }
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@ -280,11 +282,11 @@ export function Message({ topic, card, profile, host, select, selected }: { topi
|
|||||||
<BlurView style={styles.blur} blurType="dark" blurAmount={6} reducedTransparencyFallbackColor="dark" />
|
<BlurView style={styles.blur} blurType="dark" blurAmount={6} reducedTransparencyFallbackColor="dark" />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<View style={styles.editArea}>
|
<View style={styles.editArea}>
|
||||||
<Surface elevation={2} style={styles.editContent}>
|
<Surface elevation={2} style={styles.editContent}>
|
||||||
<Text style={styles.title}>{ state.strings.edit }</Text>
|
<Text style={styles.title}>{ state.strings.edit }</Text>
|
||||||
<TextInput multiline={true} mode="outlined" style={styles.message}
|
<TextInput multiline={true} mode="outlined" style={styles.message}
|
||||||
outlineColor="transparent" activeOutlineColor="transparent" spellcheck={false}
|
outlineColor="transparent" activeOutlineColor="transparent" spellcheck={false}
|
||||||
autoComplete="off" autoCapitalize="none" autoCorrect={false} placeholder={state.strings.newMessage}
|
autoComplete="off" autoCapitalize="none" autoCorrect={false} placeholder={state.strings.newMessage}
|
||||||
value={editText} onChangeText={value => setEditText(value)} />
|
value={editText} onChangeText={value => setEditText(value)} />
|
||||||
<View style={styles.controls}>
|
<View style={styles.controls}>
|
||||||
<Button mode="outlined" onPress={()=>setEditing(false)}>
|
<Button mode="outlined" onPress={()=>setEditing(false)}>
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { SafeAreaView, Modal, Share, Pressable, View, Image, Animated, useAnimatedValue } from 'react-native'
|
import { SafeAreaView, Modal, Pressable, View, Image, Animated, useAnimatedValue } from 'react-native';
|
||||||
import { Surface, Icon, Text, ProgressBar, IconButton } from 'react-native-paper'
|
import { Surface, Icon, Text, ProgressBar, IconButton } from 'react-native-paper';
|
||||||
import { useAudioAsset } from './useAudioAsset.hook';
|
import { useAudioAsset } from './useAudioAsset.hook';
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { styles } from './AudioAsset.styled'
|
import { styles } from './AudioAsset.styled';
|
||||||
import {BlurView} from '@react-native-community/blur';
|
import {BlurView} from '@react-native-community/blur';
|
||||||
import Video, { VideoRef } from 'react-native-video'
|
import Video, { VideoRef } from 'react-native-video';
|
||||||
import thumb from '../../images/audio.png';
|
import thumb from '../../images/audio.png';
|
||||||
import {Colors} from '../../constants/Colors';
|
import { activateKeepAwake, deactivateKeepAwake} from '@sayem314/react-native-keep-awake';
|
||||||
import { activateKeepAwake, deactivateKeepAwake} from "@sayem314/react-native-keep-awake";
|
|
||||||
|
|
||||||
export function AudioAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
export function AudioAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
||||||
const { state, actions } = useAudioAsset(topicId, asset);
|
const { state, actions } = useAudioAsset(topicId, asset);
|
||||||
@ -19,38 +18,39 @@ export function AudioAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
const [downloading, setDownloading] = useState(false);
|
const [downloading, setDownloading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (show) {
|
if (show) {
|
||||||
Animated.timing(opacity, {
|
Animated.timing(opacity, {
|
||||||
toValue: 1,
|
toValue: 1,
|
||||||
duration: 100,
|
duration: 100,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [show]);
|
}, [show]);
|
||||||
|
|
||||||
const showAudio = () => {
|
const showAudio = () => {
|
||||||
setModal(true);
|
setModal(true);
|
||||||
actions.loadAudio();
|
actions.loadAudio();
|
||||||
activateKeepAwake()
|
activateKeepAwake();
|
||||||
};
|
};
|
||||||
|
|
||||||
const hideAudio = () => {
|
const hideAudio = () => {
|
||||||
setModal(false);
|
setModal(false);
|
||||||
actions.cancelLoad();
|
actions.cancelLoad();
|
||||||
deactivateKeepAwake();
|
deactivateKeepAwake();
|
||||||
}
|
};
|
||||||
|
|
||||||
const play = () => {
|
const play = () => {
|
||||||
videoRef.current.resume();
|
videoRef.current.resume();
|
||||||
}
|
};
|
||||||
|
|
||||||
const pause = () => {
|
const pause = () => {
|
||||||
videoRef.current.pause();
|
videoRef.current.pause();
|
||||||
}
|
};
|
||||||
|
|
||||||
const end = () => {
|
const end = () => {
|
||||||
videoRef.current.seek(0);
|
videoRef.current.seek(0);
|
||||||
}
|
};
|
||||||
|
|
||||||
const playbackRateChange = (e) => {
|
const playbackRateChange = (e) => {
|
||||||
if (e.playbackRate === 0) {
|
if (e.playbackRate === 0) {
|
||||||
@ -58,7 +58,7 @@ export function AudioAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
} else {
|
} else {
|
||||||
setStatus('playing');
|
setStatus('playing');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const download = async () => {
|
const download = async () => {
|
||||||
if (!downloading) {
|
if (!downloading) {
|
||||||
@ -70,12 +70,12 @@ export function AudioAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
}
|
}
|
||||||
setDownloading(false);
|
setDownloading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.audio}>
|
<View style={styles.audio}>
|
||||||
<Pressable onPress={showAudio}>
|
<Pressable onPress={showAudio}>
|
||||||
<Animated.View style={[styles.container,{opacity},]}>
|
<Animated.View style={[styles.container,{opacity}]}>
|
||||||
<Image
|
<Image
|
||||||
style={styles.thumb}
|
style={styles.thumb}
|
||||||
resizeMode="contain"
|
resizeMode="contain"
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useRef } from 'react';
|
||||||
import { AppContext } from '../../context/AppContext'
|
import { AppContext } from '../../context/AppContext';
|
||||||
import { DisplayContext } from '../../context/DisplayContext'
|
import { DisplayContext } from '../../context/DisplayContext';
|
||||||
import { Focus } from 'databag-client-sdk'
|
import { ContextType } from '../../context/ContextType';
|
||||||
import { ContextType } from '../../context/ContextType'
|
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { Download } from '../../download';
|
import { Download } from '../../download';
|
||||||
|
|
||||||
export function useAudioAsset(topicId: string, asset: MediaAsset) {
|
export function useAudioAsset(topicId: string, asset: MediaAsset) {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
dataUrl: null,
|
dataUrl: null,
|
||||||
@ -16,13 +15,13 @@ export function useAudioAsset(topicId: string, asset: MediaAsset) {
|
|||||||
loaded: false,
|
loaded: false,
|
||||||
loadPercent: 0,
|
loadPercent: 0,
|
||||||
failed: false,
|
failed: false,
|
||||||
})
|
});
|
||||||
const cancelled = useRef(false);
|
const cancelled = useRef(false);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
cancelLoad: () => {
|
cancelLoad: () => {
|
||||||
@ -44,10 +43,10 @@ export function useAudioAsset(topicId: string, asset: MediaAsset) {
|
|||||||
const { focus } = app.state;
|
const { focus } = app.state;
|
||||||
const assetId = asset.audio ? asset.audio.full : asset.encrypted ? asset.encrypted.parts : null;
|
const assetId = asset.audio ? asset.audio.full : asset.encrypted ? asset.encrypted.parts : null;
|
||||||
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
||||||
cancelled.current = false;
|
cancelled.current = false;
|
||||||
updateState({ loading: true, loadPercent: 0 });
|
updateState({ loading: true, loadPercent: 0 });
|
||||||
try {
|
try {
|
||||||
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current });
|
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current; });
|
||||||
updateState({ dataUrl });
|
updateState({ dataUrl });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@ -56,7 +55,7 @@ export function useAudioAsset(topicId: string, asset: MediaAsset) {
|
|||||||
updateState({ loading: false });
|
updateState({ loading: false });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { SafeAreaView, Modal, Share, Pressable, View, Image, Animated, useAnimatedValue } from 'react-native'
|
import { SafeAreaView, Modal, Pressable, View, Image, Animated, useAnimatedValue } from 'react-native';
|
||||||
import { Text, Surface, Icon, ProgressBar, IconButton } from 'react-native-paper'
|
import { Text, Surface, Icon, ProgressBar, IconButton } from 'react-native-paper';
|
||||||
import { useBinaryAsset } from './useBinaryAsset.hook';
|
import { useBinaryAsset } from './useBinaryAsset.hook';
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { styles } from './BinaryAsset.styled'
|
import { styles } from './BinaryAsset.styled';
|
||||||
import {BlurView} from '@react-native-community/blur';
|
import {BlurView} from '@react-native-community/blur';
|
||||||
import Video from 'react-native-video'
|
|
||||||
import thumb from '../../images/binary.png';
|
import thumb from '../../images/binary.png';
|
||||||
|
|
||||||
export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
||||||
@ -23,18 +22,9 @@ export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [show]);
|
}, [show]);
|
||||||
|
|
||||||
const share = async () => {
|
|
||||||
try {
|
|
||||||
setAlert('');
|
|
||||||
await actions.download();
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
setAlert(state.strings.operationFailed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const showBinary = () => {
|
const showBinary = () => {
|
||||||
setAlert('');
|
setAlert('');
|
||||||
setModal(true);
|
setModal(true);
|
||||||
@ -44,7 +34,7 @@ export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
const hideBinary = () => {
|
const hideBinary = () => {
|
||||||
setModal(false);
|
setModal(false);
|
||||||
actions.cancelLoad();
|
actions.cancelLoad();
|
||||||
}
|
};
|
||||||
|
|
||||||
const download = async () => {
|
const download = async () => {
|
||||||
if (!downloading) {
|
if (!downloading) {
|
||||||
@ -56,12 +46,12 @@ export function BinaryAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
}
|
}
|
||||||
setDownloading(false);
|
setDownloading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.binary}>
|
<View style={styles.binary}>
|
||||||
<Pressable onPress={showBinary}>
|
<Pressable onPress={showBinary}>
|
||||||
<Animated.View style={[styles.container,{opacity},]}>
|
<Animated.View style={[styles.container,{opacity}]}>
|
||||||
<Image
|
<Image
|
||||||
style={styles.thumb}
|
style={styles.thumb}
|
||||||
resizeMode="contain"
|
resizeMode="contain"
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useRef } from 'react';
|
||||||
import { AppContext } from '../../context/AppContext'
|
import { AppContext } from '../../context/AppContext';
|
||||||
import { DisplayContext } from '../../context/DisplayContext';
|
import { DisplayContext } from '../../context/DisplayContext';
|
||||||
import { Focus } from 'databag-client-sdk'
|
import { ContextType } from '../../context/ContextType';
|
||||||
import { ContextType } from '../../context/ContextType'
|
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { Download } from '../../download';
|
import { Download } from '../../download';
|
||||||
|
|
||||||
export function useBinaryAsset(topicId: string, asset: MediaAsset) {
|
export function useBinaryAsset(topicId: string, asset: MediaAsset) {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
dataUrl: null,
|
dataUrl: null,
|
||||||
@ -16,13 +15,13 @@ export function useBinaryAsset(topicId: string, asset: MediaAsset) {
|
|||||||
loaded: false,
|
loaded: false,
|
||||||
loadPercent: 0,
|
loadPercent: 0,
|
||||||
failed: false,
|
failed: false,
|
||||||
})
|
});
|
||||||
const cancelled = useRef(false);
|
const cancelled = useRef(false);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
cancelLoad: () => {
|
cancelLoad: () => {
|
||||||
@ -43,10 +42,10 @@ export function useBinaryAsset(topicId: string, asset: MediaAsset) {
|
|||||||
const { focus } = app.state;
|
const { focus } = app.state;
|
||||||
const assetId = asset.binary ? asset.binary.data : asset.encrypted ? asset.encrypted.parts : null;
|
const assetId = asset.binary ? asset.binary.data : asset.encrypted ? asset.encrypted.parts : null;
|
||||||
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
||||||
cancelled.current = false;
|
cancelled.current = false;
|
||||||
updateState({ loading: true, loadPercent: 0 });
|
updateState({ loading: true, loadPercent: 0 });
|
||||||
try {
|
try {
|
||||||
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current });
|
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current; });
|
||||||
updateState({ dataUrl });
|
updateState({ dataUrl });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@ -54,8 +53,8 @@ export function useBinaryAsset(topicId: string, asset: MediaAsset) {
|
|||||||
}
|
}
|
||||||
updateState({ loading: false });
|
updateState({ loading: false });
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -48,10 +48,6 @@ export const styles = StyleSheet.create({
|
|||||||
bottom: '10%',
|
bottom: '10%',
|
||||||
width: '50%',
|
width: '50%',
|
||||||
},
|
},
|
||||||
alert: {
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: '10%'
|
|
||||||
},
|
|
||||||
alert: {
|
alert: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { SafeAreaView, Modal, Pressable, Animated, View, Image, useAnimatedValue } from 'react-native'
|
import { SafeAreaView, Modal, Pressable, Animated, View, Image, useAnimatedValue } from 'react-native';
|
||||||
import { Text, ProgressBar, IconButton } from 'react-native-paper'
|
import { Text, ProgressBar, IconButton } from 'react-native-paper';
|
||||||
import { useImageAsset } from './useImageAsset.hook';
|
import { useImageAsset } from './useImageAsset.hook';
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { styles } from './ImageAsset.styled'
|
import { styles } from './ImageAsset.styled';
|
||||||
import {BlurView} from '@react-native-community/blur';
|
import {BlurView} from '@react-native-community/blur';
|
||||||
import { ReactNativeZoomableView } from '@openspacelabs/react-native-zoomable-view';
|
import { ReactNativeZoomableView } from '@openspacelabs/react-native-zoomable-view';
|
||||||
import FastImage from 'react-native-fast-image'
|
import FastImage from 'react-native-fast-image';
|
||||||
|
|
||||||
export function ImageAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
export function ImageAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
||||||
const { state, actions } = useImageAsset(topicId, asset);
|
const { state, actions } = useImageAsset(topicId, asset);
|
||||||
@ -26,6 +26,7 @@ export function ImageAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
if (state.loaded) {
|
if (state.loaded) {
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state.loaded, show]);
|
}, [state.loaded, show]);
|
||||||
|
|
||||||
const showImage = () => {
|
const showImage = () => {
|
||||||
@ -37,7 +38,7 @@ export function ImageAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
const hideImage = () => {
|
const hideImage = () => {
|
||||||
setModal(false);
|
setModal(false);
|
||||||
actions.cancelLoad();
|
actions.cancelLoad();
|
||||||
}
|
};
|
||||||
|
|
||||||
const download = async () => {
|
const download = async () => {
|
||||||
if (!downloading) {
|
if (!downloading) {
|
||||||
@ -49,14 +50,14 @@ export function ImageAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
}
|
}
|
||||||
setDownloading(false);
|
setDownloading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.image}>
|
<View style={styles.image}>
|
||||||
{ state.thumbUrl && (
|
{ state.thumbUrl && (
|
||||||
<Pressable onPress={showImage}>
|
<Pressable onPress={showImage}>
|
||||||
<Animated.Image
|
<Animated.Image
|
||||||
style={[styles.thumb,{opacity},]}
|
style={[styles.thumb,{opacity}]}
|
||||||
resizeMode="contain"
|
resizeMode="contain"
|
||||||
height={92}
|
height={92}
|
||||||
width={92 * state.ratio}
|
width={92 * state.ratio}
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useEffect, useRef } from 'react';
|
||||||
import { Share } from 'react-native'
|
import { AppContext } from '../../context/AppContext';
|
||||||
import { AppContext } from '../../context/AppContext'
|
import { DisplayContext } from '../../context/DisplayContext';
|
||||||
import { DisplayContext } from '../../context/DisplayContext'
|
import { ContextType } from '../../context/ContextType';
|
||||||
import { Focus } from 'databag-client-sdk'
|
|
||||||
import { ContextType } from '../../context/ContextType'
|
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { Download } from '../../download';
|
import { Download } from '../../download';
|
||||||
|
|
||||||
export function useImageAsset(topicId: string, asset: MediaAsset) {
|
export function useImageAsset(topicId: string, asset: MediaAsset) {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
thumbUrl: null,
|
thumbUrl: null,
|
||||||
@ -21,13 +19,13 @@ export function useImageAsset(topicId: string, asset: MediaAsset) {
|
|||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
failed: false,
|
failed: false,
|
||||||
})
|
});
|
||||||
const cancelled = useRef(false);
|
const cancelled = useRef(false);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
const setThumb = async () => {
|
const setThumb = async () => {
|
||||||
const { focus } = app.state;
|
const { focus } = app.state;
|
||||||
@ -44,7 +42,8 @@ export function useImageAsset(topicId: string, asset: MediaAsset) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setThumb();
|
setThumb();
|
||||||
}, [asset]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [asset]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
loaded: (e) => {
|
loaded: (e) => {
|
||||||
@ -74,10 +73,10 @@ export function useImageAsset(topicId: string, asset: MediaAsset) {
|
|||||||
const { focus } = app.state;
|
const { focus } = app.state;
|
||||||
const assetId = asset.image ? asset.image.full : asset.encrypted ? asset.encrypted.parts : null;
|
const assetId = asset.image ? asset.image.full : asset.encrypted ? asset.encrypted.parts : null;
|
||||||
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
||||||
cancelled.current = false;
|
cancelled.current = false;
|
||||||
updateState({ loading: true, loadPercent: 0 });
|
updateState({ loading: true, loadPercent: 0 });
|
||||||
try {
|
try {
|
||||||
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current });
|
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current; });
|
||||||
updateState({ dataUrl });
|
updateState({ dataUrl });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@ -85,8 +84,8 @@ export function useImageAsset(topicId: string, asset: MediaAsset) {
|
|||||||
}
|
}
|
||||||
updateState({ loading: false });
|
updateState({ loading: false });
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { View, Animated, useAnimatedValue } from 'react-native';
|
import { View, Animated, useAnimatedValue } from 'react-native';
|
||||||
|
|
||||||
export function Shimmer({ contentStyle }: { contentStyle: any }) {
|
export function Shimmer({ contentStyle }: { contentStyle: any }) {
|
||||||
@ -19,11 +19,12 @@ export function Shimmer({ contentStyle }: { contentStyle: any }) {
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
).start();
|
).start();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View style={[{},{opacity: shimmer},]}>
|
<Animated.View style={[{},{opacity: shimmer}]}>
|
||||||
<View style={contentStyle}></View>
|
<View style={contentStyle} />
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import { useState, useContext, useEffect } from 'react'
|
import { useState, useContext, useEffect } from 'react';
|
||||||
import { DisplayContext } from '../context/DisplayContext'
|
import { DisplayContext } from '../context/DisplayContext';
|
||||||
import { AppContext } from '../context/AppContext';
|
import { AppContext } from '../context/AppContext';
|
||||||
import { ContextType } from '../context/ContextType'
|
import { ContextType } from '../context/ContextType';
|
||||||
|
|
||||||
export function useMessage() {
|
export function useMessage() {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
timeFormat: display.state.timeFormat,
|
timeFormat: display.state.timeFormat,
|
||||||
dateFormat: display.state.dateFormat,
|
dateFormat: display.state.dateFormat,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { strings, timeFormat, dateFormat } = display.state;
|
const { strings, timeFormat, dateFormat } = display.state;
|
||||||
@ -48,35 +48,35 @@ export function useMessage() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getTimestamp: (created: number) => {
|
getTimestamp: (created: number) => {
|
||||||
const now = Math.floor((new Date()).getTime() / 1000)
|
const now = Math.floor((new Date()).getTime() / 1000);
|
||||||
const date = new Date(created * 1000);
|
const date = new Date(created * 1000);
|
||||||
const offset = now - created;
|
const offset = now - created;
|
||||||
if(offset < 43200) {
|
if(offset < 43200) {
|
||||||
if (state.timeFormat === '12h') {
|
if (state.timeFormat === '12h') {
|
||||||
return date.toLocaleTimeString("en-US", {hour: 'numeric', minute:'2-digit'});
|
return date.toLocaleTimeString('en-US', {hour: 'numeric', minute:'2-digit'});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleTimeString("en-GB", {hour: 'numeric', minute:'2-digit'});
|
return date.toLocaleTimeString('en-GB', {hour: 'numeric', minute:'2-digit'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (offset < 31449600) {
|
else if (offset < 31449600) {
|
||||||
if (state.dateFormat === 'mm/dd') {
|
if (state.dateFormat === 'mm/dd') {
|
||||||
return date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
|
return date.toLocaleDateString('en-US', {day: 'numeric', month:'numeric'});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleDateString("en-GB", {day: 'numeric', month:'numeric'});
|
return date.toLocaleDateString('en-GB', {day: 'numeric', month:'numeric'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (state.dateFormat === 'mm/dd') {
|
if (state.dateFormat === 'mm/dd') {
|
||||||
return date.toLocaleDateString("en-US");
|
return date.toLocaleDateString('en-US');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleDateString("en-GB");
|
return date.toLocaleDateString('en-GB');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -75,11 +75,4 @@ export const styles = StyleSheet.create({
|
|||||||
spacer: {
|
spacer: {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
},
|
},
|
||||||
alert: {
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 0,
|
|
||||||
},
|
|
||||||
alertLabel: {
|
|
||||||
color: Colors.offsync,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { SafeAreaView, Share, Modal, Pressable, Animated, View, Image, useAnimatedValue } from 'react-native'
|
import { SafeAreaView, Modal, Pressable, Animated, View, Image, useAnimatedValue } from 'react-native';
|
||||||
import { Text, Surface, Icon, ProgressBar, IconButton } from 'react-native-paper'
|
import { Text, Surface, Icon, ProgressBar, IconButton } from 'react-native-paper';
|
||||||
import { useVideoAsset } from './useVideoAsset.hook';
|
import { useVideoAsset } from './useVideoAsset.hook';
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { styles } from './VideoAsset.styled'
|
import { styles } from './VideoAsset.styled';
|
||||||
import {BlurView} from '@react-native-community/blur';
|
import {BlurView} from '@react-native-community/blur';
|
||||||
import Video, { VideoRef } from 'react-native-video'
|
import Video, { VideoRef } from 'react-native-video';
|
||||||
import { Colors } from '../../constants/Colors';
|
import { activateKeepAwake, deactivateKeepAwake} from '@sayem314/react-native-keep-awake';
|
||||||
import { activateKeepAwake, deactivateKeepAwake} from "@sayem314/react-native-keep-awake";
|
|
||||||
|
|
||||||
export function VideoAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
export function VideoAsset({ topicId, asset, loaded, show }: { topicId: string, asset: MediaAsset, loaded: ()=>void, show: boolean }) {
|
||||||
const { state, actions } = useVideoAsset(topicId, asset);
|
const { state, actions } = useVideoAsset(topicId, asset);
|
||||||
@ -18,7 +17,7 @@ export function VideoAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
const [showControl, setShowControl] = useState(false);
|
const [showControl, setShowControl] = useState(false);
|
||||||
const clear = useRef();
|
const clear = useRef();
|
||||||
const [downloading, setDownloading] = useState(false);
|
const [downloading, setDownloading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.loaded && show) {
|
if (state.loaded && show) {
|
||||||
Animated.timing(opacity, {
|
Animated.timing(opacity, {
|
||||||
@ -30,6 +29,7 @@ export function VideoAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
if (state.loaded) {
|
if (state.loaded) {
|
||||||
loaded();
|
loaded();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state.loaded, show]);
|
}, [state.loaded, show]);
|
||||||
|
|
||||||
const showVideo = () => {
|
const showVideo = () => {
|
||||||
@ -42,7 +42,7 @@ export function VideoAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
setModal(false);
|
setModal(false);
|
||||||
actions.cancelLoad();
|
actions.cancelLoad();
|
||||||
deactivateKeepAwake();
|
deactivateKeepAwake();
|
||||||
}
|
};
|
||||||
|
|
||||||
const controls = () => {
|
const controls = () => {
|
||||||
clearTimeout(clear.current);
|
clearTimeout(clear.current);
|
||||||
@ -50,19 +50,19 @@ export function VideoAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
clear.current = setTimeout(() => {
|
clear.current = setTimeout(() => {
|
||||||
setShowControl(false);
|
setShowControl(false);
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
};
|
||||||
|
|
||||||
const play = () => {
|
const play = () => {
|
||||||
videoRef.current.resume();
|
videoRef.current.resume();
|
||||||
}
|
};
|
||||||
|
|
||||||
const pause = () => {
|
const pause = () => {
|
||||||
videoRef.current.pause();
|
videoRef.current.pause();
|
||||||
}
|
};
|
||||||
|
|
||||||
const end = () => {
|
const end = () => {
|
||||||
videoRef.current.seek(0);
|
videoRef.current.seek(0);
|
||||||
}
|
};
|
||||||
|
|
||||||
const playbackRateChange = (e) => {
|
const playbackRateChange = (e) => {
|
||||||
if (e.playbackRate === 0) {
|
if (e.playbackRate === 0) {
|
||||||
@ -70,7 +70,7 @@ export function VideoAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
} else {
|
} else {
|
||||||
setStatus('playing');
|
setStatus('playing');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const download = async () => {
|
const download = async () => {
|
||||||
if (!downloading) {
|
if (!downloading) {
|
||||||
@ -82,13 +82,13 @@ export function VideoAsset({ topicId, asset, loaded, show }: { topicId: string,
|
|||||||
}
|
}
|
||||||
setDownloading(false);
|
setDownloading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.video}>
|
<View style={styles.video}>
|
||||||
{ state.thumbUrl && (
|
{ state.thumbUrl && (
|
||||||
<Pressable style={styles.container} onPress={showVideo}>
|
<Pressable style={styles.container} onPress={showVideo}>
|
||||||
<Animated.View style={[styles.thumb,{opacity},]}>
|
<Animated.View style={[styles.thumb,{opacity}]}>
|
||||||
<Image
|
<Image
|
||||||
resizeMode="contain"
|
resizeMode="contain"
|
||||||
height={92}
|
height={92}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useEffect, useRef } from 'react';
|
||||||
import { AppContext } from '../../context/AppContext'
|
import { AppContext } from '../../context/AppContext';
|
||||||
import { DisplayContext } from '../../context/DisplayContext';
|
import { DisplayContext } from '../../context/DisplayContext';
|
||||||
import { Focus } from 'databag-client-sdk'
|
import { ContextType } from '../../context/ContextType';
|
||||||
import { ContextType } from '../../context/ContextType'
|
|
||||||
import { MediaAsset } from '../../conversation/Conversation';
|
import { MediaAsset } from '../../conversation/Conversation';
|
||||||
import { Download } from '../../download';
|
import { Download } from '../../download';
|
||||||
|
|
||||||
export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
thumbUrl: null,
|
thumbUrl: null,
|
||||||
@ -18,13 +17,13 @@ export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
|||||||
loaded: false,
|
loaded: false,
|
||||||
loadPercent: 0,
|
loadPercent: 0,
|
||||||
failed: false,
|
failed: false,
|
||||||
})
|
});
|
||||||
const cancelled = useRef(false);
|
const cancelled = useRef(false);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
const setThumb = async () => {
|
const setThumb = async () => {
|
||||||
const { focus } = app.state;
|
const { focus } = app.state;
|
||||||
@ -41,7 +40,8 @@ export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setThumb();
|
setThumb();
|
||||||
}, [asset]);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [asset]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
loaded: (e) => {
|
loaded: (e) => {
|
||||||
@ -67,10 +67,10 @@ export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
|||||||
const { focus } = app.state;
|
const { focus } = app.state;
|
||||||
const assetId = asset.video ? asset.video.hd || asset.video.lq : asset.encrypted ? asset.encrypted.parts : null;
|
const assetId = asset.video ? asset.video.hd || asset.video.lq : asset.encrypted ? asset.encrypted.parts : null;
|
||||||
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
if (focus && assetId != null && !state.loading && !state.dataUrl) {
|
||||||
cancelled.current = false;
|
cancelled.current = false;
|
||||||
updateState({ loading: true, loadPercent: 0 });
|
updateState({ loading: true, loadPercent: 0 });
|
||||||
try {
|
try {
|
||||||
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current });
|
const dataUrl = await focus.getTopicAssetUrl(topicId, assetId, (loadPercent: number)=>{ updateState({ loadPercent }); return !cancelled.current; });
|
||||||
updateState({ dataUrl });
|
updateState({ dataUrl });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@ -78,8 +78,8 @@ export function useVideoAsset(topicId: string, asset: MediaAsset) {
|
|||||||
}
|
}
|
||||||
updateState({ loading: false });
|
updateState({ loading: false });
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {Icon, Text, IconButton, Divider} from 'react-native-paper';
|
import {Icon, Text, IconButton, Divider} from 'react-native-paper';
|
||||||
import {ScrollView, Image, SafeAreaView, View} from 'react-native';
|
import {ScrollView, Image, View} from 'react-native';
|
||||||
import {styles} from './Profile.styled';
|
import {styles} from './Profile.styled';
|
||||||
import {useProfile} from './useProfile.hook';
|
import {useProfile} from './useProfile.hook';
|
||||||
import {Confirm} from '../confirm/Confirm';
|
import {Confirm} from '../confirm/Confirm';
|
||||||
|
@ -126,7 +126,7 @@ export function useProfile(params: ContactParams) {
|
|||||||
},
|
},
|
||||||
saveAndConnect: async () => {
|
saveAndConnect: async () => {
|
||||||
const contact = app.state.session?.getContact();
|
const contact = app.state.session?.getContact();
|
||||||
const added = await contact.addAndConnectCard(state.node, state.guid);
|
await contact.addAndConnectCard(state.node, state.guid);
|
||||||
},
|
},
|
||||||
remove: async () => {
|
remove: async () => {
|
||||||
const contact = app.state.session?.getContact();
|
const contact = app.state.session?.getContact();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useRef, useEffect, useState } from 'react';
|
import React, { useRef, useEffect, useState } from 'react';
|
||||||
import { Animated, useAnimatedValue, View } from 'react-native';
|
import { Animated, useAnimatedValue, View } from 'react-native';
|
||||||
import { useRing } from './useRing.hook';
|
import { useRing } from './useRing.hook';
|
||||||
import { styles } from './Ring.styled'
|
import { styles } from './Ring.styled';
|
||||||
import { Card as Contact } from '../card/Card';
|
import { Card as Contact } from '../card/Card';
|
||||||
import { Icon, Text, Surface, IconButton, ActivityIndicator } from 'react-native-paper';
|
import { Icon, Text, Surface, IconButton, ActivityIndicator } from 'react-native-paper';
|
||||||
import { Confirm } from '../confirm/Confirm';
|
import { Confirm } from '../confirm/Confirm';
|
||||||
@ -20,7 +20,7 @@ export function Ring() {
|
|||||||
const [accepting, setAccepting] = useState(null as null|string);
|
const [accepting, setAccepting] = useState(null as null|string);
|
||||||
const [ignoring, setIgnoring] = useState(null as null|string);
|
const [ignoring, setIgnoring] = useState(null as null|string);
|
||||||
const [declining, setDeclining] = useState(null as null|string);
|
const [declining, setDeclining] = useState(null as null|string);
|
||||||
const scale = useAnimatedValue(0)
|
const scale = useAnimatedValue(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ringing = setInterval(() => {
|
const ringing = setInterval(() => {
|
||||||
@ -44,6 +44,7 @@ export function Ring() {
|
|||||||
useNativeDriver: false,
|
useNativeDriver: false,
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [accepting, state.calling, state.calls]);
|
}, [accepting, state.calling, state.calls]);
|
||||||
|
|
||||||
const toggleAudio = async () => {
|
const toggleAudio = async () => {
|
||||||
@ -61,7 +62,7 @@ export function Ring() {
|
|||||||
}
|
}
|
||||||
setApplyingAudio(false);
|
setApplyingAudio(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const end = async () => {
|
const end = async () => {
|
||||||
if (!ending) {
|
if (!ending) {
|
||||||
@ -74,7 +75,7 @@ export function Ring() {
|
|||||||
}
|
}
|
||||||
setEnding(false);
|
setEnding(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const accept = async (callId, card) => {
|
const accept = async (callId, card) => {
|
||||||
if (!accepting) {
|
if (!accepting) {
|
||||||
@ -88,7 +89,7 @@ export function Ring() {
|
|||||||
}
|
}
|
||||||
setAccepting(null);
|
setAccepting(null);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const ignore = async (callId, card) => {
|
const ignore = async (callId, card) => {
|
||||||
if (!ignoring) {
|
if (!ignoring) {
|
||||||
@ -101,7 +102,7 @@ export function Ring() {
|
|||||||
}
|
}
|
||||||
setIgnoring(null);
|
setIgnoring(null);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const decline = async (callId, card) => {
|
const decline = async (callId, card) => {
|
||||||
if (!declining) {
|
if (!declining) {
|
||||||
@ -114,7 +115,7 @@ export function Ring() {
|
|||||||
}
|
}
|
||||||
setDeclining(null);
|
setDeclining(null);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const alertParams = {
|
const alertParams = {
|
||||||
title: state.strings.operationFailed,
|
title: state.strings.operationFailed,
|
||||||
@ -127,22 +128,25 @@ export function Ring() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const calls = state.calls.map((contact, index) => {
|
const calls = state.calls.map((contact) => {
|
||||||
const { callId, card } = contact;
|
const { callId, card } = contact;
|
||||||
const { name, handle, node, imageUrl } = card;
|
const { name, handle, node, imageUrl } = card;
|
||||||
const ignoreButton = <IconButton key="ignore" style={styles.circleIcon} iconColor="white" containerColor={Colors.pending} icon="eye-off-outline" compact="true" mode="contained" size={24} loading={ignoring===callId} onPress={()=>ignore(callId, card)} />
|
const ignoreButton = <IconButton key="ignore" style={styles.circleIcon} iconColor="white" containerColor={Colors.pending} icon="eye-off-outline" compact="true" mode="contained" size={24} loading={ignoring === callId} onPress={()=>ignore(callId, card)} />;
|
||||||
const declineButton = <IconButton key="decline" style={styles.flipIcon} iconColor="white" containerColor={Colors.offsync} icon="phone-outline" compact="true" mode="contained" size={24} loading={declining===callId} onPress={()=>decline(callId, card)} />
|
const declineButton = <IconButton key="decline" style={styles.flipIcon} iconColor="white" containerColor={Colors.offsync} icon="phone-outline" compact="true" mode="contained" size={24} loading={declining === callId} onPress={()=>decline(callId, card)} />;
|
||||||
const acceptButton = <IconButton key="accept" style={styles.circleIcon} iconColor="white" containerColor={Colors.primary} icon="phone-outline" compact="true" mode="contained" size={24} loading={accepting===callId} onPress={()=>accept(callId, card)} />
|
const acceptButton = <IconButton key="accept" style={styles.circleIcon} iconColor="white" containerColor={Colors.primary} icon="phone-outline" compact="true" mode="contained" size={24} loading={accepting === callId} onPress={()=>accept(callId, card)} />;
|
||||||
return (
|
return (
|
||||||
<Contact containerStyle={styles.card} placeholder={state.strings.name} imageUrl={imageUrl} name={name} node={node} handle={handle} actions={[ignoreButton, declineButton, acceptButton]} />
|
<Contact containerStyle={styles.card} placeholder={state.strings.name} imageUrl={imageUrl} name={name} node={node} handle={handle} actions={[ignoreButton, declineButton, acceptButton]} />
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sizeStyle = { width: '100%', height: scale };
|
||||||
|
const borderStyle = state.layout === 'large' ? { ...styles.ring, borderRadius: 16 } : { ...styles.ring, borderRadius: 0 };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View style={{ width: '100%', height: scale }}>
|
<Animated.View style={sizeStyle}>
|
||||||
<View style={(accepting || state.calling || state.calls.length > 0) ? styles.active : styles.inactive}>
|
<View style={(accepting || state.calling || state.calls.length > 0) ? styles.active : styles.inactive}>
|
||||||
{ state.calls.length > 0 && !accepting && !state.calling && (
|
{ state.calls.length > 0 && !accepting && !state.calling && (
|
||||||
<Surface elevation={4} mode="flat" style={{ ...styles.ring, borderRadius: state.layout === 'large' ? 16 : 0 }}>
|
<Surface elevation={4} mode="flat" style={borderStyle}>
|
||||||
{ calls[0] }
|
{ calls[0] }
|
||||||
</Surface>
|
</Surface>
|
||||||
)}
|
)}
|
||||||
@ -152,7 +156,7 @@ export function Ring() {
|
|||||||
</Surface>
|
</Surface>
|
||||||
)}
|
)}
|
||||||
{ state.calling && (
|
{ state.calling && (
|
||||||
<Surface elevation={4} mode="flat" style={{ ...styles.ring, borderRadius: state.layout === 'large' ? 16 : 0 }}>
|
<Surface elevation={4} mode="flat" style={borderStyle}>
|
||||||
<IconButton style={styles.circleIcon} iconColor="white" disabled={!state.connected} containerColor={Colors.primary} icon={state.audioEnabled ? 'microphone' : 'microphone-off'} compact="true" mode="contained" size={24} onPress={toggleAudio} />
|
<IconButton style={styles.circleIcon} iconColor="white" disabled={!state.connected} containerColor={Colors.primary} icon={state.audioEnabled ? 'microphone' : 'microphone-off'} compact="true" mode="contained" size={24} onPress={toggleAudio} />
|
||||||
<IconButton style={styles.circleIcon} iconColor="white" disabled={!state.connected} containerColor={Colors.confirmed} icon={(state.remoteVideo || state.localVideo) ? 'video-switch-outline' : 'arrow-expand-all'} compact="true" mode="contained" size={24} onPress={()=>actions.setFullscreen(true)} />
|
<IconButton style={styles.circleIcon} iconColor="white" disabled={!state.connected} containerColor={Colors.confirmed} icon={(state.remoteVideo || state.localVideo) ? 'video-switch-outline' : 'arrow-expand-all'} compact="true" mode="contained" size={24} onPress={()=>actions.setFullscreen(true)} />
|
||||||
<View style={styles.name}>
|
<View style={styles.name}>
|
||||||
@ -165,7 +169,7 @@ export function Ring() {
|
|||||||
</View>
|
</View>
|
||||||
<View style={styles.status}>
|
<View style={styles.status}>
|
||||||
{ state.connected && (
|
{ state.connected && (
|
||||||
<Text style={styles.duration}>{ `${Math.floor(state.duration/60)}:${(state.duration % 60).toString().padStart(2, '0')}` }</Text>
|
<Text style={styles.duration}>{ `${Math.floor(state.duration / 60)}:${(state.duration % 60).toString().padStart(2, '0')}` }</Text>
|
||||||
)}
|
)}
|
||||||
{ !state.connected && (
|
{ !state.connected && (
|
||||||
<View style={{ transform: [{ rotate: counter % 2 ? '15deg' : '-15deg' }] }}>
|
<View style={{ transform: [{ rotate: counter % 2 ? '15deg' : '-15deg' }] }}>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useState, useContext, useEffect, useRef } from 'react'
|
import { useState, useContext, useEffect, useRef } from 'react';
|
||||||
import { RingContext } from '../context/RingContext'
|
import { RingContext } from '../context/RingContext';
|
||||||
import { DisplayContext } from '../context/DisplayContext'
|
import { DisplayContext } from '../context/DisplayContext';
|
||||||
import { ContextType } from '../context/ContextType'
|
import { ContextType } from '../context/ContextType';
|
||||||
import { Card } from 'databag-client-sdk';
|
import { Card } from 'databag-client-sdk';
|
||||||
|
|
||||||
export function useRing() {
|
export function useRing() {
|
||||||
@ -21,12 +21,12 @@ export function useRing() {
|
|||||||
connected: false,
|
connected: false,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
failed: false,
|
failed: false,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { layout, strings } = display.state;
|
const { layout, strings } = display.state;
|
||||||
@ -37,14 +37,14 @@ export function useRing() {
|
|||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
if (offset.current) {
|
if (offset.current) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const duration = Math.floor((now.getTime() / 1000) - offsetTime.current);
|
const duration = Math.floor((now.getTime() / 1000) - offsetTime.current);
|
||||||
updateState({ duration });
|
updateState({ duration });
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { calls, calling, localVideo, remoteVideo, audioEnabled, connected, connectedTime, failed } = ring.state;
|
const { calls, calling, localVideo, remoteVideo, audioEnabled, connected, connectedTime, failed } = ring.state;
|
||||||
|
@ -34,7 +34,7 @@ export const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
overflow: 'hidden'
|
overflow: 'hidden',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -19,6 +19,7 @@ export function Selector({ share, selected, channels }: { share: { filePath: str
|
|||||||
setShow(true);
|
setShow(true);
|
||||||
actions.clearFocus();
|
actions.clearFocus();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [share]);
|
}, [share]);
|
||||||
|
|
||||||
const select = () => {
|
const select = () => {
|
||||||
@ -28,7 +29,7 @@ export function Selector({ share, selected, channels }: { share: { filePath: str
|
|||||||
setTopic(null);
|
setTopic(null);
|
||||||
selected(cardId, channelId);
|
selected(cardId, channelId);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={show} onRequestClose={()=>setShow(false)}>
|
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={show} onRequestClose={()=>setShow(false)}>
|
||||||
@ -51,8 +52,8 @@ export function Selector({ share, selected, channels }: { share: { filePath: str
|
|||||||
initialNumToRender={32}
|
initialNumToRender={32}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
renderItem={({item}) => {
|
renderItem={({item}) => {
|
||||||
const {cardId, channelId, sealed, focused, hosted, unread, imageUrl, subject, message} = item;
|
const {cardId, channelId, sealed, hosted, imageUrl, subject, message} = item;
|
||||||
const select = () => {
|
const selection = () => {
|
||||||
setTopic({ cardId, channelId });
|
setTopic({ cardId, channelId });
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
@ -62,7 +63,7 @@ export function Selector({ share, selected, channels }: { share: { filePath: str
|
|||||||
...styles.channel,
|
...styles.channel,
|
||||||
borderColor: theme.colors.outlineVariant,
|
borderColor: theme.colors.outlineVariant,
|
||||||
}}
|
}}
|
||||||
select={select}
|
select={selection}
|
||||||
unread={false}
|
unread={false}
|
||||||
sealed={sealed}
|
sealed={sealed}
|
||||||
hosted={hosted}
|
hosted={hosted}
|
||||||
@ -85,7 +86,7 @@ export function Selector({ share, selected, channels }: { share: { filePath: str
|
|||||||
<Button style={styles.control} mode="outlined" onPress={()=>setShow(false)}>
|
<Button style={styles.control} mode="outlined" onPress={()=>setShow(false)}>
|
||||||
{state.strings.cancel}
|
{state.strings.cancel}
|
||||||
</Button>
|
</Button>
|
||||||
<Button style={styles.control} disabled={topic==null} mode="contained" onPress={select}>
|
<Button style={styles.control} disabled={topic == null} mode="contained" onPress={select}>
|
||||||
{state.strings.selectImage}
|
{state.strings.selectImage}
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
|
@ -1,25 +1,19 @@
|
|||||||
import { useState, useContext, useEffect } from 'react'
|
import { useContext } from 'react';
|
||||||
import { AppContext } from '../context/AppContext'
|
import { AppContext } from '../context/AppContext';
|
||||||
import { DisplayContext } from '../context/DisplayContext';
|
import { DisplayContext } from '../context/DisplayContext';
|
||||||
import { ContextType } from '../context/ContextType'
|
import { ContextType } from '../context/ContextType';
|
||||||
import { Channel } from 'databag-client-sdk';
|
|
||||||
|
|
||||||
export function useSelector() {
|
export function useSelector() {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) 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 state = {
|
||||||
const updateState = (value: any) => {
|
strings: display.state.strings,
|
||||||
setState((s) => ({ ...s, ...value }))
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
clearFocus: app.actions.clearFocus,
|
clearFocus: app.actions.clearFocus,
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
import React, {useState, useCallback, useEffect} from 'react';
|
import React, {useState, useCallback} from 'react';
|
||||||
import {SafeAreaView, Pressable, View, useColorScheme} from 'react-native';
|
import {SafeAreaView, View, useColorScheme} from 'react-native';
|
||||||
import {styles} from './Service.styled';
|
import {styles} from './Service.styled';
|
||||||
import {IconButton, Surface, Text, Icon} from 'react-native-paper';
|
import {IconButton, Surface} from 'react-native-paper';
|
||||||
import {Accounts} from '../accounts/Accounts';
|
import {Accounts} from '../accounts/Accounts';
|
||||||
import {Setup} from '../setup/Setup';
|
import {Setup} from '../setup/Setup';
|
||||||
import {useService} from './useService.hook';
|
import {useService} from './useService.hook';
|
||||||
import {NavigationContainer, DefaultTheme, DarkTheme} from '@react-navigation/native';
|
import {NavigationContainer, DefaultTheme, DarkTheme} from '@react-navigation/native';
|
||||||
import {createDrawerNavigator} from '@react-navigation/drawer';
|
import {createDrawerNavigator} from '@react-navigation/drawer';
|
||||||
import {Colors} from '../constants/Colors';
|
|
||||||
|
|
||||||
const SetupDrawer = createDrawerNavigator();
|
const SetupDrawer = createDrawerNavigator();
|
||||||
|
|
||||||
export function Service() {
|
export function Service() {
|
||||||
const { state, actions } = useService();
|
const { state } = useService();
|
||||||
const [tab, setTab] = useState('accounts');
|
const [tab, setTab] = useState('accounts');
|
||||||
const scheme = useColorScheme();
|
const scheme = useColorScheme();
|
||||||
const showAccounts = {display: tab === 'accounts' ? 'flex' : 'none'};
|
const showAccounts = {display: tab === 'accounts' ? 'flex' : 'none'};
|
||||||
const showSetup = {display: tab === 'setup' ? 'flex' : 'none'};
|
const showSetup = {display: tab === 'setup' ? 'flex' : 'none'};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.service}>
|
<Surface elevation={0} style={styles.service}>
|
||||||
{state.layout !== 'large' && (
|
{state.layout !== 'large' && (
|
||||||
<View>
|
<View>
|
||||||
<View style={styles.full}>
|
<View style={styles.full}>
|
||||||
@ -95,7 +94,7 @@ export function Service() {
|
|||||||
</View>
|
</View>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
)}
|
)}
|
||||||
</View>
|
</Surface>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {useEffect, useState, useContext, useRef} from 'react';
|
import {useEffect, useState, useContext} from 'react';
|
||||||
import {AppContext} from '../context/AppContext';
|
import {AppContext} from '../context/AppContext';
|
||||||
import {DisplayContext} from '../context/DisplayContext';
|
import {DisplayContext} from '../context/DisplayContext';
|
||||||
import {ContextType} from '../context/ContextType';
|
import {ContextType} from '../context/ContextType';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, {useState, useCallback, useEffect} from 'react';
|
import React, {useState, useCallback, useEffect} from 'react';
|
||||||
import {SafeAreaView, Modal, Pressable, View, useColorScheme} from 'react-native';
|
import {SafeAreaView, Pressable, View, useColorScheme} from 'react-native';
|
||||||
import {RingContextProvider} from '../context/RingContext';
|
import {RingContextProvider} from '../context/RingContext';
|
||||||
import {styles} from './Session.styled';
|
import {styles} from './Session.styled';
|
||||||
import {IconButton, Surface, Text, Icon} from 'react-native-paper';
|
import {IconButton, Surface, Text, Icon} from 'react-native-paper';
|
||||||
@ -13,8 +13,6 @@ import {Identity} from '../identity/Identity';
|
|||||||
import {Base} from '../base/Base';
|
import {Base} from '../base/Base';
|
||||||
import {Conversation} from '../conversation/Conversation';
|
import {Conversation} from '../conversation/Conversation';
|
||||||
import {useSession} from './useSession.hook';
|
import {useSession} from './useSession.hook';
|
||||||
import {TransitionPresets} from '@react-navigation/stack';
|
|
||||||
import {Focus, Card} from 'databag-client-sdk';
|
|
||||||
import {NavigationContainer, DefaultTheme, DarkTheme} from '@react-navigation/native';
|
import {NavigationContainer, DefaultTheme, DarkTheme} from '@react-navigation/native';
|
||||||
import {createDrawerNavigator} from '@react-navigation/drawer';
|
import {createDrawerNavigator} from '@react-navigation/drawer';
|
||||||
import {createNativeStackNavigator} from '@react-navigation/native-stack';
|
import {createNativeStackNavigator} from '@react-navigation/native-stack';
|
||||||
@ -45,11 +43,11 @@ export function Session({ share }: { share: { filePath: string, mimeType: string
|
|||||||
|
|
||||||
const textContact = (cardId: null|string) => {
|
const textContact = (cardId: null|string) => {
|
||||||
setTextCard({ cardId });
|
setTextCard({ cardId });
|
||||||
}
|
};
|
||||||
|
|
||||||
const callContact = (card: null|Card) => {
|
const callContact = (card: null|Card) => {
|
||||||
setCallCard({ card });
|
setCallCard({ card });
|
||||||
}
|
};
|
||||||
|
|
||||||
const sessionNav = {strings: state.strings, callContact, callCard, textContact, textCard, focus, setFocus, share};
|
const sessionNav = {strings: state.strings, callContact, callCard, textContact, textCard, focus, setFocus, share};
|
||||||
const showContent = {display: tab === 'content' ? 'flex' : 'none'};
|
const showContent = {display: tab === 'content' ? 'flex' : 'none'};
|
||||||
@ -61,18 +59,19 @@ export function Session({ share }: { share: { filePath: string, mimeType: string
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setDismissed(false);
|
setDismissed(false);
|
||||||
}, 60000);
|
}, 60000);
|
||||||
}
|
};
|
||||||
|
|
||||||
const contentTab = () => {
|
const contentTab = () => {
|
||||||
if (tab !== 'content') {
|
if (tab !== 'content') {
|
||||||
setTab('content');
|
setTab('content');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (share) {
|
if (share) {
|
||||||
contentTab();
|
contentTab();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [share]);
|
}, [share]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -219,7 +218,7 @@ function ContentTab({scheme, textCard, contentTab, share}: {scheme: string, text
|
|||||||
const openConversation = (props) => {
|
const openConversation = (props) => {
|
||||||
props.navigation.navigate('conversation');
|
props.navigation.navigate('conversation');
|
||||||
contentTab();
|
contentTab();
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationContainer theme={scheme === 'dark' ? DarkTheme : DefaultTheme}>
|
<NavigationContainer theme={scheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||||
@ -293,7 +292,7 @@ function DetailsScreen({nav}) {
|
|||||||
const closeAll = (props) => {
|
const closeAll = (props) => {
|
||||||
props.navigation.closeDrawer();
|
props.navigation.closeDrawer();
|
||||||
nav.setFocus(false);
|
nav.setFocus(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const DetailsComponent = useCallback(
|
const DetailsComponent = useCallback(
|
||||||
(props) => (
|
(props) => (
|
||||||
@ -303,6 +302,7 @@ function DetailsScreen({nav}) {
|
|||||||
/>
|
/>
|
||||||
</Surface>
|
</Surface>
|
||||||
),
|
),
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
[nav],
|
[nav],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -448,6 +448,7 @@ function SettingsScreen({nav}) {
|
|||||||
function HomeScreen({nav}) {
|
function HomeScreen({nav}) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
nav.contacts.closeDrawer();
|
nav.contacts.closeDrawer();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [nav.callCard]);
|
}, [nav.callCard]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -460,7 +461,7 @@ function HomeScreen({nav}) {
|
|||||||
<Content share={nav.share} textCard={nav.textCard} closeAll={()=>{}} openConversation={()=>nav.setFocus(true)} />
|
<Content share={nav.share} textCard={nav.textCard} closeAll={()=>{}} openConversation={()=>nav.setFocus(true)} />
|
||||||
</Surface>
|
</Surface>
|
||||||
</View>
|
</View>
|
||||||
<Surface style={styles.right} mode="flat">
|
<Surface style={styles.right} mode="flat">
|
||||||
{ !nav.focus && (
|
{ !nav.focus && (
|
||||||
<Base />
|
<Base />
|
||||||
)}
|
)}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {useEffect, useState, useContext, useRef} from 'react';
|
import {useEffect, useState, useContext} from 'react';
|
||||||
import { AppState } from 'react-native';
|
import { AppState } from 'react-native';
|
||||||
import {AppContext} from '../context/AppContext';
|
import {AppContext} from '../context/AppContext';
|
||||||
import {DisplayContext} from '../context/DisplayContext';
|
import {DisplayContext} from '../context/DisplayContext';
|
||||||
@ -25,13 +25,13 @@ export function useSession() {
|
|||||||
if (loaded) {
|
if (loaded) {
|
||||||
SplashScreen.hide();
|
SplashScreen.hide();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const setSdkState = (state: string) => {
|
const setSdkState = (sdkState: string) => {
|
||||||
updateState({ sdkState: state === 'connected' });
|
updateState({ sdkState: sdkState === 'connected' });
|
||||||
}
|
};
|
||||||
const setAppState = (state: string) => {
|
const setAppState = (appState: string) => {
|
||||||
updateState({ appState: state === 'active' });
|
updateState({ appState: appState === 'active' });
|
||||||
}
|
};
|
||||||
const session = app.state.session;
|
const session = app.state.session;
|
||||||
if (session) {
|
if (session) {
|
||||||
const content = session.getContent();
|
const content = session.getContent();
|
||||||
@ -42,7 +42,7 @@ export function useSession() {
|
|||||||
session.removeStatusListener(setSdkState);
|
session.removeStatusListener(setSdkState);
|
||||||
content.removeLoadedListener(setContentState);
|
content.removeLoadedListener(setContentState);
|
||||||
sub.remove();
|
sub.remove();
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}, [app.state.session]);
|
}, [app.state.session]);
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
setBlockedError(true);
|
setBlockedError(true);
|
||||||
}
|
}
|
||||||
setBlockedMessage(true);
|
setBlockedMessage(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
const unblockMessage = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
|
const unblockMessage = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
|
||||||
try {
|
try {
|
||||||
@ -62,7 +62,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
setBlockedError(true);
|
setBlockedError(true);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const blockedMessages = state.blockedMessages.map((blocked, index) => (
|
const blockedMessages = state.blockedMessages.map((blocked, index) => (
|
||||||
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
|
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
|
||||||
@ -80,7 +80,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
setBlockedError(true);
|
setBlockedError(true);
|
||||||
}
|
}
|
||||||
setBlockedChannel(true);
|
setBlockedChannel(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
const unblockChannel = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
|
const unblockChannel = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
|
||||||
try {
|
try {
|
||||||
@ -90,7 +90,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
setBlockedError(true);
|
setBlockedError(true);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const blockedChannels = state.blockedChannels.map((blocked, index) => (
|
const blockedChannels = state.blockedChannels.map((blocked, index) => (
|
||||||
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
|
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
|
||||||
@ -108,7 +108,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
setBlockedError(true);
|
setBlockedError(true);
|
||||||
}
|
}
|
||||||
setBlockedContact(true);
|
setBlockedContact(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
const unblockContact = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
|
const unblockContact = async (blocked: {cardId: string | null, channelId: string, topicId: string, timestamp: number}) => {
|
||||||
try {
|
try {
|
||||||
@ -118,7 +118,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
setBlockedError(true);
|
setBlockedError(true);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const blockedContacts = state.blockedContacts.map((blocked, index) => (
|
const blockedContacts = state.blockedContacts.map((blocked, index) => (
|
||||||
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
|
<View key={index} style={{ ...styles.blockedItem, borderColor: theme.colors.outlineVariant }}>
|
||||||
@ -669,7 +669,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
<View style={styles.modalControls}>
|
<View style={styles.modalControls}>
|
||||||
<View style={styles.modalOption}>
|
<View style={styles.modalOption}>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={styles.optionIcon}
|
style={styles.optionIcon}
|
||||||
iconColor={Colors.primary}
|
iconColor={Colors.primary}
|
||||||
icon="menu-right-outline"
|
icon="menu-right-outline"
|
||||||
size={32}
|
size={32}
|
||||||
@ -696,7 +696,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
</Button>
|
</Button>
|
||||||
<View style={styles.modalOther}>
|
<View style={styles.modalOther}>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={styles.optionIcon}
|
style={styles.optionIcon}
|
||||||
iconColor={Colors.primary}
|
iconColor={Colors.primary}
|
||||||
icon="menu-left-outline"
|
icon="menu-left-outline"
|
||||||
size={32}
|
size={32}
|
||||||
@ -719,8 +719,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.sealPassword}
|
value={state.sealPassword}
|
||||||
label={Platform.OS==='ios'?state.strings.password:undefined}
|
label={Platform.OS === 'ios' ? state.strings.password : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.password:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.password : undefined}
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -739,8 +739,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.sealConfirm}
|
value={state.sealConfirm}
|
||||||
label={Platform.OS==='ios'?state.strings.confirmPassword:undefined}
|
label={Platform.OS === 'ios' ? state.strings.confirmPassword : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.confirmPassword:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.confirmPassword : undefined}
|
||||||
secureTextEntry={!showConfirm}
|
secureTextEntry={!showConfirm}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -772,8 +772,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.sealPassword}
|
value={state.sealPassword}
|
||||||
label={Platform.OS==='ios'?state.strings.password:undefined}
|
label={Platform.OS === 'ios' ? state.strings.password : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.password:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.password : undefined}
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -789,7 +789,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
<View style={styles.modalControls}>
|
<View style={styles.modalControls}>
|
||||||
<View style={styles.modalOption}>
|
<View style={styles.modalOption}>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={styles.optionIcon}
|
style={styles.optionIcon}
|
||||||
iconColor={Colors.primary}
|
iconColor={Colors.primary}
|
||||||
icon="menu-right-outline"
|
icon="menu-right-outline"
|
||||||
size={32}
|
size={32}
|
||||||
@ -813,7 +813,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
</Button>
|
</Button>
|
||||||
<View style={styles.modalOther}>
|
<View style={styles.modalOther}>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={styles.optionIcon}
|
style={styles.optionIcon}
|
||||||
iconColor={Colors.primary}
|
iconColor={Colors.primary}
|
||||||
icon="menu-left-outline"
|
icon="menu-left-outline"
|
||||||
size={32}
|
size={32}
|
||||||
@ -836,8 +836,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.sealDelete}
|
value={state.sealDelete}
|
||||||
label={Platform.OS==='ios'?state.strings.deleteKey:undefined}
|
label={Platform.OS === 'ios' ? state.strings.deleteKey : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.deleteKey:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.deleteKey : undefined}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
onChangeText={value => actions.setSealDelete(value)}
|
onChangeText={value => actions.setSealDelete(value)}
|
||||||
/>
|
/>
|
||||||
@ -859,8 +859,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.sealPassword}
|
value={state.sealPassword}
|
||||||
label={Platform.OS==='ios'?state.strings.password:undefined}
|
label={Platform.OS === 'ios' ? state.strings.password : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.password:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.password : undefined}
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -899,8 +899,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.name:undefined}
|
label={Platform.OS === 'ios' ? state.strings.name : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.name:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.name : undefined}
|
||||||
value={state.name}
|
value={state.name}
|
||||||
left={<TextInput.Icon style={styles.inputIcon} icon="account" />}
|
left={<TextInput.Icon style={styles.inputIcon} icon="account" />}
|
||||||
onChangeText={value => actions.setName(value)}
|
onChangeText={value => actions.setName(value)}
|
||||||
@ -911,8 +911,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.location:undefined}
|
label={Platform.OS === 'ios' ? state.strings.location : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.location:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.location : undefined}
|
||||||
value={state.location}
|
value={state.location}
|
||||||
left={<TextInput.Icon style={styles.inputIcon} icon="map-marker-outline" />}
|
left={<TextInput.Icon style={styles.inputIcon} icon="map-marker-outline" />}
|
||||||
onChangeText={value => actions.setLocation(value)}
|
onChangeText={value => actions.setLocation(value)}
|
||||||
@ -923,8 +923,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios'?state.strings.description:undefined}
|
label={Platform.OS === 'ios' ? state.strings.description : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.description:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.description : undefined}
|
||||||
value={state.description}
|
value={state.description}
|
||||||
left={<TextInput.Icon style={styles.inputIcon} icon="book-open-outline" />}
|
left={<TextInput.Icon style={styles.inputIcon} icon="book-open-outline" />}
|
||||||
onChangeText={value => actions.setDescription(value)}
|
onChangeText={value => actions.setDescription(value)}
|
||||||
@ -1013,8 +1013,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
label={Platform.OS==='ios' ? state.strings.username : undefined}
|
label={Platform.OS === 'ios' ? state.strings.username : undefined}
|
||||||
placeholder={Platform.OS!=='ios' ? state.strings.username : undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.username : undefined}
|
||||||
value={state.handle}
|
value={state.handle}
|
||||||
left={<TextInput.Icon style={styles.inputIcon} icon="account" />}
|
left={<TextInput.Icon style={styles.inputIcon} icon="account" />}
|
||||||
right={
|
right={
|
||||||
@ -1035,8 +1035,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.password}
|
value={state.password}
|
||||||
label={Platform.OS==='ios' ? state.strings.password : undefined}
|
label={Platform.OS === 'ios' ? state.strings.password : undefined}
|
||||||
placeholder={Platform.OS!=='ios' ? state.strings.password : undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.password : undefined}
|
||||||
secureTextEntry={!showPassword}
|
secureTextEntry={!showPassword}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -1055,8 +1055,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.confirm}
|
value={state.confirm}
|
||||||
label={Platform.OS==='ios' ? state.strings.confirmPassword : undefined}
|
label={Platform.OS === 'ios' ? state.strings.confirmPassword : undefined}
|
||||||
placeholder={Platform.OS!=='ios' ? state.strings.confirmPassword : undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.confirmPassword : undefined}
|
||||||
secureTextEntry={!showConfirm}
|
secureTextEntry={!showConfirm}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||||
right={
|
right={
|
||||||
@ -1121,8 +1121,8 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
value={state.remove}
|
value={state.remove}
|
||||||
label={Platform.OS==='ios'?state.strings.deleteKey:undefined}
|
label={Platform.OS === 'ios' ? state.strings.deleteKey : undefined}
|
||||||
placeholder={Platform.OS!=='ios'?state.strings.deleteKey:undefined}
|
placeholder={Platform.OS !== 'ios' ? state.strings.deleteKey : undefined}
|
||||||
left={<TextInput.Icon style={styles.icon} icon="delete-outline" />}
|
left={<TextInput.Icon style={styles.icon} icon="delete-outline" />}
|
||||||
onChangeText={value => actions.setRemove(value)}
|
onChangeText={value => actions.setRemove(value)}
|
||||||
/>
|
/>
|
||||||
@ -1149,7 +1149,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedMessage(false)} />
|
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedMessage(false)} />
|
||||||
</View>
|
</View>
|
||||||
<Surface style={styles.blocked} elevation={1} mode="flat">
|
<Surface style={styles.blocked} elevation={1} mode="flat">
|
||||||
{ state.blockedMessages.length == 0 && (
|
{ state.blockedMessages.length === 0 && (
|
||||||
<View style={styles.blockedEmpty}>
|
<View style={styles.blockedEmpty}>
|
||||||
<Text style={styles.blockedLabel}>{ state.strings.noMessages }</Text>
|
<Text style={styles.blockedLabel}>{ state.strings.noMessages }</Text>
|
||||||
</View>
|
</View>
|
||||||
@ -1159,7 +1159,7 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
{ blockedMessages }
|
{ blockedMessages }
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</Surface>
|
</Surface>
|
||||||
<View style={styles.blockedDone}>
|
<View style={styles.blockedDone}>
|
||||||
{ blockedError && (
|
{ blockedError && (
|
||||||
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
|
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
|
||||||
@ -1182,17 +1182,17 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedChannel(false)} />
|
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedChannel(false)} />
|
||||||
</View>
|
</View>
|
||||||
<Surface style={styles.blocked} elevation={1} mode="flat">
|
<Surface style={styles.blocked} elevation={1} mode="flat">
|
||||||
{ state.blockedChannels.length == 0 && (
|
{ state.blockedChannels.length === 0 && (
|
||||||
<View style={styles.blockedEmpty}>
|
<View style={styles.blockedEmpty}>
|
||||||
<Text style={styles.blockedLabel}>{ state.strings.noTopics }</Text>
|
<Text style={styles.blockedLabel}>{ state.strings.noTopics }</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{ state.blockedChannels.length > 0 && (
|
{ state.blockedChannels.length > 0 && (
|
||||||
<View>
|
<View>
|
||||||
{ blockedChannels }
|
{ blockedChannels }
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</Surface>
|
</Surface>
|
||||||
<View style={styles.blockedDone}>
|
<View style={styles.blockedDone}>
|
||||||
{ blockedError && (
|
{ blockedError && (
|
||||||
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
|
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
|
||||||
@ -1215,17 +1215,17 @@ export function Settings({showLogout}: {showLogout: boolean}) {
|
|||||||
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedContact(false)} />
|
<IconButton style={styles.blockedClose} icon="close" size={24} onPress={() => setBlockedContact(false)} />
|
||||||
</View>
|
</View>
|
||||||
<Surface style={styles.blocked} elevation={1} mode="flat">
|
<Surface style={styles.blocked} elevation={1} mode="flat">
|
||||||
{ state.blockedContacts.length == 0 && (
|
{ state.blockedContacts.length === 0 && (
|
||||||
<View style={styles.blockedEmpty}>
|
<View style={styles.blockedEmpty}>
|
||||||
<Text style={styles.blockedLabel}>{ state.strings.noContacts }</Text>
|
<Text style={styles.blockedLabel}>{ state.strings.noContacts }</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{ state.blockedContacts.length > 0 && (
|
{ state.blockedContacts.length > 0 && (
|
||||||
<View>
|
<View>
|
||||||
{ blockedContacts }
|
{ blockedContacts }
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</Surface>
|
</Surface>
|
||||||
<View style={styles.blockedDone}>
|
<View style={styles.blockedDone}>
|
||||||
{ blockedError && (
|
{ blockedError && (
|
||||||
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
|
<Text style={styles.blockedError}>{ state.strings.operationFailed }</Text>
|
||||||
|
@ -258,7 +258,7 @@ export function useSettings() {
|
|||||||
unblockMessage: async (cardId: string | null, channelId: string, topicId: string) => {
|
unblockMessage: async (cardId: string | null, channelId: string, topicId: string) => {
|
||||||
const content = app.state.session.getContent();
|
const content = app.state.session.getContent();
|
||||||
await content.clearBlockedChannelTopic(cardId, channelId, topicId);
|
await content.clearBlockedChannelTopic(cardId, channelId, topicId);
|
||||||
const blockedMessages = state.blockedMessages.filter(blocked => (blocked.cardId != cardId || blocked.channelId != channelId || blocked.topicId != topicId));
|
const blockedMessages = state.blockedMessages.filter(blocked => (blocked.cardId !== cardId || blocked.channelId !== channelId || blocked.topicId !== topicId));
|
||||||
updateState({ blockedMessages });
|
updateState({ blockedMessages });
|
||||||
},
|
},
|
||||||
loadBlockedChannels: async () => {
|
loadBlockedChannels: async () => {
|
||||||
@ -269,7 +269,7 @@ export function useSettings() {
|
|||||||
unblockChannel: async (cardId: string | null, channelId: string) => {
|
unblockChannel: async (cardId: string | null, channelId: string) => {
|
||||||
const content = app.state.session.getContent();
|
const content = app.state.session.getContent();
|
||||||
await content.setBlockedChannel(cardId, channelId, false);
|
await content.setBlockedChannel(cardId, channelId, false);
|
||||||
const blockedChannels = state.blockedChannels.filter(blocked => (blocked.cardId != cardId || blocked.channelId != channelId));
|
const blockedChannels = state.blockedChannels.filter(blocked => (blocked.cardId !== cardId || blocked.channelId !== channelId));
|
||||||
updateState({ blockedChannels });
|
updateState({ blockedChannels });
|
||||||
},
|
},
|
||||||
loadBlockedContacts: async () => {
|
loadBlockedContacts: async () => {
|
||||||
@ -280,38 +280,38 @@ export function useSettings() {
|
|||||||
unblockContact: async (cardId: string) => {
|
unblockContact: async (cardId: string) => {
|
||||||
const contact = app.state.session.getContact();
|
const contact = app.state.session.getContact();
|
||||||
await contact.setBlockedCard(cardId, false);
|
await contact.setBlockedCard(cardId, false);
|
||||||
const blockedContacts = state.blockedContacts.filter(blocked => blocked.cardId != cardId);
|
const blockedContacts = state.blockedContacts.filter(blocked => blocked.cardId !== cardId);
|
||||||
updateState({ blockedContacts });
|
updateState({ blockedContacts });
|
||||||
},
|
},
|
||||||
getTimestamp: (created: number) => {
|
getTimestamp: (created: number) => {
|
||||||
const now = Math.floor((new Date()).getTime() / 1000)
|
const now = Math.floor((new Date()).getTime() / 1000);
|
||||||
const date = new Date(created * 1000);
|
const date = new Date(created * 1000);
|
||||||
const offset = now - created;
|
const offset = now - created;
|
||||||
if(offset < 43200) {
|
if(offset < 43200) {
|
||||||
if (state.timeFormat === '12h') {
|
if (state.timeFormat === '12h') {
|
||||||
return date.toLocaleTimeString("en-US", {hour: 'numeric', minute:'2-digit'});
|
return date.toLocaleTimeString('en-US', {hour: 'numeric', minute:'2-digit'});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleTimeString("en-GB", {hour: 'numeric', minute:'2-digit'});
|
return date.toLocaleTimeString('en-GB', {hour: 'numeric', minute:'2-digit'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (offset < 31449600) {
|
else if (offset < 31449600) {
|
||||||
if (state.dateFormat === 'mm/dd') {
|
if (state.dateFormat === 'mm/dd') {
|
||||||
return date.toLocaleDateString("en-US", {day: 'numeric', month:'numeric'});
|
return date.toLocaleDateString('en-US', {day: 'numeric', month:'numeric'});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleDateString("en-GB", {day: 'numeric', month:'numeric'});
|
return date.toLocaleDateString('en-GB', {day: 'numeric', month:'numeric'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (state.dateFormat === 'mm/dd') {
|
if (state.dateFormat === 'mm/dd') {
|
||||||
return date.toLocaleDateString("en-US");
|
return date.toLocaleDateString('en-US');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return date.toLocaleDateString("en-GB");
|
return date.toLocaleDateString('en-GB');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return {state, actions};
|
return {state, actions};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import {SafeAreaView, TouchableOpacity, Modal, Image, View, Pressable} from 'react-native';
|
import {TouchableOpacity, Modal, Image, View} from 'react-native';
|
||||||
import {ActivityIndicator, Icon, Button, IconButton, RadioButton, Switch, Surface, Divider, TextInput, Text} from 'react-native-paper';
|
import {ActivityIndicator, Icon, Button, IconButton, RadioButton, Switch, Surface, Divider, TextInput, Text} from 'react-native-paper';
|
||||||
import {styles} from './Setup.styled';
|
import {styles} from './Setup.styled';
|
||||||
import {useSetup} from './useSetup.hook';
|
import {useSetup} from './useSetup.hook';
|
||||||
@ -12,18 +12,17 @@ import Clipboard from '@react-native-clipboard/clipboard';
|
|||||||
|
|
||||||
export function Setup() {
|
export function Setup() {
|
||||||
const { state, actions } = useSetup();
|
const { state, actions } = useSetup();
|
||||||
const [mfaCode, setMfaCode] = useState('');
|
|
||||||
const [updating, setUpdating] = useState(false);
|
const [updating, setUpdating] = useState(false);
|
||||||
const [secretCopy, setSecretCopy] = useState(false);
|
const [secretCopy, setSecretCopy] = useState(false);
|
||||||
const [confirmingAuth, setConfirmingAuth] = useState(false);
|
const [confirmingAuth, setConfirmingAuth] = useState(false);
|
||||||
|
|
||||||
const errorParams = {
|
const errorParams = {
|
||||||
title: state.strings.operationFailed,
|
title: state.strings.operationFailed,
|
||||||
prompt: state.strings.tryAgain,
|
prompt: state.strings.tryAgain,
|
||||||
cancel: {
|
cancel: {
|
||||||
label: state.strings.close,
|
label: state.strings.close,
|
||||||
action: actions.clearError,
|
action: actions.clearError,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const confirmAuth = async () => {
|
const confirmAuth = async () => {
|
||||||
@ -32,7 +31,7 @@ export function Setup() {
|
|||||||
await actions.confirmMFAuth();
|
await actions.confirmMFAuth();
|
||||||
setConfirmingAuth(false);
|
setConfirmingAuth(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const copySecret = async () => {
|
const copySecret = async () => {
|
||||||
if (!secretCopy) {
|
if (!secretCopy) {
|
||||||
@ -54,7 +53,7 @@ export function Setup() {
|
|||||||
}
|
}
|
||||||
setUpdating(false);
|
setUpdating(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.setup}>
|
<View style={styles.setup}>
|
||||||
@ -76,14 +75,14 @@ export function Setup() {
|
|||||||
<View style={styles.radioSelect}>
|
<View style={styles.radioSelect}>
|
||||||
<View style={styles.radio}>
|
<View style={styles.radio}>
|
||||||
<Text style={styles.radioLabel}>RSA2048</Text>
|
<Text style={styles.radioLabel}>RSA2048</Text>
|
||||||
<RadioButton.Item
|
<RadioButton.Item
|
||||||
disabled={state.loading}
|
disabled={state.loading}
|
||||||
rippleColor="transparent"
|
rippleColor="transparent"
|
||||||
style={styles.radioButton}
|
style={styles.radioButton}
|
||||||
label=""
|
label=""
|
||||||
mode="android"
|
mode="android"
|
||||||
status={state.setup?.keyType === 'RSA2048' ? 'checked' : 'unchecked'}
|
status={state.setup?.keyType === 'RSA2048' ? 'checked' : 'unchecked'}
|
||||||
onPress={() => { actions.setKeyType('RSA2048') }}
|
onPress={() => { actions.setKeyType('RSA2048'); }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.radio}>
|
<View style={styles.radio}>
|
||||||
@ -95,7 +94,7 @@ export function Setup() {
|
|||||||
label=""
|
label=""
|
||||||
mode="android"
|
mode="android"
|
||||||
status={state.setup?.keyType === 'RSA4096' ? 'checked' : 'unchecked'}
|
status={state.setup?.keyType === 'RSA4096' ? 'checked' : 'unchecked'}
|
||||||
onPress={() => { actions.setKeyType('RSA4096') }}
|
onPress={() => { actions.setKeyType('RSA4096'); }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@ -41,14 +41,14 @@ export function useSetup() {
|
|||||||
const mfaEnabled = await service.checkMFAuth();
|
const mfaEnabled = await service.checkMFAuth();
|
||||||
setup.current = await service.getSetup();
|
setup.current = await service.getSetup();
|
||||||
loading.current = false;
|
loading.current = false;
|
||||||
const storage = Math.floor((setup.current?.accountStorage || 0) / 1073741824);
|
const storage = Math.floor((setup.current?.accountStorage || 0) / 1073741824);
|
||||||
updateState({ setup: setup.current, mfaEnabled, accountStorage: storage.toString(), loading: false });
|
updateState({ setup: setup.current, mfaEnabled, accountStorage: storage.toString(), loading: false });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
await new Promise((r) => setTimeout(r, DELAY_MS));
|
await new Promise((r) => setTimeout(r, DELAY_MS));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
updated.current = true;
|
updated.current = true;
|
||||||
@ -60,7 +60,7 @@ export function useSetup() {
|
|||||||
const service = app.state.service;
|
const service = app.state.service;
|
||||||
await service.setSetup(setup.current);
|
await service.setSetup(setup.current);
|
||||||
if (updated.current) {
|
if (updated.current) {
|
||||||
save()
|
save();
|
||||||
} else {
|
} else {
|
||||||
updateState({ updating: false });
|
updateState({ updating: false });
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ export function useSetup() {
|
|||||||
updateState({ error: true });
|
updateState({ error: true });
|
||||||
}
|
}
|
||||||
}, DEBOUNCE_MS);
|
}, DEBOUNCE_MS);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { layout, strings} = display.state;
|
const { layout, strings} = display.state;
|
||||||
@ -82,9 +82,10 @@ export function useSetup() {
|
|||||||
sync();
|
sync();
|
||||||
return () => {
|
return () => {
|
||||||
loading.current = false;
|
loading.current = false;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}, []);
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [app.state.service]);
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
logout: app.actions.adminLogout,
|
logout: app.actions.adminLogout,
|
||||||
@ -117,7 +118,7 @@ export function useSetup() {
|
|||||||
await service.confirmMFAuth(state.mfaCode);
|
await service.confirmMFAuth(state.mfaCode);
|
||||||
updateState({ confirmingMFAuth: false, mfaEnabled: true });
|
updateState({ confirmingMFAuth: false, mfaEnabled: true });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const { message } = err as { message: string }
|
const { message } = err as { message: string };
|
||||||
if (message === '401') {
|
if (message === '401') {
|
||||||
updateState({ mfaMessage: state.strings.mfaError });
|
updateState({ mfaMessage: state.strings.mfaError });
|
||||||
} else if (message === '429') {
|
} else if (message === '429') {
|
||||||
@ -142,7 +143,7 @@ export function useSetup() {
|
|||||||
},
|
},
|
||||||
setAccountStorage: (accountStorage: string) => {
|
setAccountStorage: (accountStorage: string) => {
|
||||||
if (setup.current) {
|
if (setup.current) {
|
||||||
const storage = parseInt(accountStorage) * 1073741824;
|
const storage = parseInt(accountStorage, 10) * 1073741824;
|
||||||
if (storage >= 0) {
|
if (storage >= 0) {
|
||||||
setup.current.accountStorage = storage;
|
setup.current.accountStorage = storage;
|
||||||
updateState({ setup: setup.current, accountStorage });
|
updateState({ setup: setup.current, accountStorage });
|
||||||
@ -170,7 +171,7 @@ export function useSetup() {
|
|||||||
},
|
},
|
||||||
setOpenAccessLimit: (openAccessLimit: string) => {
|
setOpenAccessLimit: (openAccessLimit: string) => {
|
||||||
if (setup.current) {
|
if (setup.current) {
|
||||||
const limit = parseInt(openAccessLimit);
|
const limit = parseInt(openAccessLimit, 10);
|
||||||
if (limit >= 0) {
|
if (limit >= 0) {
|
||||||
setup.current.openAccessLimit = limit;
|
setup.current.openAccessLimit = limit;
|
||||||
updateState({ setup: setup.current, openAccessLimit });
|
updateState({ setup: setup.current, openAccessLimit });
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import { Colors } from '../constants/Colors';
|
|
||||||
|
|
||||||
export const styles = StyleSheet.create({
|
export const styles = StyleSheet.create({
|
||||||
base: {
|
base: {
|
||||||
@ -41,7 +40,7 @@ export const styles = StyleSheet.create({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
gap: 8,
|
gap: 8,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React from 'react';
|
||||||
import { View, Image } from 'react-native';
|
import { View, Image } from 'react-native';
|
||||||
import { styles } from './Welcome.styled';
|
import { styles } from './Welcome.styled';
|
||||||
import { useWelcome } from './useWelcome.hook';
|
import { useWelcome } from './useWelcome.hook';
|
||||||
@ -16,7 +16,7 @@ export function Welcome() {
|
|||||||
<View style={{ ...styles.base, backgroundColor: theme.colors.base }}>
|
<View style={{ ...styles.base, backgroundColor: theme.colors.base }}>
|
||||||
<Text style={styles.title}>Databag</Text>
|
<Text style={styles.title}>Databag</Text>
|
||||||
<Text style={styles.description}>{ state.strings.communication }</Text>
|
<Text style={styles.description}>{ state.strings.communication }</Text>
|
||||||
<Image style={styles.image} source={theme.colors.name == 'light' ? light : dark} resizeMode="contain" />
|
<Image style={styles.image} source={theme.colors.name === 'light' ? light : dark} resizeMode="contain" />
|
||||||
<View style={styles.steps}>
|
<View style={styles.steps}>
|
||||||
<View style={styles.step}>
|
<View style={styles.step}>
|
||||||
<Icon size={18} source="chevron-right" color={Colors.placeholder} />
|
<Icon size={18} source="chevron-right" color={Colors.placeholder} />
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import { useState, useContext, useEffect } from 'react'
|
import { useState, useContext, useEffect } from 'react';
|
||||||
import { DisplayContext } from '../context/DisplayContext';
|
import { DisplayContext } from '../context/DisplayContext';
|
||||||
import { AppContext } from '../context/AppContext';
|
import { AppContext } from '../context/AppContext';
|
||||||
import { ContextType } from '../context/ContextType'
|
import { ContextType } from '../context/ContextType';
|
||||||
|
|
||||||
export function useWelcome() {
|
export function useWelcome() {
|
||||||
const app = useContext(AppContext) as ContextType
|
const app = useContext(AppContext) as ContextType;
|
||||||
const display = useContext(DisplayContext) as ContextType
|
const display = useContext(DisplayContext) as ContextType;
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
strings: display.state.strings,
|
strings: display.state.strings,
|
||||||
showWelcome: null as null | boolean,
|
showWelcome: null as null | boolean,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const updateState = (value: any) => {
|
const updateState = (value: any) => {
|
||||||
setState((s) => ({ ...s, ...value }))
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const showWelcome = app.state.showWelcome;
|
const showWelcome = app.state.showWelcome;
|
||||||
@ -25,7 +25,7 @@ export function useWelcome() {
|
|||||||
clearWelcome: async () => {
|
clearWelcome: async () => {
|
||||||
await app.actions.setShowWelcome(false);
|
await app.actions.setShowWelcome(false);
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return { state, actions }
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user