mirror of
https://github.com/balzack/databag.git
synced 2025-04-24 02:25:26 +00:00
formatting code
This commit is contained in:
parent
ed369424cd
commit
c2642f534e
@ -11,28 +11,37 @@ export class LocalStore implements SqlStore {
|
||||
|
||||
public async open(path: string) {
|
||||
this.db = await SQLite.openDatabase({name: path, location: 'default'});
|
||||
await this.localStoreSet("CREATE TABLE IF NOT EXISTS local_store (key text, value text, unique(key));");
|
||||
await this.localStoreSet(
|
||||
'CREATE TABLE IF NOT EXISTS local_store (key text, value text, unique(key));',
|
||||
);
|
||||
}
|
||||
|
||||
public async get(key: string, value: string, unset: string): Promise<string> {
|
||||
try {
|
||||
const rows = await this.localStoreGet(`SELECT * FROM local_store WHERE key='${key}';`);
|
||||
const rows = await this.localStoreGet(
|
||||
`SELECT * FROM local_store WHERE key='${key}';`,
|
||||
);
|
||||
if (rows.length == 1 && rows[0].value != null) {
|
||||
return rows[0].value;
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
return unset;
|
||||
}
|
||||
|
||||
public async set(key: string, value: string): Promise<void> {
|
||||
await this.localStoreSet('INSERT OR REPLACE INTO local_store (key, value) values (?, ?)', [key, value]);
|
||||
await this.localStoreSet(
|
||||
'INSERT OR REPLACE INTO local_store (key, value) values (?, ?)',
|
||||
[key, value],
|
||||
);
|
||||
}
|
||||
|
||||
public async clear(key: string): Promise<void> {
|
||||
await this.localStoreSet('INSERT OR REPLACE INTO local_store (key, value) values (?, null)', [key]);
|
||||
await this.localStoreSet(
|
||||
'INSERT OR REPLACE INTO local_store (key, value) values (?, null)',
|
||||
[key],
|
||||
);
|
||||
}
|
||||
|
||||
private async localStoreSet(
|
||||
|
@ -1,109 +1,134 @@
|
||||
import { Crypto } from 'databag-client-sdk';
|
||||
import {Crypto} from 'databag-client-sdk';
|
||||
import CryptoJS from 'crypto-js';
|
||||
import { JSEncrypt } from 'jsencrypt'
|
||||
import { RSA } from 'react-native-rsa-native';
|
||||
import { generateSecureRandom } from 'react-native-securerandom';
|
||||
import {JSEncrypt} from 'jsencrypt';
|
||||
import {RSA} from 'react-native-rsa-native';
|
||||
import {generateSecureRandom} from 'react-native-securerandom';
|
||||
|
||||
export class NativeCrypto implements Crypto {
|
||||
|
||||
// generate salt for pbk function
|
||||
public async pbkdfSalt(): Promise<{ saltHex: string }> {
|
||||
public async pbkdfSalt(): Promise<{saltHex: string}> {
|
||||
const salt = await generateSecureRandom(16);
|
||||
const saltHex = this.uint8ToHexStr(salt);
|
||||
return { saltHex };
|
||||
return {saltHex};
|
||||
}
|
||||
|
||||
// generate aes key with pbkdf2
|
||||
public async pbkdfKey(saltHex: string, password: string): Promise<{ aesKeyHex: string }> {
|
||||
public async pbkdfKey(
|
||||
saltHex: string,
|
||||
password: string,
|
||||
): Promise<{aesKeyHex: string}> {
|
||||
const salt = CryptoJS.enc.Hex.parse(saltHex);
|
||||
const aes = CryptoJS.PBKDF2(password, salt, { keySize: 256 / 32, iterations: 1024, hasher: CryptoJS.algo.SHA1, });
|
||||
const aes = CryptoJS.PBKDF2(password, salt, {
|
||||
keySize: 256 / 32,
|
||||
iterations: 1024,
|
||||
hasher: CryptoJS.algo.SHA1,
|
||||
});
|
||||
const aesKeyHex = aes.toString();
|
||||
return { aesKeyHex };
|
||||
return {aesKeyHex};
|
||||
}
|
||||
|
||||
// generate random aes key
|
||||
public async aesKey(): Promise<{ aesKeyHex: string }> {
|
||||
public async aesKey(): Promise<{aesKeyHex: string}> {
|
||||
const aes = await generateSecureRandom(32);
|
||||
const aesHex = this.uint8ToHexStr(aes);
|
||||
return { aesKeyHex };
|
||||
return {aesKeyHex};
|
||||
}
|
||||
|
||||
// generate iv to use to aes function
|
||||
public async aesIv(): Promise<{ ivHex: string }> {
|
||||
public async aesIv(): Promise<{ivHex: string}> {
|
||||
const iv = await generateSecureRandom(16);
|
||||
const ivHex = this.uint8ToHexStr(iv);
|
||||
return { ivHex };
|
||||
return {ivHex};
|
||||
}
|
||||
|
||||
// encrypt data with aes key and iv
|
||||
public async aesEncrypt(data: string, ivHex: string, aesKeyHex: string): Promise<{ encryptedDataB64: string }> {
|
||||
public async aesEncrypt(
|
||||
data: string,
|
||||
ivHex: string,
|
||||
aesKeyHex: string,
|
||||
): Promise<{encryptedDataB64: string}> {
|
||||
const iv = CryptoJS.enc.Hex.parse(ivHex);
|
||||
const key = CryptoJS.enc.Hex.parse(aesKeyHex);
|
||||
const encrypted = CryptoJS.AES.encrypt(data, key, { iv });
|
||||
const encrypted = CryptoJS.AES.encrypt(data, key, {iv});
|
||||
const encryptedDataB64 = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
|
||||
return { encryptedDataB64 };
|
||||
return {encryptedDataB64};
|
||||
}
|
||||
|
||||
// decrypt data with aes key and iv
|
||||
public async aesDecrypt(encryptedDataB64: string, ivHex: string, aesKeyHex: string): Promise<{ data: string }> {
|
||||
public async aesDecrypt(
|
||||
encryptedDataB64: string,
|
||||
ivHex: string,
|
||||
aesKeyHex: string,
|
||||
): Promise<{data: string}> {
|
||||
const iv = CryptoJS.enc.Hex.parse(ivHex);
|
||||
const key = CryptoJS.enc.Hex.parse(aesKeyHex);
|
||||
const ciphertext = CryptoJS.enc.Base64.parse(encryptedDataB64);
|
||||
const cipher = CryptoJS.lib.CipherParams.create({ ciphertext, iv });
|
||||
const decrypted = CryptoJS.AES.decrypt(cipher, key, { iv });
|
||||
const cipher = CryptoJS.lib.CipherParams.create({ciphertext, iv});
|
||||
const decrypted = CryptoJS.AES.decrypt(cipher, key, {iv});
|
||||
const data = decrypted.toString(CryptoJS.enc.Utf8);
|
||||
return { data };
|
||||
return {data};
|
||||
}
|
||||
|
||||
// generate rsa key
|
||||
public async rsaKey(): Promise<{ publicKeyB64: string, privateKeyB64: string }> {
|
||||
const crypto = new JSEncrypt({ default_key_size: '2048' });
|
||||
public async rsaKey(): Promise<{
|
||||
publicKeyB64: string;
|
||||
privateKeyB64: string;
|
||||
}> {
|
||||
const crypto = new JSEncrypt({default_key_size: '2048'});
|
||||
crypto.getKey();
|
||||
const publicKey = crypto.getPublicKey();
|
||||
const publicKeyB64 = this.convertPem(publicKey);
|
||||
const privateKey = crypto.getPrivateKey();
|
||||
const privateKeyB64 = this.convertPem(privateKey);
|
||||
return { publicKeyB64, privateKeyB64 };
|
||||
return {publicKeyB64, privateKeyB64};
|
||||
}
|
||||
|
||||
// encrypt data with public rsa key
|
||||
public async rsaEncrypt(data: string, publicKeyB64: string): Promise<{ encryptedDataB64: string }> {
|
||||
public async rsaEncrypt(
|
||||
data: string,
|
||||
publicKeyB64: string,
|
||||
): Promise<{encryptedDataB64: string}> {
|
||||
const crypto = new JSEncrypt();
|
||||
crypto.setPublicKey(publicKeyB64);
|
||||
const encryptedDataB64 = crypto.encrypt(data);
|
||||
if (!encryptedDataB64) {
|
||||
throw new Error('rsaEncrypt failed');
|
||||
}
|
||||
return { encryptedDataB64 };
|
||||
return {encryptedDataB64};
|
||||
}
|
||||
|
||||
// decrypt data with private rsa key
|
||||
public async rsaDecrypt(encryptedDataB64: string, privateKeyB64: string): Promise<{ data: string }> {
|
||||
public async rsaDecrypt(
|
||||
encryptedDataB64: string,
|
||||
privateKeyB64: string,
|
||||
): Promise<{data: string}> {
|
||||
const crypto = new JSEncrypt();
|
||||
crypto.setPrivateKey(privateKeyB64);
|
||||
const data = await RSA.decrypt(encryptedDataB64, privateKeyB64);
|
||||
if (!data) {
|
||||
throw new Error('rsaDecrypt failed');
|
||||
}
|
||||
return { data };
|
||||
return {data};
|
||||
}
|
||||
|
||||
private convertPem(pem: string): string {
|
||||
const lines = pem.split('\n');
|
||||
let encoded = '';
|
||||
for(let i = 0;i < lines.length;i++){
|
||||
if (lines[i].trim().length > 0 &&
|
||||
lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
|
||||
lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
|
||||
lines[i].indexOf('-BEGIN PUBLIC KEY-') < 0 &&
|
||||
lines[i].indexOf('-END PUBLIC KEY-') < 0 &&
|
||||
lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
|
||||
lines[i].indexOf('-END RSA PUBLIC KEY-') < 0) {
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (
|
||||
lines[i].trim().length > 0 &&
|
||||
lines[i].indexOf('-BEGIN RSA PRIVATE KEY-') < 0 &&
|
||||
lines[i].indexOf('-BEGIN RSA PUBLIC KEY-') < 0 &&
|
||||
lines[i].indexOf('-BEGIN PUBLIC KEY-') < 0 &&
|
||||
lines[i].indexOf('-END PUBLIC KEY-') < 0 &&
|
||||
lines[i].indexOf('-END RSA PRIVATE KEY-') < 0 &&
|
||||
lines[i].indexOf('-END RSA PUBLIC KEY-') < 0
|
||||
) {
|
||||
encoded += lines[i].trim();
|
||||
}
|
||||
}
|
||||
return encoded
|
||||
};
|
||||
return encoded;
|
||||
}
|
||||
|
||||
private uint8ToHexStr(bin: Uint8Array) {
|
||||
let hex = '';
|
||||
|
@ -1,10 +1,5 @@
|
||||
import React, {useState} from 'react';
|
||||
import {
|
||||
Platform,
|
||||
KeyboardAvoidingView,
|
||||
View,
|
||||
Image,
|
||||
} from 'react-native';
|
||||
import {Platform, KeyboardAvoidingView, View, Image} from 'react-native';
|
||||
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
|
||||
import {useAccess} from './useAccess.hook';
|
||||
import {styles} from './Access.styled';
|
||||
@ -135,12 +130,14 @@ export function Access() {
|
||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||
right={
|
||||
showPassword ? (
|
||||
<TextInput.Icon style={styles.icon}
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="eye-off"
|
||||
onPress={() => setShowPassword(false)}
|
||||
/>
|
||||
) : (
|
||||
<TextInput.Icon style={styles.icon}
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="eye"
|
||||
onPress={() => setShowPassword(true)}
|
||||
/>
|
||||
@ -174,7 +171,9 @@ export function Access() {
|
||||
autoComplete="off"
|
||||
autoCorrect={false}
|
||||
label={state.strings.token}
|
||||
left={<TextInput.Icon style={styles.icon} icon="ticket-account" />}
|
||||
left={
|
||||
<TextInput.Icon style={styles.icon} icon="ticket-account" />
|
||||
}
|
||||
onChangeText={value => actions.setToken(value)}
|
||||
/>
|
||||
<TextInput
|
||||
@ -216,7 +215,12 @@ export function Access() {
|
||||
autoComplete="off"
|
||||
autoCorrect={false}
|
||||
label={state.strings.token}
|
||||
left={<TextInput.Icon style={styles.icon} icon="ticket-account" />}
|
||||
left={
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="ticket-account"
|
||||
/>
|
||||
}
|
||||
onChangeText={value => actions.setToken(value)}
|
||||
/>
|
||||
)}
|
||||
@ -257,12 +261,14 @@ export function Access() {
|
||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||
right={
|
||||
showPassword ? (
|
||||
<TextInput.Icon style={styles.icon}
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="eye-off"
|
||||
onPress={() => setShowPassword(false)}
|
||||
/>
|
||||
) : (
|
||||
<TextInput.Icon style={styles.icon}
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="eye"
|
||||
onPress={() => setShowPassword(true)}
|
||||
/>
|
||||
@ -283,12 +289,14 @@ export function Access() {
|
||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||
right={
|
||||
showPassword ? (
|
||||
<TextInput.Icon style={styles.icon}
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="eye-off"
|
||||
onPress={() => setShowConfirm(false)}
|
||||
/>
|
||||
) : (
|
||||
<TextInput.Icon style={styles.icon}
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="eye"
|
||||
onPress={() => setShowConfirm(true)}
|
||||
/>
|
||||
@ -343,12 +351,14 @@ export function Access() {
|
||||
left={<TextInput.Icon style={styles.icon} icon="lock" />}
|
||||
right={
|
||||
showPassword ? (
|
||||
<TextInput.Icon style={styles.icon}
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="eye-off"
|
||||
onPress={() => setShowPassword(false)}
|
||||
/>
|
||||
) : (
|
||||
<TextInput.Icon style={styles.icon}
|
||||
<TextInput.Icon
|
||||
style={styles.icon}
|
||||
icon="eye"
|
||||
onPress={() => setShowPassword(true)}
|
||||
/>
|
||||
|
@ -1,5 +1,4 @@
|
||||
export const Colors = {
|
||||
primary: '#66aa88',
|
||||
danger: '#ff8888',
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -8,7 +8,7 @@ const SETTINGS_DB = 'ls_v001.db';
|
||||
|
||||
export function useAppContext() {
|
||||
const local = useRef(new LocalStore());
|
||||
const sdk = useRef(new DatabagSDK(new NativeCrypto()))
|
||||
const sdk = useRef(new DatabagSDK(new NativeCrypto()));
|
||||
const [state, setState] = useState({
|
||||
session: null as null | Session,
|
||||
fullDayTime: false,
|
||||
@ -22,9 +22,11 @@ export function useAppContext() {
|
||||
|
||||
const setup = async () => {
|
||||
await local.current.open(SETTINGS_DB);
|
||||
const fullDayTime = await local.current.get('time_format', '12h') === '24h';
|
||||
const monthFirstDate = await local.current.get('date_format', 'month_first') === 'month_first';
|
||||
|
||||
const fullDayTime =
|
||||
(await local.current.get('time_format', '12h')) === '24h';
|
||||
const monthFirstDate =
|
||||
(await local.current.get('date_format', 'month_first')) === 'month_first';
|
||||
|
||||
const store = new SessionStore();
|
||||
await store.open(DATABAG_DB);
|
||||
const session: Session | null = await sdk.current.initOfflineStore(store);
|
||||
@ -39,11 +41,14 @@ export function useAppContext() {
|
||||
|
||||
const actions = {
|
||||
setMonthFirstDate: async (monthFirstDate: boolean) => {
|
||||
updateState({ monthFirstDate });
|
||||
await local.current.set('date_format', monthFirstDate ? 'month_first' : 'day_first');
|
||||
updateState({monthFirstDate});
|
||||
await local.current.set(
|
||||
'date_format',
|
||||
monthFirstDate ? 'month_first' : 'day_first',
|
||||
);
|
||||
},
|
||||
setFullDayTime: async (fullDayTime: boolean) => {
|
||||
updateState({ fullDayTime });
|
||||
updateState({fullDayTime});
|
||||
await local.current.set('time_format', fullDayTime ? '24h' : '12h');
|
||||
},
|
||||
accountLogin: async (
|
||||
@ -86,7 +91,7 @@ export function useAppContext() {
|
||||
accountRemove: async () => {
|
||||
if (state.session) {
|
||||
await sdk.current.remove(state.session);
|
||||
updateState({ session: null });
|
||||
updateState({session: null});
|
||||
}
|
||||
},
|
||||
accountCreate: async (
|
||||
|
@ -123,9 +123,6 @@ export const styles = StyleSheet.create({
|
||||
fontSize: 16,
|
||||
},
|
||||
controlSwitch: {
|
||||
transform: [
|
||||
{ scaleX: 0.7 },
|
||||
{scaleY: 0.7 },
|
||||
]
|
||||
transform: [{scaleX: 0.7}, {scaleY: 0.7}],
|
||||
},
|
||||
});
|
||||
|
@ -1,21 +1,29 @@
|
||||
import { useState } from 'react';
|
||||
import { Modal, TouchableOpacity, SafeAreaView, View, Image } from 'react-native';
|
||||
import { Surface, IconButton, Button, Switch, Icon, Text, Menu } from 'react-native-paper';
|
||||
import { styles } from './Identity.styled';
|
||||
import { useIdentity } from './useIdentity.hook';
|
||||
import {useState} from 'react';
|
||||
import {Modal, TouchableOpacity, SafeAreaView, View, Image} from 'react-native';
|
||||
import {
|
||||
Surface,
|
||||
IconButton,
|
||||
Button,
|
||||
Switch,
|
||||
Icon,
|
||||
Text,
|
||||
Menu,
|
||||
} from 'react-native-paper';
|
||||
import {styles} from './Identity.styled';
|
||||
import {useIdentity} from './useIdentity.hook';
|
||||
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
|
||||
import {BlurView} from '@react-native-community/blur';
|
||||
|
||||
export function Identity({ openSettings }) {
|
||||
export function Identity({openSettings}) {
|
||||
const [menu, setMenu] = useState(false);
|
||||
const { state, actions } = useIdentity();
|
||||
const {state, actions} = useIdentity();
|
||||
const [logout, setLogout] = useState(false);
|
||||
const [applyingLogout, setApplyingLogout] = useState(false);
|
||||
|
||||
const showLogout = () => {
|
||||
setMenu(false);
|
||||
setLogout(true);
|
||||
}
|
||||
};
|
||||
|
||||
const applyLogout = async () => {
|
||||
if (!applyingLogout) {
|
||||
@ -24,25 +32,46 @@ export function Identity({ openSettings }) {
|
||||
setLogout(false);
|
||||
setApplyingLogout(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SafeAreaView style={styles.identity}>
|
||||
<TouchableOpacity style={styles.identityData} activeOpacity={1} onPress={() => setMenu(true)}>
|
||||
<TouchableOpacity
|
||||
style={styles.identityData}
|
||||
activeOpacity={1}
|
||||
onPress={() => setMenu(true)}>
|
||||
<View style={styles.image}>
|
||||
{state.profile.imageSet && (
|
||||
<Image style={styles.logoSet} resizeMode={'contain'} source={state.imageUrl} />
|
||||
<Image
|
||||
style={styles.logoSet}
|
||||
resizeMode={'contain'}
|
||||
source={state.imageUrl}
|
||||
/>
|
||||
)}
|
||||
{!state.profile.imageSet && (
|
||||
<Image style={styles.logoUnset} resizeMode={'contain'} source={state.imageUrl} />
|
||||
<Image
|
||||
style={styles.logoUnset}
|
||||
resizeMode={'contain'}
|
||||
source={state.imageUrl}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.details}>
|
||||
{state.profile.name && (
|
||||
<Text style={styles.name} adjustsFontSizeToFit={true} numberOfLines={1}>{state.profile.name}</Text>
|
||||
<Text
|
||||
style={styles.name}
|
||||
adjustsFontSizeToFit={true}
|
||||
numberOfLines={1}>
|
||||
{state.profile.name}
|
||||
</Text>
|
||||
)}
|
||||
<Text style={styles.username} adjustsFontSizeToFit={true} numberOfLines={1}>{`${state.profile.handle}${state.profile.node ? '/' + state.profile.node : ''}`}</Text>
|
||||
<Text
|
||||
style={styles.username}
|
||||
adjustsFontSizeToFit={true}
|
||||
numberOfLines={1}>{`${state.profile.handle}${
|
||||
state.profile.node ? '/' + state.profile.node : ''
|
||||
}`}</Text>
|
||||
</View>
|
||||
<Icon size={18} source="chevron-right" />
|
||||
</TouchableOpacity>
|
||||
@ -50,10 +79,29 @@ export function Identity({ openSettings }) {
|
||||
visible={menu}
|
||||
onDismiss={() => setMenu(false)}
|
||||
anchorPosition="top"
|
||||
anchor={<View style={styles.anchor}><Text> </Text></View>}>
|
||||
<Menu.Item leadingIcon="cog-outline" onPress={() => {setMenu(false); openSettings()}} title={state.strings.settings} />
|
||||
<Menu.Item leadingIcon="contacts-outline" onPress={() => {}} title={state.strings.contacts} />
|
||||
<Menu.Item leadingIcon="logout" onPress={showLogout} title={state.strings.logout} />
|
||||
anchor={
|
||||
<View style={styles.anchor}>
|
||||
<Text> </Text>
|
||||
</View>
|
||||
}>
|
||||
<Menu.Item
|
||||
leadingIcon="cog-outline"
|
||||
onPress={() => {
|
||||
setMenu(false);
|
||||
openSettings();
|
||||
}}
|
||||
title={state.strings.settings}
|
||||
/>
|
||||
<Menu.Item
|
||||
leadingIcon="contacts-outline"
|
||||
onPress={() => {}}
|
||||
title={state.strings.contacts}
|
||||
/>
|
||||
<Menu.Item
|
||||
leadingIcon="logout"
|
||||
onPress={showLogout}
|
||||
title={state.strings.logout}
|
||||
/>
|
||||
</Menu>
|
||||
</SafeAreaView>
|
||||
<Modal
|
||||
@ -69,24 +117,44 @@ export function Identity({ openSettings }) {
|
||||
blurAmount={2}
|
||||
reducedTransparencyFallbackColor="dark"
|
||||
/>
|
||||
<KeyboardAwareScrollView style={styles.container} contentContainerStyle={styles.content}>
|
||||
<KeyboardAwareScrollView
|
||||
style={styles.container}
|
||||
contentContainerStyle={styles.content}>
|
||||
<Surface elevation={5} mode="flat" style={styles.surface}>
|
||||
<Text style={styles.modalLabel}>{ state.strings.loggingOut }</Text>
|
||||
<IconButton style={styles.modalClose} icon="close" size={24} onPress={() => setLogout(false)} />
|
||||
<Text style={styles.modalLabel}>{state.strings.loggingOut}</Text>
|
||||
<IconButton
|
||||
style={styles.modalClose}
|
||||
icon="close"
|
||||
size={24}
|
||||
onPress={() => setLogout(false)}
|
||||
/>
|
||||
|
||||
<View style={styles.allControl}>
|
||||
<Text style={styles.controlLabel}>{state.strings.allDevices}</Text>
|
||||
<Switch style={styles.controlSwitch} value={state.all} onValueChange={actions.setAll} />
|
||||
<Text style={styles.controlLabel}>
|
||||
{state.strings.allDevices}
|
||||
</Text>
|
||||
<Switch
|
||||
style={styles.controlSwitch}
|
||||
value={state.all}
|
||||
onValueChange={actions.setAll}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.modalControls}>
|
||||
<Button mode="outlined" onPress={() => setLogout(false)}>{ state.strings.cancel }</Button>
|
||||
<Button mode="contained" loading={applyingLogout} onPress={applyLogout}>{ state.strings.logout }</Button>
|
||||
<Button mode="outlined" onPress={() => setLogout(false)}>
|
||||
{state.strings.cancel}
|
||||
</Button>
|
||||
<Button
|
||||
mode="contained"
|
||||
loading={applyingLogout}
|
||||
onPress={applyLogout}>
|
||||
{state.strings.logout}
|
||||
</Button>
|
||||
</View>
|
||||
</Surface>
|
||||
</KeyboardAwareScrollView>
|
||||
</KeyboardAwareScrollView>
|
||||
</View>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { useEffect, useState, useContext, useRef } from 'react'
|
||||
import { AppContext } from '../context/AppContext'
|
||||
import { DisplayContext } from '../context/DisplayContext';
|
||||
import { ContextType } from '../context/ContextType'
|
||||
import {useEffect, useState, useContext, useRef} from 'react';
|
||||
import {AppContext} from '../context/AppContext';
|
||||
import {DisplayContext} from '../context/DisplayContext';
|
||||
import {ContextType} from '../context/ContextType';
|
||||
|
||||
export function useIdentity() {
|
||||
const display = useContext(DisplayContext) as ContextType
|
||||
const app = useContext(AppContext) as ContextType
|
||||
const display = useContext(DisplayContext) as ContextType;
|
||||
const app = useContext(AppContext) as ContextType;
|
||||
|
||||
const [state, setState] = useState({
|
||||
all: false,
|
||||
@ -14,41 +14,40 @@ export function useIdentity() {
|
||||
profileSet: false,
|
||||
imageUrl: null,
|
||||
strings: display.state.strings,
|
||||
})
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const updateState = (value: any) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
setState(s => ({...s, ...value}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const identity = app.state.session?.getIdentity()
|
||||
const identity = app.state.session?.getIdentity();
|
||||
if (!identity) {
|
||||
console.log('session not set in identity hook')
|
||||
console.log('session not set in identity hook');
|
||||
} else {
|
||||
const setProfile = (profile: Profile) => {
|
||||
updateState({
|
||||
profile,
|
||||
profileSet: true,
|
||||
imageUrl: { uri: identity.getProfileImageUrl() },
|
||||
})
|
||||
|
||||
}
|
||||
identity.addProfileListener(setProfile)
|
||||
imageUrl: {uri: identity.getProfileImageUrl()},
|
||||
});
|
||||
};
|
||||
identity.addProfileListener(setProfile);
|
||||
return () => {
|
||||
identity.removeProfileListener(setProfile)
|
||||
}
|
||||
identity.removeProfileListener(setProfile);
|
||||
};
|
||||
}
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
const actions = {
|
||||
setAll: (all) => {
|
||||
updateState({ all });
|
||||
setAll: all => {
|
||||
updateState({all});
|
||||
},
|
||||
logout: async () => {
|
||||
await app.actions.accountLogout(state.all);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions }
|
||||
return {state, actions};
|
||||
}
|
||||
|
@ -1,7 +1,13 @@
|
||||
import React, {useState, useContext} from 'react';
|
||||
import {View, useColorScheme} from 'react-native';
|
||||
import {styles} from './Session.styled';
|
||||
import {BottomNavigation, Surface, Menu, Button, Text} from 'react-native-paper';
|
||||
import {
|
||||
BottomNavigation,
|
||||
Surface,
|
||||
Menu,
|
||||
Button,
|
||||
Text,
|
||||
} from 'react-native-paper';
|
||||
import {Settings} from '../settings/Settings';
|
||||
import {Channels} from '../channels/Channels';
|
||||
import {Contacts} from '../contacts/Contacts';
|
||||
@ -11,7 +17,11 @@ import {Details} from '../details/Details';
|
||||
import {Identity} from '../identity/Identity';
|
||||
import {useSession} from './useSession.hook';
|
||||
|
||||
import {NavigationContainer, DefaultTheme, DarkTheme} from '@react-navigation/native';
|
||||
import {
|
||||
NavigationContainer,
|
||||
DefaultTheme,
|
||||
DarkTheme,
|
||||
} from '@react-navigation/native';
|
||||
import {createDrawerNavigator} from '@react-navigation/drawer';
|
||||
|
||||
const ChannelsRoute = () => <Channels />;
|
||||
@ -67,7 +77,8 @@ export function Session() {
|
||||
/>
|
||||
)}
|
||||
{state.layout === 'large' && (
|
||||
<NavigationContainer theme={scheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||
<NavigationContainer
|
||||
theme={scheme === 'dark' ? DarkTheme : DefaultTheme}>
|
||||
<DetailsScreen nav={sessionNav} />
|
||||
</NavigationContainer>
|
||||
)}
|
||||
@ -157,7 +168,7 @@ function SettingsScreen({nav}) {
|
||||
id="SettingsDrawer"
|
||||
drawerContent={Settings}
|
||||
screenOptions={{
|
||||
drawerStyle: { width: '40%' },
|
||||
drawerStyle: {width: '40%'},
|
||||
drawerPosition: 'right',
|
||||
drawerType: 'front',
|
||||
headerShown: false,
|
||||
@ -178,8 +189,7 @@ function HomeScreen({nav}) {
|
||||
<Surface elevation={2} mode="flat">
|
||||
<Identity openSettings={nav.settings.openDrawer} />
|
||||
</Surface>
|
||||
<Surface style={styles.channels} elevation={1} mode="flat">
|
||||
</Surface>
|
||||
<Surface style={styles.channels} elevation={1} mode="flat"></Surface>
|
||||
</View>
|
||||
<View style={styles.right}>
|
||||
<Text>CONVERSATION</Text>
|
||||
|
@ -1,34 +1,34 @@
|
||||
import { useEffect, useState, useContext, useRef } from 'react'
|
||||
import { AppContext } from '../context/AppContext'
|
||||
import { DisplayContext } from '../context/DisplayContext'
|
||||
import { ContextType } from '../context/ContextType'
|
||||
import {useEffect, useState, useContext, useRef} from 'react';
|
||||
import {AppContext} from '../context/AppContext';
|
||||
import {DisplayContext} from '../context/DisplayContext';
|
||||
import {ContextType} from '../context/ContextType';
|
||||
|
||||
const DEBOUNCE_MS = 1000
|
||||
const DEBOUNCE_MS = 1000;
|
||||
|
||||
export function useSession() {
|
||||
const display = useContext(DisplayContext) as ContextType
|
||||
const app = useContext(AppContext) as ContextType
|
||||
const display = useContext(DisplayContext) as ContextType;
|
||||
const app = useContext(AppContext) as ContextType;
|
||||
|
||||
const [state, setState] = useState({
|
||||
layout: null,
|
||||
strings: {},
|
||||
})
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const updateState = (value: any) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
setState(s => ({...s, ...value}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const { layout, strings } = display.state;
|
||||
updateState({ layout, strings });
|
||||
const {layout, strings} = display.state;
|
||||
updateState({layout, strings});
|
||||
}, [display.state.layout, display.state.strings]);
|
||||
|
||||
const actions = {
|
||||
logout: async () => {
|
||||
await app.actions.accountLogout();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions }
|
||||
return {state, actions};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {StyleSheet} from 'react-native';
|
||||
import { Colors } from '../constants/Colors';
|
||||
import {Colors} from '../constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
modal: {
|
||||
@ -260,10 +260,7 @@ export const styles = StyleSheet.create({
|
||||
color: Colors.danger,
|
||||
},
|
||||
controlSwitch: {
|
||||
transform: [
|
||||
{ scaleX: 0.7 },
|
||||
{scaleY: 0.7 },
|
||||
]
|
||||
transform: [{scaleX: 0.7}, {scaleY: 0.7}],
|
||||
},
|
||||
input: {
|
||||
width: '100%',
|
||||
@ -302,4 +299,4 @@ export const styles = StyleSheet.create({
|
||||
fontSize: 16,
|
||||
color: Colors.danger,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,14 @@
|
||||
import { useEffect, useState, useContext, useRef } from 'react'
|
||||
import { AppContext } from '../context/AppContext'
|
||||
import { DisplayContext } from '../context/DisplayContext'
|
||||
import { ContextType } from '../context/ContextType'
|
||||
import {useEffect, useState, useContext, useRef} from 'react';
|
||||
import {AppContext} from '../context/AppContext';
|
||||
import {DisplayContext} from '../context/DisplayContext';
|
||||
import {ContextType} from '../context/ContextType';
|
||||
|
||||
const DEBOUNCE_MS = 1000
|
||||
const DEBOUNCE_MS = 1000;
|
||||
|
||||
export function useSettings() {
|
||||
const display = useContext(DisplayContext) as ContextType
|
||||
const app = useContext(AppContext) as ContextType
|
||||
const debounce = useRef(setTimeout(() => {}, 0))
|
||||
const display = useContext(DisplayContext) as ContextType;
|
||||
const app = useContext(AppContext) as ContextType;
|
||||
const debounce = useRef(setTimeout(() => {}, 0));
|
||||
|
||||
const [state, setState] = useState({
|
||||
config: {} as Config,
|
||||
@ -36,32 +36,32 @@ export function useSettings() {
|
||||
secretCopied: false,
|
||||
monthFirstDate: true,
|
||||
fullDayTime: false,
|
||||
})
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const updateState = (value: any) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
}
|
||||
setState(s => ({...s, ...value}));
|
||||
};
|
||||
|
||||
const getSession = () => {
|
||||
const session = app.state?.session
|
||||
const settings = session?.getSettings()
|
||||
const identity = session?.getIdentity()
|
||||
const session = app.state?.session;
|
||||
const settings = session?.getSettings();
|
||||
const identity = session?.getIdentity();
|
||||
if (!settings || !identity) {
|
||||
console.log('session not set in settings hook')
|
||||
console.log('session not set in settings hook');
|
||||
}
|
||||
return { settings, identity }
|
||||
}
|
||||
return {settings, identity};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const { settings, identity } = getSession()
|
||||
const {settings, identity} = getSession();
|
||||
const setConfig = (config: Config) => {
|
||||
updateState({ config })
|
||||
}
|
||||
settings.addConfigListener(setConfig)
|
||||
updateState({config});
|
||||
};
|
||||
settings.addConfigListener(setConfig);
|
||||
const setProfile = (profile: Profile) => {
|
||||
const { handle, name, location, description } = profile
|
||||
const url = identity.getProfileImageUrl()
|
||||
const {handle, name, location, description} = profile;
|
||||
const url = identity.getProfileImageUrl();
|
||||
updateState({
|
||||
profile,
|
||||
handle,
|
||||
@ -70,194 +70,188 @@ export function useSettings() {
|
||||
description,
|
||||
imageUrl: url,
|
||||
profileSet: true,
|
||||
})
|
||||
}
|
||||
identity.addProfileListener(setProfile)
|
||||
});
|
||||
};
|
||||
identity.addProfileListener(setProfile);
|
||||
return () => {
|
||||
settings.removeConfigListener(setConfig)
|
||||
identity.removeProfileListener(setProfile)
|
||||
}
|
||||
}, [])
|
||||
settings.removeConfigListener(setConfig);
|
||||
identity.removeProfileListener(setProfile);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const { fullDayTime, monthFirstDate } = app.state;
|
||||
updateState({ fullDayTime, monthFirstDate });
|
||||
const {fullDayTime, monthFirstDate} = app.state;
|
||||
updateState({fullDayTime, monthFirstDate});
|
||||
}, [app.state.fullDayTime, app.state.monthFirstDate]);
|
||||
|
||||
useEffect(() => {
|
||||
const {
|
||||
strings,
|
||||
dateFormat,
|
||||
timeFormat,
|
||||
} = display.state
|
||||
const {strings, dateFormat, timeFormat} = display.state;
|
||||
updateState({
|
||||
strings,
|
||||
dateFormat,
|
||||
timeFormat,
|
||||
})
|
||||
}, [display.state])
|
||||
});
|
||||
}, [display.state]);
|
||||
|
||||
const actions = {
|
||||
getUsernameStatus: async (username: string) => {
|
||||
const { settings } = getSession()
|
||||
return await settings.getUsernameStatus(username)
|
||||
const {settings} = getSession();
|
||||
return await settings.getUsernameStatus(username);
|
||||
},
|
||||
setLogin: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.setLogin(state.handle, state.password)
|
||||
const {settings} = getSession();
|
||||
await settings.setLogin(state.handle, state.password);
|
||||
},
|
||||
enableNotifications: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.enableNotifications()
|
||||
const {settings} = getSession();
|
||||
await settings.enableNotifications();
|
||||
},
|
||||
disableNotifications: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.disableNotifications()
|
||||
const {settings} = getSession();
|
||||
await settings.disableNotifications();
|
||||
},
|
||||
enableRegistry: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.enableRegistry()
|
||||
const {settings} = getSession();
|
||||
await settings.enableRegistry();
|
||||
},
|
||||
disableRegistry: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.disableRegistry()
|
||||
const {settings} = getSession();
|
||||
await settings.disableRegistry();
|
||||
},
|
||||
enableMFA: async () => {
|
||||
const { settings } = getSession()
|
||||
const { secretImage, secretText } = await settings.enableMFA()
|
||||
updateState({ secretImage, secretText });
|
||||
const {settings} = getSession();
|
||||
const {secretImage, secretText} = await settings.enableMFA();
|
||||
updateState({secretImage, secretText});
|
||||
},
|
||||
disableMFA: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.disableMFA()
|
||||
const {settings} = getSession();
|
||||
await settings.disableMFA();
|
||||
},
|
||||
confirmMFA: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.confirmMFA(state.code)
|
||||
const {settings} = getSession();
|
||||
await settings.confirmMFA(state.code);
|
||||
},
|
||||
setCode: (code: string) => {
|
||||
updateState({ code });
|
||||
updateState({code});
|
||||
},
|
||||
copySecret: () => {
|
||||
navigator.clipboard.writeText(state.secretText);
|
||||
updateState({ secretCopied: true });
|
||||
updateState({secretCopied: true});
|
||||
setTimeout(() => {
|
||||
updateState({ secretCopied: false });
|
||||
updateState({secretCopied: false});
|
||||
}, 1000);
|
||||
},
|
||||
setSeal: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.setSeal(state.sealPassword)
|
||||
const {settings} = getSession();
|
||||
await settings.setSeal(state.sealPassword);
|
||||
},
|
||||
clearSeal: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.clearSeal()
|
||||
const {settings} = getSession();
|
||||
await settings.clearSeal();
|
||||
},
|
||||
unlockSeal: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.unlockSeal(state.sealPassword)
|
||||
const {settings} = getSession();
|
||||
await settings.unlockSeal(state.sealPassword);
|
||||
},
|
||||
forgetSeal: async () => {
|
||||
const { settings } = getSession()
|
||||
await settings.forgetSeal()
|
||||
const {settings} = getSession();
|
||||
await settings.forgetSeal();
|
||||
},
|
||||
updateSeal: async () => {
|
||||
const { settings } = getSession();
|
||||
const {settings} = getSession();
|
||||
await settings.updateSeal(state.sealPassword);
|
||||
},
|
||||
setProfileData: async (
|
||||
name: string,
|
||||
location: string,
|
||||
description: string
|
||||
description: string,
|
||||
) => {
|
||||
const { identity } = getSession()
|
||||
await identity.setProfileData(name, location, description)
|
||||
const {identity} = getSession();
|
||||
await identity.setProfileData(name, location, description);
|
||||
},
|
||||
setProfileImage: async (image: string) => {
|
||||
const { identity } = getSession()
|
||||
await identity.setProfileImage(image)
|
||||
const {identity} = getSession();
|
||||
await identity.setProfileImage(image);
|
||||
},
|
||||
getProfileImageUrl: () => {
|
||||
const { identity } = getSession()
|
||||
return identity.getProfileImageUrl()
|
||||
const {identity} = getSession();
|
||||
return identity.getProfileImageUrl();
|
||||
},
|
||||
setDateFormat: (format: string) => {
|
||||
display.actions.setDateFormat(format)
|
||||
display.actions.setDateFormat(format);
|
||||
},
|
||||
setTimeFormat: (format: string) => {
|
||||
display.actions.setTimeFormat(format)
|
||||
display.actions.setTimeFormat(format);
|
||||
},
|
||||
setAll: (all: boolean) => {
|
||||
updateState({ all })
|
||||
updateState({all});
|
||||
},
|
||||
logout: async () => {
|
||||
await app.actions.accountLogout(state.all)
|
||||
await app.actions.accountLogout(state.all);
|
||||
},
|
||||
remove: async () => {
|
||||
await app.actions.accountRemove()
|
||||
await app.actions.accountRemove();
|
||||
},
|
||||
setHandle: (handle: string) => {
|
||||
updateState({ handle, taken: false, checked: false })
|
||||
clearTimeout(debounce.current)
|
||||
updateState({handle, taken: false, checked: false});
|
||||
clearTimeout(debounce.current);
|
||||
if (!handle || handle === state.profile.handle) {
|
||||
updateState({ available: true, checked: true })
|
||||
updateState({available: true, checked: true});
|
||||
} else {
|
||||
debounce.current = setTimeout(async () => {
|
||||
const { settings } = getSession()
|
||||
const {settings} = getSession();
|
||||
try {
|
||||
const available = await settings.getUsernameStatus(handle)
|
||||
updateState({ taken: !available, checked: true })
|
||||
}
|
||||
catch (err) {
|
||||
const available = await settings.getUsernameStatus(handle);
|
||||
updateState({taken: !available, checked: true});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}, DEBOUNCE_MS)
|
||||
}, DEBOUNCE_MS);
|
||||
}
|
||||
},
|
||||
setPassword: (password: string) => {
|
||||
updateState({ password })
|
||||
updateState({password});
|
||||
},
|
||||
setConfirm: (confirm: string) => {
|
||||
updateState({ confirm })
|
||||
updateState({confirm});
|
||||
},
|
||||
setRemove: (remove: string) => {
|
||||
updateState({ remove });
|
||||
updateState({remove});
|
||||
},
|
||||
setName: (name: string) => {
|
||||
updateState({ name })
|
||||
updateState({name});
|
||||
},
|
||||
setLocation: (location: string) => {
|
||||
updateState({ location })
|
||||
updateState({location});
|
||||
},
|
||||
setDescription: (description: string) => {
|
||||
updateState({ description })
|
||||
updateState({description});
|
||||
},
|
||||
setDetails: async () => {
|
||||
const { identity } = getSession()
|
||||
const { name, location, description } = state
|
||||
await identity.setProfileData(name, location, description)
|
||||
const {identity} = getSession();
|
||||
const {name, location, description} = state;
|
||||
await identity.setProfileData(name, location, description);
|
||||
},
|
||||
setSealDelete: (sealDelete: string) => {
|
||||
updateState({ sealDelete });
|
||||
updateState({sealDelete});
|
||||
},
|
||||
setSealPassword: (sealPassword: string) => {
|
||||
updateState({ sealPassword });
|
||||
updateState({sealPassword});
|
||||
},
|
||||
setSealConfirm: (sealConfirm: string) => {
|
||||
updateState({ sealConfirm });
|
||||
updateState({sealConfirm});
|
||||
},
|
||||
setFullDayTime: async (flag: boolean) => {
|
||||
try {
|
||||
await app.actions.setFullDayTime(flag);
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
setMonthFirstDate: async (flag: boolean) => {
|
||||
await app.actions.setMonthFirstDate(flag);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
return { state, actions }
|
||||
return {state, actions};
|
||||
}
|
||||
|
@ -41,7 +41,8 @@ export function InputCode({onChangeText, style}) {
|
||||
<Text style={styles.text}>{code.charAt(5)}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TextInput style={styles.input}
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
keyboardType={Platform.OS === 'ios' ? 'numeric' : 'number-pad'}
|
||||
onChangeText={updateCode}
|
||||
autoCorrect={false}
|
||||
|
Loading…
x
Reference in New Issue
Block a user